Update scoring and progress
This commit is contained in:
@@ -3,19 +3,20 @@ using static Managing.Common.Enums;
|
||||
|
||||
public class BacktestScorer
|
||||
{
|
||||
// Updated weights with more balanced distribution
|
||||
// Updated weights with more emphasis on HODL comparison and risk management
|
||||
private static readonly Dictionary<string, double> Weights = new Dictionary<string, double>
|
||||
{
|
||||
{ "GrowthPercentage", 0.25 },
|
||||
{ "GrowthPercentage", 0.20 },
|
||||
{ "SharpeRatio", 0.15 },
|
||||
{ "MaxDrawdownUsd", 0.12 },
|
||||
{ "HodlComparison", 0.05 },
|
||||
{ "WinRate", 0.15 },
|
||||
{ "MaxDrawdownUsd", 0.10 },
|
||||
{ "HodlComparison", 0.15 }, // Increased from 0.05 to 0.15
|
||||
{ "WinRate", 0.12 },
|
||||
{ "ProfitabilityBonus", 0.08 },
|
||||
{ "TradeCount", 0.05 },
|
||||
{ "RecoveryTime", 0.02 },
|
||||
{ "TestDuration", 0.03 },
|
||||
{ "FeesImpact", 0.02 }
|
||||
{ "FeesImpact", 0.02 },
|
||||
{ "RiskAdjustedReturn", 0.08 } // New component
|
||||
};
|
||||
|
||||
public static double CalculateTotalScore(BacktestScoringParams p)
|
||||
@@ -52,7 +53,8 @@ public class BacktestScorer
|
||||
{ "TradeCount", CalculateTradeCountScore(p.TradeCount) },
|
||||
{ "RecoveryTime", CalculateRecoveryScore(p.MaxDrawdownRecoveryTime, p.Timeframe) },
|
||||
{ "TestDuration", CalculateTestDurationScore(p.StartDate, p.EndDate, p.Timeframe) },
|
||||
{ "FeesImpact", CalculateFeesImpactScore(p.FeesPaid, p.InitialBalance, (decimal)p.TotalPnL) }
|
||||
{ "FeesImpact", CalculateFeesImpactScore(p.FeesPaid, p.InitialBalance, (decimal)p.TotalPnL) },
|
||||
{ "RiskAdjustedReturn", CalculateRiskAdjustedReturnScore(p.TotalPnL, p.MaxDrawdown, p.InitialBalance) }
|
||||
};
|
||||
|
||||
return componentScores.Sum(kvp => kvp.Value * Weights[kvp.Key]);
|
||||
@@ -89,14 +91,25 @@ public class BacktestScorer
|
||||
penaltyMultiplier *= Math.Max(0.5, 1 - profitPenalty);
|
||||
}
|
||||
|
||||
// 5. Drawdown Penalty (Dynamic)
|
||||
// 5. Drawdown Penalty (Dynamic) - Enhanced to consider PnL ratio
|
||||
if (p.MaxDrawdownPc > 20)
|
||||
{
|
||||
var drawdownPenalty = (p.MaxDrawdownPc - 20) * 0.02; // 2% penalty per 1% above 20%
|
||||
penaltyMultiplier *= Math.Max(0.3, 1 - drawdownPenalty);
|
||||
}
|
||||
|
||||
// 6. Test Duration Penalty (Dynamic)
|
||||
// 6. Enhanced Drawdown vs PnL Penalty
|
||||
if (p.TotalPnL > 0 && p.MaxDrawdown > 0)
|
||||
{
|
||||
var drawdownToPnLRatio = (double)(p.MaxDrawdown / (decimal)p.TotalPnL);
|
||||
if (drawdownToPnLRatio > 1.5) // If drawdown is more than 150% of PnL
|
||||
{
|
||||
var ratioPenalty = (drawdownToPnLRatio - 1.5) * 0.2; // 20% penalty per 0.5 ratio above 1.5
|
||||
penaltyMultiplier *= Math.Max(0.2, 1 - ratioPenalty);
|
||||
}
|
||||
}
|
||||
|
||||
// 7. Test Duration Penalty (Dynamic)
|
||||
var testDurationDays = (p.EndDate - p.StartDate).TotalDays;
|
||||
if (testDurationDays < 30)
|
||||
{
|
||||
@@ -154,8 +167,6 @@ public class BacktestScorer
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static double CalculateDrawdownUsdScore(decimal maxDrawdown, decimal initialBalance)
|
||||
{
|
||||
if (initialBalance <= 0) return 0;
|
||||
@@ -188,10 +199,16 @@ public class BacktestScorer
|
||||
private static double CalculateHodlComparisonScore(double strategyGrowth, double hodlGrowth)
|
||||
{
|
||||
var difference = strategyGrowth - hodlGrowth;
|
||||
|
||||
// Much more aggressive scoring for HODL comparison
|
||||
return difference switch
|
||||
{
|
||||
> 0 => 80 - (80 / (1 + difference / 3)), // Reduced max to 80
|
||||
_ => Math.Max(0, 20 + difference * 2) // Reduced base score
|
||||
> 5 => 100, // Significantly outperform HODL (>5% better)
|
||||
> 2 => 80 + (difference - 2) * 6.67, // 2-5% better: 80-100 points
|
||||
> 0 => 40 + difference * 20, // 0-2% better: 40-80 points
|
||||
> -2 => 20 + (difference + 2) * 10, // -2-0%: 20-40 points
|
||||
> -5 => Math.Max(0, 10 + (difference + 5) * 3.33), // -5 to -2%: 0-20 points
|
||||
_ => 0 // More than 5% worse than HODL = 0 points
|
||||
};
|
||||
}
|
||||
|
||||
@@ -273,4 +290,22 @@ public class BacktestScorer
|
||||
|
||||
return feeEfficiency;
|
||||
}
|
||||
|
||||
private static double CalculateRiskAdjustedReturnScore(double totalPnL, decimal maxDrawdown, decimal initialBalance)
|
||||
{
|
||||
if (initialBalance <= 0 || maxDrawdown <= 0) return 0;
|
||||
|
||||
var pnlRatio = totalPnL / (double)maxDrawdown;
|
||||
|
||||
// Score based on PnL to drawdown ratio
|
||||
return pnlRatio switch
|
||||
{
|
||||
> 3 => 100, // Excellent risk-adjusted return (>3:1)
|
||||
> 2 => 80 + (pnlRatio - 2) * 20, // 2-3:1: 80-100 points
|
||||
> 1.5 => 60 + (pnlRatio - 1.5) * 40, // 1.5-2:1: 60-80 points
|
||||
> 1 => 40 + (pnlRatio - 1) * 40, // 1-1.5:1: 40-60 points
|
||||
> 0.5 => 20 + (pnlRatio - 0.5) * 40, // 0.5-1:1: 20-40 points
|
||||
_ => Math.Max(0, pnlRatio * 40) // 0-0.5:1: 0-20 points
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user