Fix front and backtest

This commit is contained in:
2025-07-04 13:14:12 +07:00
parent c9959f7550
commit 2d295fc860
18 changed files with 676 additions and 182 deletions

View File

@@ -30,7 +30,6 @@ namespace Managing.Application.Abstractions
int GetWinRate();
decimal GetProfitAndLoss();
decimal GetTotalFees();
void LoadScenario(string scenarioName);
void LoadScenario(Scenario scenario);
void UpdateIndicatorsValues();
Task LoadAccount();

View File

@@ -1,6 +1,7 @@
using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Repositories;
using Managing.Application.Abstractions.Services;
using Managing.Application.Bots;
using Managing.Core.FixedSizedQueue;
using Managing.Domain.Accounts;
using Managing.Domain.Backtests;
@@ -113,24 +114,15 @@ namespace Managing.Application.Backtesting
List<Candle> candles,
User user = null)
{
// Set FlipPosition based on BotType
config.FlipPosition = config.FlipPosition;
var tradingBot = _botFactory.CreateBacktestTradingBot(config);
// Load scenario - prefer Scenario object over ScenarioName
if (config.Scenario != null)
// Scenario and indicators should already be loaded in constructor by BotService
// This is just a validation check to ensure everything loaded properly
if (tradingBot is TradingBot bot && !bot.Indicators.Any())
{
tradingBot.LoadScenario(config.Scenario);
}
else if (!string.IsNullOrEmpty(config.ScenarioName))
{
tradingBot.LoadScenario(config.ScenarioName);
}
else
{
throw new ArgumentException(
"Either Scenario object or ScenarioName must be provided in TradingBotConfig");
throw new InvalidOperationException(
$"No indicators were loaded for scenario '{config.ScenarioName ?? config.Scenario?.Name}'. " +
"This indicates a problem with scenario loading.");
}
tradingBot.User = user;
@@ -218,7 +210,6 @@ namespace Managing.Application.Backtesting
_logger.LogInformation("Backtest processing completed. Calculating final results...");
bot.Candles = new HashSet<Candle>(candles);
// bot.UpdateIndicatorsValues();
var indicatorsValues = GetIndicatorsValues(bot.Config.Scenario.Indicators, candles);
@@ -256,7 +247,8 @@ namespace Managing.Application.Backtesting
Statistics = stats,
OptimizedMoneyManagement = optimizedMoneyManagement,
IndicatorsValues = AggregateValues(indicatorsValues, bot.IndicatorsValues),
Score = score
Score = score,
Id = Guid.NewGuid().ToString()
};
return result;

View File

@@ -38,27 +38,14 @@ namespace Managing.Application.Bots.Base
ITradingBot IBotFactory.CreateTradingBot(TradingBotConfig config)
{
return new TradingBot(
_exchangeService,
_tradingBotLogger,
_tradingService,
_accountService,
_messengerService,
_botService,
config);
// Delegate to BotService which handles scenario loading properly
return _botService.CreateTradingBot(config);
}
ITradingBot IBotFactory.CreateBacktestTradingBot(TradingBotConfig config)
{
config.IsForBacktest = true;
return new TradingBot(
_exchangeService,
_tradingBotLogger,
_tradingService,
_accountService,
_messengerService,
_botService,
config);
// Delegate to BotService which handles scenario loading properly
return _botService.CreateBacktestTradingBot(config);
}
}
}

View File

@@ -76,6 +76,16 @@ public class TradingBot : Bot, ITradingBot
WalletBalances = new Dictionary<DateTime, decimal>();
IndicatorsValues = new Dictionary<IndicatorType, IndicatorsResultBase>();
// Load indicators if scenario is provided in config
if (Config.Scenario != null)
{
LoadIndicators(Config.Scenario);
}
else
{
throw new ArgumentException("Scenario object must be provided in TradingBotConfig. ScenarioName alone is not sufficient.");
}
if (!Config.IsForBacktest)
{
Interval = CandleExtensions.GetIntervalFromTimeframe(Config.Timeframe);
@@ -91,7 +101,13 @@ public class TradingBot : Bot, ITradingBot
if (!Config.IsForBacktest)
{
LoadScenario(Config.ScenarioName);
// Scenario and indicators should already be loaded in constructor
// This is just a safety check
if (Config.Scenario == null || !Indicators.Any())
{
throw new InvalidOperationException("Scenario or indicators not loaded properly in constructor. This indicates a configuration error.");
}
PreloadCandles().GetAwaiter().GetResult();
CancelAllOrders().GetAwaiter().GetResult();
@@ -127,33 +143,32 @@ public class TradingBot : Bot, ITradingBot
}
}
public void LoadScenario(string scenarioName)
{
if (Config.Scenario != null)
return;
var scenario = TradingService.GetScenarioByName(scenarioName);
if (scenario == null)
{
Logger.LogWarning("No scenario found for this scenario name");
Stop();
}
else
{
LoadIndicators(ScenarioHelpers.GetIndicatorsFromScenario(scenario));
}
}
public void LoadScenario(Scenario scenario)
{
if (scenario == null)
{
Logger.LogWarning("Null scenario provided");
Stop();
var errorMessage = "Null scenario provided";
Logger.LogWarning(errorMessage);
// If called during construction, throw exception instead of Stop()
if (Status == BotStatus.Down)
{
throw new ArgumentException(errorMessage);
}
else
{
Stop();
}
}
else
{
// Store the scenario in config and load indicators
Config.Scenario = scenario;
LoadIndicators(ScenarioHelpers.GetIndicatorsFromScenario(scenario));
Logger.LogInformation($"Loaded scenario '{scenario.Name}' with {Indicators.Count} indicators");
}
}
@@ -164,10 +179,15 @@ public class TradingBot : Bot, ITradingBot
public void LoadIndicators(IEnumerable<IIndicator> indicators)
{
foreach (var strategy in indicators)
// Clear existing indicators to prevent duplicates
Indicators.Clear();
foreach (var indicator in indicators)
{
Indicators.Add(strategy);
Indicators.Add(indicator);
}
Logger.LogInformation($"Loaded {Indicators.Count} indicators for bot '{Name}'");
}
public async Task Run()
@@ -1444,9 +1464,9 @@ public class TradingBot : Bot, ITradingBot
throw new ArgumentException("Account name cannot be null or empty");
}
if (string.IsNullOrEmpty(newConfig.ScenarioName))
if (newConfig.Scenario == null)
{
throw new ArgumentException("Scenario name cannot be null or empty");
throw new ArgumentException("Scenario object must be provided in configuration");
}
// Protect critical properties that shouldn't change for running bots
@@ -1487,9 +1507,17 @@ public class TradingBot : Bot, ITradingBot
// If scenario changed, reload it
var currentScenario = Config.Scenario?.Name;
if (Config.ScenarioName != currentScenario)
var newScenario = newConfig.Scenario?.Name;
if (newScenario != currentScenario)
{
LoadScenario(Config.ScenarioName);
if (newConfig.Scenario != null)
{
LoadScenario(newConfig.Scenario);
}
else
{
throw new ArgumentException("New scenario object must be provided when updating configuration.");
}
}
await LogInformation("✅ **Configuration Applied**\n" +

View File

@@ -134,6 +134,25 @@ namespace Managing.Application.ManageBot
}
}
// Ensure the scenario is properly loaded from database if needed
if (scalpingConfig.Scenario == null && !string.IsNullOrEmpty(scalpingConfig.ScenarioName))
{
var scenario = _tradingService.GetScenarioByName(scalpingConfig.ScenarioName);
if (scenario != null)
{
scalpingConfig.Scenario = scenario;
}
else
{
throw new ArgumentException($"Scenario '{scalpingConfig.ScenarioName}' not found in database when loading backup");
}
}
if (scalpingConfig.Scenario == null)
{
throw new ArgumentException("Scenario object must be provided or ScenarioName must be valid when loading backup");
}
// Ensure critical properties are set correctly for restored bots
scalpingConfig.IsForBacktest = false;
@@ -235,6 +254,25 @@ namespace Managing.Application.ManageBot
if (_botTasks.TryGetValue(identifier, out var botTaskWrapper) &&
botTaskWrapper.BotInstance is TradingBot tradingBot)
{
// Ensure the scenario is properly loaded from database if needed
if (newConfig.Scenario == null && !string.IsNullOrEmpty(newConfig.ScenarioName))
{
var scenario = _tradingService.GetScenarioByName(newConfig.ScenarioName);
if (scenario != null)
{
newConfig.Scenario = scenario;
}
else
{
throw new ArgumentException($"Scenario '{newConfig.ScenarioName}' not found in database when updating configuration");
}
}
if (newConfig.Scenario == null)
{
throw new ArgumentException("Scenario object must be provided or ScenarioName must be valid when updating configuration");
}
// Check if the bot name is changing
if (newConfig.Name != identifier && !string.IsNullOrEmpty(newConfig.Name))
{
@@ -279,6 +317,25 @@ namespace Managing.Application.ManageBot
public ITradingBot CreateTradingBot(TradingBotConfig config)
{
// Ensure the scenario is properly loaded from database if needed
if (config.Scenario == null && !string.IsNullOrEmpty(config.ScenarioName))
{
var scenario = _tradingService.GetScenarioByName(config.ScenarioName);
if (scenario != null)
{
config.Scenario = scenario;
}
else
{
throw new ArgumentException($"Scenario '{config.ScenarioName}' not found in database");
}
}
if (config.Scenario == null)
{
throw new ArgumentException("Scenario object must be provided or ScenarioName must be valid");
}
return new TradingBot(
_exchangeService,
_tradingBotLogger,
@@ -291,6 +348,25 @@ namespace Managing.Application.ManageBot
public ITradingBot CreateBacktestTradingBot(TradingBotConfig config)
{
// Ensure the scenario is properly loaded from database if needed
if (config.Scenario == null && !string.IsNullOrEmpty(config.ScenarioName))
{
var scenario = _tradingService.GetScenarioByName(config.ScenarioName);
if (scenario != null)
{
config.Scenario = scenario;
}
else
{
throw new ArgumentException($"Scenario '{config.ScenarioName}' not found in database");
}
}
if (config.Scenario == null)
{
throw new ArgumentException("Scenario object must be provided or ScenarioName must be valid");
}
config.IsForBacktest = true;
return new TradingBot(
_exchangeService,
@@ -304,6 +380,25 @@ namespace Managing.Application.ManageBot
public ITradingBot CreateScalpingBot(TradingBotConfig config)
{
// Ensure the scenario is properly loaded from database if needed
if (config.Scenario == null && !string.IsNullOrEmpty(config.ScenarioName))
{
var scenario = _tradingService.GetScenarioByName(config.ScenarioName);
if (scenario != null)
{
config.Scenario = scenario;
}
else
{
throw new ArgumentException($"Scenario '{config.ScenarioName}' not found in database");
}
}
if (config.Scenario == null)
{
throw new ArgumentException("Scenario object must be provided or ScenarioName must be valid");
}
config.FlipPosition = false;
return new TradingBot(
_exchangeService,
@@ -317,6 +412,25 @@ namespace Managing.Application.ManageBot
public ITradingBot CreateBacktestScalpingBot(TradingBotConfig config)
{
// Ensure the scenario is properly loaded from database if needed
if (config.Scenario == null && !string.IsNullOrEmpty(config.ScenarioName))
{
var scenario = _tradingService.GetScenarioByName(config.ScenarioName);
if (scenario != null)
{
config.Scenario = scenario;
}
else
{
throw new ArgumentException($"Scenario '{config.ScenarioName}' not found in database");
}
}
if (config.Scenario == null)
{
throw new ArgumentException("Scenario object must be provided or ScenarioName must be valid");
}
config.IsForBacktest = true;
config.FlipPosition = false;
return new TradingBot(
@@ -331,6 +445,25 @@ namespace Managing.Application.ManageBot
public ITradingBot CreateFlippingBot(TradingBotConfig config)
{
// Ensure the scenario is properly loaded from database if needed
if (config.Scenario == null && !string.IsNullOrEmpty(config.ScenarioName))
{
var scenario = _tradingService.GetScenarioByName(config.ScenarioName);
if (scenario != null)
{
config.Scenario = scenario;
}
else
{
throw new ArgumentException($"Scenario '{config.ScenarioName}' not found in database");
}
}
if (config.Scenario == null)
{
throw new ArgumentException("Scenario object must be provided or ScenarioName must be valid");
}
config.FlipPosition = true;
return new TradingBot(
_exchangeService,
@@ -344,6 +477,25 @@ namespace Managing.Application.ManageBot
public ITradingBot CreateBacktestFlippingBot(TradingBotConfig config)
{
// Ensure the scenario is properly loaded from database if needed
if (config.Scenario == null && !string.IsNullOrEmpty(config.ScenarioName))
{
var scenario = _tradingService.GetScenarioByName(config.ScenarioName);
if (scenario != null)
{
config.Scenario = scenario;
}
else
{
throw new ArgumentException($"Scenario '{config.ScenarioName}' not found in database");
}
}
if (config.Scenario == null)
{
throw new ArgumentException("Scenario object must be provided or ScenarioName must be valid");
}
config.IsForBacktest = true;
config.FlipPosition = true;
return new TradingBot(