Update score
This commit is contained in:
@@ -5,28 +5,25 @@ public class BacktestScorer
|
|||||||
// Updated weights without ProfitEfficiency
|
// Updated weights without ProfitEfficiency
|
||||||
private static readonly Dictionary<string, double> Weights = new Dictionary<string, double>
|
private static readonly Dictionary<string, double> Weights = new Dictionary<string, double>
|
||||||
{
|
{
|
||||||
{ "SharpeRatio", 0.22 }, // Increased weight
|
{ "GrowthPercentage", 0.30 }, // Increased weight for profitability
|
||||||
{ "GrowthPercentage", 0.22 }, // Increased weight
|
{ "SharpeRatio", 0.18 },
|
||||||
{ "MaxDrawdownPc", 0.15 },
|
{ "MaxDrawdownPc", 0.15 },
|
||||||
{ "WinRate", 0.15 }, // Increased weight
|
{ "HodlComparison", 0.15 },
|
||||||
{ "HodlComparison", 0.15 }, // Increased weight
|
{ "WinRate", 0.10 },
|
||||||
{ "TradeCount", 0.06 },
|
{ "ProfitabilityBonus", 0.07 }, // New direct profitability component
|
||||||
{ "RecoveryTime", 0.04 },
|
{ "TradeCount", 0.03 },
|
||||||
{ "RiskAdjustedGrowth", 0.01 }
|
{ "RecoveryTime", 0.02 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
public static double CalculateTotalScore(BacktestScoringParams p)
|
public static double CalculateTotalScore(BacktestScoringParams p)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Detect inactive strategies
|
var baseScore = CalculateBaseScore(p);
|
||||||
if (IsInactiveStrategy(p))
|
var finalScore = ApplyProfitabilityRules(baseScore, p);
|
||||||
{
|
|
||||||
return Math.Min(CalculateBaseScore(p) * 0.3, 40);
|
|
||||||
}
|
|
||||||
|
|
||||||
var score = CalculateBaseScore(p);
|
return double.Clamp(finalScore, 0, 100);
|
||||||
return double.Clamp(score, 0, 100);
|
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -38,19 +35,85 @@ public class BacktestScorer
|
|||||||
{
|
{
|
||||||
var componentScores = new Dictionary<string, double>
|
var componentScores = new Dictionary<string, double>
|
||||||
{
|
{
|
||||||
{ "SharpeRatio", CalculateSharpeScore(p.SharpeRatio) },
|
|
||||||
{ "GrowthPercentage", CalculateGrowthScore(p.GrowthPercentage) },
|
{ "GrowthPercentage", CalculateGrowthScore(p.GrowthPercentage) },
|
||||||
|
{ "SharpeRatio", CalculateSharpeScore(p.SharpeRatio) },
|
||||||
{ "MaxDrawdownPc", CalculateDrawdownScore(p.MaxDrawdownPc) },
|
{ "MaxDrawdownPc", CalculateDrawdownScore(p.MaxDrawdownPc) },
|
||||||
{ "WinRate", CalculateWinRateScore(p.WinRate, p.TradeCount) },
|
|
||||||
{ "HodlComparison", CalculateHodlComparisonScore(p.GrowthPercentage, p.HodlPercentage) },
|
{ "HodlComparison", CalculateHodlComparisonScore(p.GrowthPercentage, p.HodlPercentage) },
|
||||||
|
{ "WinRate", CalculateWinRateScore(p.WinRate, p.TradeCount) },
|
||||||
|
{ "ProfitabilityBonus", CalculateProfitabilityBonus(p.GrowthPercentage) },
|
||||||
{ "TradeCount", CalculateTradeCountScore(p.TradeCount) },
|
{ "TradeCount", CalculateTradeCountScore(p.TradeCount) },
|
||||||
{ "RecoveryTime", CalculateRecoveryScore(p.MaxDrawdownRecoveryTime) },
|
{ "RecoveryTime", CalculateRecoveryScore(p.MaxDrawdownRecoveryTime) }
|
||||||
{ "RiskAdjustedGrowth", CalculateRiskAdjustedGrowthScore(p.GrowthPercentage, p.MaxDrawdownPc) }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return componentScores.Sum(kvp => kvp.Value * Weights[kvp.Key]);
|
return componentScores.Sum(kvp => kvp.Value * Weights[kvp.Key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static double ApplyProfitabilityRules(double baseScore, BacktestScoringParams p)
|
||||||
|
{
|
||||||
|
// 1. Negative PnL Penalty (Core Rule)
|
||||||
|
if (p.GrowthPercentage < 0)
|
||||||
|
{
|
||||||
|
baseScore = Math.Min(baseScore, 70) * GetNegativePnLMultiplier(p.GrowthPercentage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Absolute PnL Validation (Additional Recommendation)
|
||||||
|
if (p.TotalPnL <= 0)
|
||||||
|
{
|
||||||
|
baseScore = Math.Min(baseScore, 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Win Rate Validation (Additional Recommendation)
|
||||||
|
if (p.WinRate < 0.3 && p.TradeCount > 10)
|
||||||
|
{
|
||||||
|
baseScore = Math.Min(baseScore, 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Minimum Profit Threshold (Additional Recommendation)
|
||||||
|
if (p.GrowthPercentage < 2 && p.TradeCount > 5)
|
||||||
|
{
|
||||||
|
baseScore = Math.Min(baseScore, 80);
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double CalculateGrowthScore(double growthPercentage)
|
||||||
|
{
|
||||||
|
// More aggressive penalty for negative growth
|
||||||
|
if (growthPercentage < 0)
|
||||||
|
{
|
||||||
|
return Math.Max(0, 40 + (growthPercentage * 2)); // -10% → 20, -20% → 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Require minimum 5% growth for full score
|
||||||
|
return growthPercentage switch
|
||||||
|
{
|
||||||
|
< 5 => growthPercentage * 15, // 2% → 30, 4% → 60
|
||||||
|
_ => 100
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Existing multiplier calculation
|
||||||
|
private static double GetNegativePnLMultiplier(double growthPercentage)
|
||||||
|
{
|
||||||
|
return growthPercentage switch
|
||||||
|
{
|
||||||
|
> -5 => 0.8,
|
||||||
|
> -10 => 0.6,
|
||||||
|
> -20 => 0.4,
|
||||||
|
_ => 0.2
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double CalculateProfitabilityBonus(double growthPercentage)
|
||||||
|
{
|
||||||
|
return growthPercentage switch
|
||||||
|
{
|
||||||
|
> 0 => 100 * (1 - 1 / (1 + growthPercentage / 50)), // Diminishing returns
|
||||||
|
_ => 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private static bool IsInactiveStrategy(BacktestScoringParams p)
|
private static bool IsInactiveStrategy(BacktestScoringParams p)
|
||||||
{
|
{
|
||||||
// Detect strategies with no economic value
|
// Detect strategies with no economic value
|
||||||
@@ -69,14 +132,6 @@ public class BacktestScorer
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static double CalculateGrowthScore(double growthPercentage)
|
|
||||||
{
|
|
||||||
if (growthPercentage < 0)
|
|
||||||
return Math.Max(0, 50 + (growthPercentage * 2)); // -5% → 40, -25% → 0
|
|
||||||
|
|
||||||
return Math.Min(100, (Math.Log(1 + growthPercentage) / Math.Log(1 + 1000)) * 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static double CalculateDrawdownScore(double maxDrawdownPc)
|
private static double CalculateDrawdownScore(double maxDrawdownPc)
|
||||||
{
|
{
|
||||||
return maxDrawdownPc switch
|
return maxDrawdownPc switch
|
||||||
|
|||||||
Reference in New Issue
Block a user