Update scoring and progress

This commit is contained in:
2025-07-12 00:10:22 +07:00
parent cebbeff887
commit c0f6d68833
6 changed files with 142 additions and 73 deletions

View File

@@ -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
};
}
}