Improve perf for backtests
This commit is contained in:
@@ -14,6 +14,7 @@ using Managing.Domain.Indicators;
|
||||
using Managing.Domain.Scenarios;
|
||||
using Managing.Domain.Shared.Helpers;
|
||||
using Managing.Domain.Strategies;
|
||||
using Managing.Domain.Strategies.Base;
|
||||
using Managing.Domain.Synth.Models;
|
||||
using Managing.Domain.Trades;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@@ -28,7 +29,9 @@ public class TradingBotBase : ITradingBot
|
||||
public readonly ILogger<TradingBotBase> Logger;
|
||||
private readonly IServiceScopeFactory _scopeFactory;
|
||||
private const int NEW_POSITION_GRACE_SECONDS = 45; // grace window before evaluating missing orders
|
||||
private const int CLOSE_POSITION_GRACE_MS = 20000; // grace window before closing position to allow broker processing (20 seconds)
|
||||
|
||||
private const int
|
||||
CLOSE_POSITION_GRACE_MS = 20000; // grace window before closing position to allow broker processing (20 seconds)
|
||||
|
||||
public TradingBotConfig Config { get; set; }
|
||||
public Account Account { get; set; }
|
||||
@@ -42,6 +45,12 @@ public class TradingBotBase : ITradingBot
|
||||
public Candle LastCandle { get; set; }
|
||||
public DateTime? LastPositionClosingTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Pre-calculated indicator values for backtesting optimization.
|
||||
/// Key is IndicatorType, Value is the calculated indicator result.
|
||||
/// </summary>
|
||||
public Dictionary<IndicatorType, IndicatorsResultBase> PreCalculatedIndicatorValues { get; set; }
|
||||
|
||||
|
||||
public TradingBotBase(
|
||||
ILogger<TradingBotBase> logger,
|
||||
@@ -56,6 +65,7 @@ public class TradingBotBase : ITradingBot
|
||||
Positions = new Dictionary<Guid, Position>();
|
||||
WalletBalances = new Dictionary<DateTime, decimal>();
|
||||
PreloadSince = CandleHelpers.GetBotPreloadSinceFromTimeframe(config.Timeframe);
|
||||
PreCalculatedIndicatorValues = new Dictionary<IndicatorType, IndicatorsResultBase>();
|
||||
}
|
||||
|
||||
public async Task Start(BotStatus previousStatus)
|
||||
@@ -269,7 +279,8 @@ public class TradingBotBase : ITradingBot
|
||||
if (Config.IsForBacktest && candles != null)
|
||||
{
|
||||
var backtestSignal =
|
||||
TradingBox.GetSignal(candles, Config.Scenario, Signals, Config.Scenario.LoopbackPeriod);
|
||||
TradingBox.GetSignal(candles, Config.Scenario, Signals, Config.Scenario.LoopbackPeriod,
|
||||
PreCalculatedIndicatorValues);
|
||||
if (backtestSignal == null) return;
|
||||
await AddSignal(backtestSignal);
|
||||
}
|
||||
@@ -768,7 +779,8 @@ public class TradingBotBase : ITradingBot
|
||||
await LogInformation(
|
||||
$"⏰ Time Limit Close\nClosing position due to time limit: `{Config.MaxPositionTimeHours}h` exceeded\n📈 Position Status: {profitStatus}\n💰 Entry: `${positionForSignal.Open.Price}` → Current: `${lastCandle.Close}`\n📊 Realized PNL: `${currentPnl:F2}` (`{pnlPercentage:F2}%`)");
|
||||
// Force a market close: compute PnL based on current price instead of SL/TP
|
||||
await CloseTrade(signal, positionForSignal, positionForSignal.Open, lastCandle.Close, true, true);
|
||||
await CloseTrade(signal, positionForSignal, positionForSignal.Open, lastCandle.Close, true,
|
||||
true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1355,7 +1367,8 @@ public class TradingBotBase : ITradingBot
|
||||
await SetPositionStatus(signal.Identifier, PositionStatus.Finished);
|
||||
}
|
||||
|
||||
await HandleClosedPosition(closedPosition, forceMarketClose ? lastPrice : (decimal?)null, forceMarketClose);
|
||||
await HandleClosedPosition(closedPosition, forceMarketClose ? lastPrice : (decimal?)null,
|
||||
forceMarketClose);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1371,13 +1384,15 @@ public class TradingBotBase : ITradingBot
|
||||
// Trade close on exchange => Should close trade manually
|
||||
await SetPositionStatus(signal.Identifier, PositionStatus.Finished);
|
||||
// Ensure trade dates are properly updated even for canceled/rejected positions
|
||||
await HandleClosedPosition(position, forceMarketClose ? lastPrice : (decimal?)null, forceMarketClose);
|
||||
await HandleClosedPosition(position, forceMarketClose ? lastPrice : (decimal?)null,
|
||||
forceMarketClose);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandleClosedPosition(Position position, decimal? forcedClosingPrice = null, bool forceMarketClose = false)
|
||||
private async Task HandleClosedPosition(Position position, decimal? forcedClosingPrice = null,
|
||||
bool forceMarketClose = false)
|
||||
{
|
||||
if (Positions.ContainsKey(position.Identifier))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user