fix(simulation,technicals): fix EMA 200 warmup distortion, intrabar execution path, and zero slippage

This commit is contained in:
2026-09-01 17:38:34 +02:00
parent cb8a169043
commit d161efb370
5 changed files with 25 additions and 19 deletions
@@ -62,8 +62,7 @@ public static class TechnicalIndicatorsEngine
public static decimal CalculateEma(IReadOnlyList<CandleDto> candles, int period)
{
if (candles == null || candles.Count == 0 || period <= 0) return 0m;
if (candles.Count < period) return CalculateSma(candles, candles.Count);
if (candles == null || candles.Count < period || period <= 0) return 0m;
decimal k = 2m / (period + 1);
// Seed with SMA
@@ -246,14 +246,14 @@ public class TechnicalScoringEngine : ITechnicalScoringEngine
decimal score = 50m;
if (dir == SignalDirection.Buy)
{
if (ind.TryGetValue("EMA_20", out var e20) && ind.TryGetValue("EMA_50", out var e50) && e20 > e50) score += 15m;
if (ind.TryGetValue("EMA_20", out var e20) && ind.TryGetValue("EMA_50", out var e50) && e20 > 0m && e50 > 0m && e20 > e50) score += 15m;
if (ind.TryGetValue("RSI_14", out var rsi) && rsi is >= 45m and <= 65m) score += 15m;
if (ind.TryGetValue("ADX_14", out var adx) && adx >= 25m) score += 10m;
if (ind.TryGetValue("VWAP", out var vwap) && ind.TryGetValue("EMA_20", out var e20b) && e20b > vwap) score += 10m;
if (ind.TryGetValue("VWAP", out var vwap) && vwap > 0m && ind.TryGetValue("EMA_20", out var e20b) && e20b > vwap) score += 10m;
}
else if (dir == SignalDirection.Sell)
{
if (ind.TryGetValue("EMA_20", out var e20) && ind.TryGetValue("EMA_50", out var e50) && e20 < e50) score += 15m;
if (ind.TryGetValue("EMA_20", out var e20) && ind.TryGetValue("EMA_50", out var e50) && e20 > 0m && e50 > 0m && e20 < e50) score += 15m;
if (ind.TryGetValue("RSI_14", out var rsi) && rsi is >= 35m and <= 55m) score += 15m;
if (ind.TryGetValue("ADX_14", out var adx) && adx >= 25m) score += 10m;
}
@@ -21,7 +21,6 @@ public class TrendPullbackFvgStrategy : ITechnicalStrategy
public StrategyResultDto? Evaluate(TechnicalContext context, IReadOnlyList<PatternResultDto> activePatterns)
{
var candles = context.PrimaryCandles;
if (candles.Count < 30) return null;
// Tunable for backtesting only (see TechnicalContext.ParameterOverrides doc comment) - defaults match
// this strategy's original hardcoded values, so live scanning behavior is unchanged.
@@ -30,13 +29,15 @@ public class TrendPullbackFvgStrategy : ITechnicalStrategy
int emaSlowPeriod = (int)context.GetParameter(StrategyKey, "EmaSlow", 200m);
decimal stopAtrMultiplier = context.GetParameter(StrategyKey, "StopAtrMultiplier", 1.2m);
if (candles.Count < emaSlowPeriod + 5) return null;
var current = candles.Last();
decimal ema20 = TechnicalIndicatorsEngine.CalculateEma(candles, emaFastPeriod);
decimal ema50 = TechnicalIndicatorsEngine.CalculateEma(candles, emaMidPeriod);
decimal ema200 = TechnicalIndicatorsEngine.CalculateEma(candles, emaSlowPeriod);
decimal atr = context.CurrentAtr > 0 ? context.CurrentAtr : TechnicalIndicatorsEngine.CalculateAtr(candles, 14);
if (atr <= 0) return null;
if (ema20 <= 0m || ema50 <= 0m || ema200 <= 0m || atr <= 0) return null;
// Long Setup: Bullish Trend (EMA20 > EMA50 > EMA200) + Bullish FVG retracement.
bool isBullishTrend = ema20 > ema50 && ema50 > ema200 && current.Close > ema50;