Fix positions for backtests

This commit is contained in:
2025-11-12 19:45:30 +07:00
parent 57ba32f31e
commit e0d2111553
4 changed files with 33 additions and 88 deletions

View File

@@ -177,9 +177,10 @@ public class BacktestExecutor
// Pre-calculate indicator values once for all candles to optimize performance
// This avoids recalculating indicators for every candle iteration
Dictionary<IndicatorType, IndicatorsResultBase> preCalculatedIndicatorValues = null;
var indicatorCalcStart = Stopwatch.GetTimestamp();
if (config.Scenario != null)
if (config.Scenario != null && false)
{
var indicatorCalcStart = Stopwatch.GetTimestamp();
try
{
_logger.LogInformation("⚡ Pre-calculating indicator values for {IndicatorCount} indicators",
@@ -222,15 +223,12 @@ public class BacktestExecutor
var initialBalance = config.BotTradingBalance;
// Pre-allocate and populate candle structures for maximum performance
var orderedCandles = candles.OrderBy(c => c.Date).ToList();
var orderedCandles = candles.ToList();
// Skip pre-calculated signals - the approach was flawed and caused performance regression
// The signal calculation depends on rolling window state and cannot be pre-calculated effectively
// Use optimized rolling window approach - TradingBox.GetSignal only needs last 600 candles
const int rollingWindowSize = 600;
var rollingCandles = new List<Candle>(rollingWindowSize); // Pre-allocate capacity for better performance
var fixedCandlesHashSet = new HashSet<Candle>(rollingWindowSize); // Reuse HashSet to avoid allocations
var candlesProcessed = 0;
// Signal caching optimization - reduce signal update frequency for better performance
@@ -242,6 +240,8 @@ public class BacktestExecutor
var lastWalletCheck = 0;
var lastWalletBalance = config.BotTradingBalance;
var fixedCandles = new HashSet<Candle>();
// Track memory usage during processing
var peakMemory = initialMemory;
const int memoryCheckInterval = 100; // Check memory every N candles to reduce GC.GetTotalMemory overhead
@@ -258,44 +258,15 @@ public class BacktestExecutor
// Process all candles with optimized rolling window approach
foreach (var candle in orderedCandles)
{
// Maintain rolling window efficiently using List
rollingCandles.Add(candle);
if (rollingCandles.Count > rollingWindowSize)
{
// Remove oldest candle from both structures
var removedCandle = rollingCandles[0];
rollingCandles.RemoveAt(0);
fixedCandlesHashSet.Remove(removedCandle);
}
// Add to HashSet for reuse
fixedCandlesHashSet.Add(candle);
fixedCandles.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);
if (!shouldSkipSignalUpdate)
{
// Smart signal caching - reduce signal update frequency for performance
// RSI and similar indicators don't need updates every candle for 15-minute data
var signalUpdateStart = Stopwatch.GetTimestamp();
await tradingBot.UpdateSignals(fixedCandlesHashSet);
signalUpdateTotalTime += Stopwatch.GetElapsedTime(signalUpdateStart);
telemetry.TotalSignalUpdates++;
}
else
{
signalUpdateSkipCount++;
// Skip signal update - reuse previous signal state
// This saves ~1ms per skipped update and improves performance significantly
}
// Run with optimized backtest path (minimize async calls)
var backtestStepStart = Stopwatch.GetTimestamp();
await RunOptimizedBacktestStep(tradingBot);
await tradingBot.UpdateSignals(fixedCandles);
await tradingBot.Run();
backtestStepTotalTime += Stopwatch.GetElapsedTime(backtestStepStart);
telemetry.TotalBacktestSteps++;
@@ -343,11 +314,12 @@ public class BacktestExecutor
// Track peak memory usage (reduced frequency to minimize GC overhead)
if (currentCandle - lastMemoryCheck >= memoryCheckInterval)
{
var currentMemory = GC.GetTotalMemory(false);
if (currentMemory > peakMemory)
{
peakMemory = currentMemory;
var currentMemory = GC.GetTotalMemory(false);
if (currentMemory > peakMemory)
{
peakMemory = currentMemory;
}
lastMemoryCheck = currentCandle;
}
@@ -554,7 +526,6 @@ public class BacktestExecutor
/// Pre-calculates all signals for the entire backtest period
/// This eliminates repeated GetSignal() calls during the backtest loop
/// </summary>
/// <summary>
/// Converts a Backtest to LightBacktest
/// </summary>
@@ -609,7 +580,6 @@ public class BacktestExecutor
private async Task RunOptimizedBacktestStep(TradingBotBase tradingBot)
{
// Use the standard Run method but ensure it's optimized for backtests
await tradingBot.Run();
}