Fix backtest consistency
This commit is contained in:
@@ -230,9 +230,6 @@ public class BacktestExecutor
|
||||
var fixedCandlesHashSet = new HashSet<Candle>(rollingWindowSize); // Reuse HashSet to avoid allocations
|
||||
var candlesProcessed = 0;
|
||||
|
||||
// Pre-allocate reusable collections to minimize allocations during processing
|
||||
var tempCandlesList = new List<Candle>(rollingWindowSize);
|
||||
|
||||
// Signal caching optimization - reduce signal update frequency for better performance
|
||||
var signalUpdateSkipCount = 0;
|
||||
|
||||
@@ -256,39 +253,26 @@ public class BacktestExecutor
|
||||
// Process all candles with optimized rolling window approach
|
||||
_logger.LogInformation("🎯 Starting to process {Count} candles in loop", orderedCandles.Count);
|
||||
Console.WriteLine("CONSOLE: About to start candle processing loop");
|
||||
|
||||
// Optimize: Pre-populate rolling window with initial candles to avoid repeated checks
|
||||
var initialWindowSize = Math.Min(rollingWindowSize, orderedCandles.Count);
|
||||
for (int i = 0; i < initialWindowSize; i++)
|
||||
{
|
||||
var candle = orderedCandles[i];
|
||||
rollingCandles.Add(candle);
|
||||
fixedCandlesHashSet.Add(candle);
|
||||
}
|
||||
|
||||
foreach (var candle in orderedCandles)
|
||||
{
|
||||
// Optimized rolling window maintenance - only modify when window is full
|
||||
if (rollingCandles.Count >= rollingWindowSize)
|
||||
// Maintain rolling window efficiently using List
|
||||
rollingCandles.Add(candle);
|
||||
|
||||
if (rollingCandles.Count > rollingWindowSize)
|
||||
{
|
||||
// Remove oldest candle from both structures efficiently
|
||||
// Remove oldest candle from both structures
|
||||
var removedCandle = rollingCandles[0];
|
||||
rollingCandles.RemoveAt(0);
|
||||
fixedCandlesHashSet.Remove(removedCandle);
|
||||
}
|
||||
|
||||
// Add new candle to rolling window (skip if already in initial population)
|
||||
if (!fixedCandlesHashSet.Contains(candle))
|
||||
{
|
||||
rollingCandles.Add(candle);
|
||||
fixedCandlesHashSet.Add(candle);
|
||||
}
|
||||
|
||||
// Add to HashSet for reuse
|
||||
fixedCandlesHashSet.Add(candle);
|
||||
tradingBot.LastCandle = candle;
|
||||
|
||||
// Smart signal caching - reduce signal update frequency for performance
|
||||
// RSI and similar indicators don't need updates every candle for 15-minute data
|
||||
var shouldSkipSignalUpdate = ShouldSkipSignalUpdate(currentCandle, totalCandles, config);
|
||||
var shouldSkipSignalUpdate = ShouldSkipSignalUpdate(currentCandle, totalCandles);
|
||||
if (currentCandle <= 5) // Debug first few candles
|
||||
{
|
||||
_logger.LogInformation("🔍 Candle {CurrentCandle}: shouldSkip={ShouldSkip}, totalCandles={Total}",
|
||||
@@ -549,70 +533,24 @@ public class BacktestExecutor
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Advanced signal caching based on indicator update frequency and timeframe
|
||||
/// Dynamically adjusts update frequency based on timeframe and indicator characteristics
|
||||
/// Advanced signal caching based on indicator update frequency
|
||||
/// Instead of hashing candles, we cache signals based on how often indicators need updates
|
||||
/// </summary>
|
||||
private bool ShouldSkipSignalUpdate(int currentCandleIndex, int totalCandles, TradingBotConfig config)
|
||||
private bool ShouldSkipSignalUpdate(int currentCandleIndex, int totalCandles)
|
||||
{
|
||||
// RSI and similar indicators don't need to be recalculated every candle
|
||||
// For 15-minute candles, we can update signals every 3-5 candles without significant accuracy loss
|
||||
const int signalUpdateFrequency = 3; // Update signals every N candles
|
||||
|
||||
// Always update signals for the first few candles to establish baseline
|
||||
if (currentCandleIndex < 20)
|
||||
if (currentCandleIndex < 10)
|
||||
return false;
|
||||
|
||||
// Always update signals near the end to ensure final trades are calculated
|
||||
if (currentCandleIndex > totalCandles - 20)
|
||||
if (currentCandleIndex > totalCandles - 10)
|
||||
return false;
|
||||
|
||||
// Adaptive update frequency based on timeframe
|
||||
// Shorter timeframes can skip more updates as they're more volatile
|
||||
int signalUpdateFrequency;
|
||||
switch (config.Timeframe)
|
||||
{
|
||||
case Timeframe.OneMinute:
|
||||
case Timeframe.FiveMinutes:
|
||||
signalUpdateFrequency = 10; // Update every 10 candles for fast timeframes
|
||||
break;
|
||||
case Timeframe.FifteenMinutes:
|
||||
case Timeframe.ThirtyMinutes:
|
||||
signalUpdateFrequency = 5; // Update every 5 candles for medium timeframes
|
||||
break;
|
||||
case Timeframe.OneHour:
|
||||
case Timeframe.FourHour:
|
||||
signalUpdateFrequency = 3; // Update every 3 candles for slower timeframes
|
||||
break;
|
||||
case Timeframe.OneDay:
|
||||
signalUpdateFrequency = 1; // Update every candle for daily (already slow)
|
||||
break;
|
||||
default:
|
||||
signalUpdateFrequency = 5; // Default fallback
|
||||
break;
|
||||
}
|
||||
|
||||
// Further optimize based on indicator types in the scenario
|
||||
if (config.Scenario?.Indicators != null)
|
||||
{
|
||||
var hasFastIndicators = config.Scenario.Indicators.Any(ind =>
|
||||
ind.Type == IndicatorType.RsiDivergence ||
|
||||
ind.Type == IndicatorType.StochRsiTrend ||
|
||||
ind.Type == IndicatorType.MacdCross);
|
||||
|
||||
var hasSlowIndicators = config.Scenario.Indicators.Any(ind =>
|
||||
ind.Type == IndicatorType.EmaCross ||
|
||||
ind.Type == IndicatorType.EmaTrend ||
|
||||
ind.Type == IndicatorType.SuperTrend);
|
||||
|
||||
// If we have mostly slow indicators, we can update less frequently
|
||||
if (!hasFastIndicators && hasSlowIndicators)
|
||||
{
|
||||
signalUpdateFrequency = Math.Max(signalUpdateFrequency, 8);
|
||||
}
|
||||
// If we have fast indicators, we need more frequent updates
|
||||
else if (hasFastIndicators && !hasSlowIndicators)
|
||||
{
|
||||
signalUpdateFrequency = Math.Min(signalUpdateFrequency, 3);
|
||||
}
|
||||
}
|
||||
|
||||
// Skip signal updates based on calculated frequency
|
||||
// Skip signal updates based on frequency
|
||||
return (currentCandleIndex % signalUpdateFrequency) != 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user