This commit is contained in:
2025-06-05 01:17:15 +07:00
parent 973a8c7c61
commit 6441687df3
12 changed files with 281 additions and 198 deletions

View File

@@ -176,18 +176,11 @@ public class BacktestController : BaseController
switch (request.Config.BotType) switch (request.Config.BotType)
{ {
case BotType.SimpleBot: case BotType.SimpleBot:
// SimpleBot backtest not implemented yet
break; break;
case BotType.ScalpingBot: case BotType.ScalpingBot:
backtestResult = await _backtester.RunScalpingBotBacktest(
backtestConfig,
request.StartDate,
request.EndDate,
user,
request.Save,
null);
break;
case BotType.FlippingBot: case BotType.FlippingBot:
backtestResult = await _backtester.RunFlippingBotBacktest( backtestResult = await _backtester.RunTradingBotBacktest(
backtestConfig, backtestConfig,
request.StartDate, request.StartDate,
request.EndDate, request.EndDate,

View File

@@ -7,6 +7,39 @@ namespace Managing.Application.Abstractions.Services
{ {
public interface IBacktester public interface IBacktester
{ {
/// <summary>
/// Runs a unified trading bot backtest with the specified configuration and date range.
/// Automatically handles ScalpingBot and FlippingBot behavior based on config.BotType.
/// </summary>
/// <param name="config">The trading bot configuration</param>
/// <param name="startDate">The start date for the backtest</param>
/// <param name="endDate">The end date for the backtest</param>
/// <param name="user">The user running the backtest</param>
/// <param name="save">Whether to save the backtest results</param>
/// <param name="initialCandles">Optional pre-loaded candles</param>
/// <returns>The backtest results</returns>
Task<Backtest> RunTradingBotBacktest(
TradingBotConfig config,
DateTime startDate,
DateTime endDate,
User user = null,
bool save = false,
List<Candle>? initialCandles = null);
/// <summary>
/// Runs a unified trading bot backtest with pre-loaded candles.
/// Automatically handles ScalpingBot and FlippingBot behavior based on config.BotType.
/// </summary>
/// <param name="config">The trading bot configuration</param>
/// <param name="candles">The candles to use for backtesting</param>
/// <param name="user">The user running the backtest</param>
/// <returns>The backtest results</returns>
Task<Backtest> RunTradingBotBacktest(
TradingBotConfig config,
List<Candle> candles,
User user = null);
// Legacy methods - maintained for backward compatibility
Task<Backtest> RunScalpingBotBacktest( Task<Backtest> RunScalpingBotBacktest(
TradingBotConfig config, TradingBotConfig config,
DateTime startDate, DateTime startDate,

View File

@@ -1,5 +1,4 @@
using Managing.Application.Bots; using Managing.Domain.Bots;
using Managing.Domain.Bots;
using Managing.Domain.Workflows; using Managing.Domain.Workflows;
namespace Managing.Application.Abstractions namespace Managing.Application.Abstractions
@@ -7,6 +6,22 @@ namespace Managing.Application.Abstractions
public interface IBotFactory public interface IBotFactory
{ {
IBot CreateSimpleBot(string botName, Workflow workflow); IBot CreateSimpleBot(string botName, Workflow workflow);
/// <summary>
/// Creates a trading bot using the unified TradingBot class
/// </summary>
/// <param name="config">The trading bot configuration</param>
/// <returns>ITradingBot instance</returns>
ITradingBot CreateTradingBot(TradingBotConfig config);
/// <summary>
/// Creates a trading bot for backtesting using the unified TradingBot class
/// </summary>
/// <param name="config">The trading bot configuration</param>
/// <returns>ITradingBot instance configured for backtesting</returns>
ITradingBot CreateBacktestTradingBot(TradingBotConfig config);
// Legacy methods - these will use TradingBot internally but maintain backward compatibility
ITradingBot CreateScalpingBot(TradingBotConfig config); ITradingBot CreateScalpingBot(TradingBotConfig config);
ITradingBot CreateBacktestScalpingBot(TradingBotConfig config); ITradingBot CreateBacktestScalpingBot(TradingBotConfig config);
ITradingBot CreateFlippingBot(TradingBotConfig config); ITradingBot CreateFlippingBot(TradingBotConfig config);

View File

@@ -15,6 +15,21 @@ public interface IBotService
void StartBotFromBackup(BotBackup backupBot); void StartBotFromBackup(BotBackup backupBot);
BotBackup GetBotBackup(string identifier); BotBackup GetBotBackup(string identifier);
/// <summary>
/// Creates a trading bot using the unified TradingBot class
/// </summary>
/// <param name="config">The trading bot configuration</param>
/// <returns>ITradingBot instance</returns>
ITradingBot CreateTradingBot(TradingBotConfig config);
/// <summary>
/// Creates a trading bot for backtesting using the unified TradingBot class
/// </summary>
/// <param name="config">The trading bot configuration</param>
/// <returns>ITradingBot instance configured for backtesting</returns>
ITradingBot CreateBacktestTradingBot(TradingBotConfig config);
// Legacy methods - these will use TradingBot internally but maintain backward compatibility
ITradingBot CreateScalpingBot(TradingBotConfig config); ITradingBot CreateScalpingBot(TradingBotConfig config);
ITradingBot CreateBacktestScalpingBot(TradingBotConfig config); ITradingBot CreateBacktestScalpingBot(TradingBotConfig config);
ITradingBot CreateFlippingBot(TradingBotConfig config); ITradingBot CreateFlippingBot(TradingBotConfig config);

View File

@@ -55,7 +55,18 @@ namespace Managing.Application.Backtesting
return result; return result;
} }
public async Task<Backtest> RunScalpingBotBacktest( /// <summary>
/// Runs a unified trading bot backtest with the specified configuration and date range.
/// Automatically handles ScalpingBot and FlippingBot behavior based on config.BotType.
/// </summary>
/// <param name="config">The trading bot configuration</param>
/// <param name="startDate">The start date for the backtest</param>
/// <param name="endDate">The end date for the backtest</param>
/// <param name="user">The user running the backtest</param>
/// <param name="save">Whether to save the backtest results</param>
/// <param name="initialCandles">Optional pre-loaded candles</param>
/// <returns>The backtest results</returns>
public async Task<Backtest> RunTradingBotBacktest(
TradingBotConfig config, TradingBotConfig config,
DateTime startDate, DateTime startDate,
DateTime endDate, DateTime endDate,
@@ -64,12 +75,17 @@ namespace Managing.Application.Backtesting
List<Candle>? initialCandles = null) List<Candle>? initialCandles = null)
{ {
var account = await GetAccountFromConfig(config); var account = await GetAccountFromConfig(config);
var scalpingBot = _botFactory.CreateBacktestScalpingBot(config);
scalpingBot.LoadScenario(config.ScenarioName); // Set FlipPosition based on BotType
scalpingBot.User = user; config.FlipPosition = config.BotType == BotType.FlippingBot;
await scalpingBot.LoadAccount();
var tradingBot = _botFactory.CreateBacktestTradingBot(config);
tradingBot.LoadScenario(config.ScenarioName);
tradingBot.User = user;
await tradingBot.LoadAccount();
var candles = initialCandles ?? GetCandles(account, config.Ticker, config.Timeframe, startDate, endDate); var candles = initialCandles ?? GetCandles(account, config.Ticker, config.Timeframe, startDate, endDate);
var result = GetBacktestingResult(config, scalpingBot, candles); var result = GetBacktestingResult(config, tradingBot, candles);
if (user != null) if (user != null)
{ {
@@ -88,6 +104,52 @@ namespace Managing.Application.Backtesting
return result; return result;
} }
/// <summary>
/// Runs a unified trading bot backtest with pre-loaded candles.
/// Automatically handles ScalpingBot and FlippingBot behavior based on config.BotType.
/// </summary>
/// <param name="config">The trading bot configuration</param>
/// <param name="candles">The candles to use for backtesting</param>
/// <param name="user">The user running the backtest</param>
/// <returns>The backtest results</returns>
public async Task<Backtest> RunTradingBotBacktest(
TradingBotConfig config,
List<Candle> candles,
User user = null)
{
var account = await GetAccountFromConfig(config);
// Set FlipPosition based on BotType
config.FlipPosition = config.BotType == BotType.FlippingBot;
var tradingBot = _botFactory.CreateBacktestTradingBot(config);
tradingBot.LoadScenario(config.ScenarioName);
tradingBot.User = user;
await tradingBot.LoadAccount();
var result = GetBacktestingResult(config, tradingBot, candles);
if (user != null)
{
result.User = user;
}
return result;
}
// Legacy methods - maintained for backward compatibility
public async Task<Backtest> RunScalpingBotBacktest(
TradingBotConfig config,
DateTime startDate,
DateTime endDate,
User user = null,
bool save = false,
List<Candle>? initialCandles = null)
{
config.BotType = BotType.ScalpingBot; // Ensure correct type
return await RunTradingBotBacktest(config, startDate, endDate, user, save, initialCandles);
}
public async Task<Backtest> RunFlippingBotBacktest( public async Task<Backtest> RunFlippingBotBacktest(
TradingBotConfig config, TradingBotConfig config,
DateTime startDate, DateTime startDate,
@@ -96,30 +158,8 @@ namespace Managing.Application.Backtesting
bool save = false, bool save = false,
List<Candle>? initialCandles = null) List<Candle>? initialCandles = null)
{ {
var account = await GetAccountFromConfig(config); config.BotType = BotType.FlippingBot; // Ensure correct type
var flippingBot = _botFactory.CreateBacktestFlippingBot(config); return await RunTradingBotBacktest(config, startDate, endDate, user, save, initialCandles);
flippingBot.LoadScenario(config.ScenarioName);
flippingBot.User = user;
await flippingBot.LoadAccount();
var candles = initialCandles ?? GetCandles(account, config.Ticker, config.Timeframe, startDate, endDate);
var result = GetBacktestingResult(config, flippingBot, candles);
if (user != null)
{
result.User = user;
}
// Set start and end dates
result.StartDate = startDate;
result.EndDate = endDate;
if (save)
{
_backtestRepository.InsertBacktestForUser(user, result);
}
return result;
} }
public async Task<Backtest> RunScalpingBotBacktest( public async Task<Backtest> RunScalpingBotBacktest(
@@ -127,20 +167,8 @@ namespace Managing.Application.Backtesting
List<Candle> candles, List<Candle> candles,
User user = null) User user = null)
{ {
var account = await GetAccountFromConfig(config); config.BotType = BotType.ScalpingBot; // Ensure correct type
var bot = _botFactory.CreateBacktestScalpingBot(config); return await RunTradingBotBacktest(config, candles, user);
bot.LoadScenario(config.ScenarioName);
bot.User = user;
await bot.LoadAccount();
var result = GetBacktestingResult(config, bot, candles);
if (user != null)
{
result.User = user;
}
return result;
} }
public async Task<Backtest> RunFlippingBotBacktest( public async Task<Backtest> RunFlippingBotBacktest(
@@ -148,20 +176,8 @@ namespace Managing.Application.Backtesting
List<Candle> candles, List<Candle> candles,
User user = null) User user = null)
{ {
var account = await GetAccountFromConfig(config); config.BotType = BotType.FlippingBot; // Ensure correct type
var bot = _botFactory.CreateBacktestFlippingBot(config); return await RunTradingBotBacktest(config, candles, user);
bot.LoadScenario(config.ScenarioName);
bot.User = user;
await bot.LoadAccount();
var result = GetBacktestingResult(config, bot, candles);
if (user != null)
{
result.User = user;
}
return result;
} }
private async Task<Account> GetAccountFromConfig(TradingBotConfig config) private async Task<Account> GetAccountFromConfig(TradingBotConfig config)

View File

@@ -37,10 +37,37 @@ namespace Managing.Application.Bots.Base
return new SimpleBot(botName, _tradingBotLogger, workflow, _botService); return new SimpleBot(botName, _tradingBotLogger, workflow, _botService);
} }
ITradingBot IBotFactory.CreateTradingBot(TradingBotConfig config)
{
return new TradingBot(
_exchangeService,
_tradingBotLogger,
_tradingService,
_accountService,
_messengerService,
_botService,
config);
}
ITradingBot IBotFactory.CreateBacktestTradingBot(TradingBotConfig config)
{
config.IsForBacktest = true;
return new TradingBot(
_exchangeService,
_tradingBotLogger,
_tradingService,
_accountService,
_messengerService,
_botService,
config);
}
// Legacy methods for backward compatibility - will be deprecated
ITradingBot IBotFactory.CreateScalpingBot(TradingBotConfig config) ITradingBot IBotFactory.CreateScalpingBot(TradingBotConfig config)
{ {
config.BotType = BotType.ScalpingBot; config.BotType = BotType.ScalpingBot;
return new ScalpingBot( config.FlipPosition = false;
return new TradingBot(
_exchangeService, _exchangeService,
_tradingBotLogger, _tradingBotLogger,
_tradingService, _tradingService,
@@ -54,7 +81,8 @@ namespace Managing.Application.Bots.Base
{ {
config.BotType = BotType.ScalpingBot; config.BotType = BotType.ScalpingBot;
config.IsForBacktest = true; config.IsForBacktest = true;
return new ScalpingBot( config.FlipPosition = false;
return new TradingBot(
_exchangeService, _exchangeService,
_tradingBotLogger, _tradingBotLogger,
_tradingService, _tradingService,
@@ -67,7 +95,8 @@ namespace Managing.Application.Bots.Base
public ITradingBot CreateFlippingBot(TradingBotConfig config) public ITradingBot CreateFlippingBot(TradingBotConfig config)
{ {
config.BotType = BotType.FlippingBot; config.BotType = BotType.FlippingBot;
return new FlippingBot( config.FlipPosition = true;
return new TradingBot(
_exchangeService, _exchangeService,
_tradingBotLogger, _tradingBotLogger,
_tradingService, _tradingService,
@@ -81,7 +110,8 @@ namespace Managing.Application.Bots.Base
{ {
config.BotType = BotType.FlippingBot; config.BotType = BotType.FlippingBot;
config.IsForBacktest = true; config.IsForBacktest = true;
return new FlippingBot( config.FlipPosition = true;
return new TradingBot(
_exchangeService, _exchangeService,
_tradingBotLogger, _tradingBotLogger,
_tradingService, _tradingService,

View File

@@ -1,32 +0,0 @@
using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Services;
using Managing.Domain.Bots;
using Microsoft.Extensions.Logging;
using static Managing.Common.Enums;
namespace Managing.Application.Bots
{
public class FlippingBot : TradingBot
{
public FlippingBot(
IExchangeService exchangeService,
ILogger<TradingBot> logger,
ITradingService tradingService,
IAccountService accountService,
IMessengerService messengerService,
IBotService botService,
TradingBotConfig config)
: base(exchangeService, logger, tradingService, accountService, messengerService, botService, config)
{
Config.BotType = BotType.FlippingBot;
Config.FlipPosition = true;
}
public sealed override void Start()
{
Logger.LogInformation($"{Name} - Bot Started");
base.Start();
Logger.LogInformation($"Starting {Name} bot - Status : {Status}");
}
}
}

View File

@@ -1,31 +0,0 @@
using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Services;
using Managing.Domain.Bots;
using Microsoft.Extensions.Logging;
using static Managing.Common.Enums;
namespace Managing.Application.Bots
{
public class ScalpingBot : TradingBot
{
public ScalpingBot(
IExchangeService exchangeService,
ILogger<TradingBot> logger,
ITradingService tradingService,
IAccountService accountService,
IMessengerService messengerService,
IBotService botService,
TradingBotConfig config)
: base(exchangeService, logger, tradingService, accountService, messengerService, botService, config)
{
Config.BotType = BotType.ScalpingBot;
}
public sealed override void Start()
{
Logger.LogInformation($"{Name} - Bot Started");
base.Start();
Logger.LogInformation($"Starting {Name} bot - Status : {Status}");
}
}
}

View File

@@ -471,16 +471,23 @@ public class TradingBot : Bot, ITradingBot
// Check time-based position management (only if MaxPositionTimeHours is set) // Check time-based position management (only if MaxPositionTimeHours is set)
if (Config.MaxPositionTimeHours.HasValue) if (Config.MaxPositionTimeHours.HasValue)
{ {
var isPositionInProfit = await IsPositionInProfit(positionForSignal, lastCandle.Close);
var isAtBreakeven = Math.Abs(lastCandle.Close - positionForSignal.Open.Price) < 0.01m; // Small tolerance for breakeven
var hasExceededTimeLimit = HasPositionExceededTimeLimit(positionForSignal, currentTime); var hasExceededTimeLimit = HasPositionExceededTimeLimit(positionForSignal, currentTime);
// Calculate current unrealized PNL for logging // Calculate current unrealized PNL for logging
var currentPnl = CalculateUnrealizedPnl(positionForSignal, lastCandle.Close); var currentPnl = CalculateUnrealizedPnl(positionForSignal, lastCandle.Close);
var pnlPercentage = Math.Round((currentPnl / (positionForSignal.Open.Price * positionForSignal.Open.Quantity)) * 100, 2); var pnlPercentage =
Math.Round(
(currentPnl / (positionForSignal.Open.Price * positionForSignal.Open.Quantity)) * 100, 2);
// Early closure logic when CloseEarlyWhenProfitable is enabled // Early closure logic when CloseEarlyWhenProfitable is enabled
if (Config.CloseEarlyWhenProfitable && (isPositionInProfit || isAtBreakeven)) if (Config.CloseEarlyWhenProfitable)
{
var isPositionInProfit = await IsPositionInProfit(positionForSignal, lastCandle.Close);
var isAtBreakeven =
Math.Abs(lastCandle.Close - positionForSignal.Open.Price) <
0.01m; // Small tolerance for breakeven
if (isPositionInProfit || isAtBreakeven)
{ {
await LogInformation( await LogInformation(
$"Closing position early due to profitability - Position opened at {positionForSignal.Open.Date}, " + $"Closing position early due to profitability - Position opened at {positionForSignal.Open.Date}, " +
@@ -492,30 +499,46 @@ public class TradingBot : Bot, ITradingBot
return; return;
} }
// Time limit exceeded logic // Time limit exceeded logic when CloseEarlyWhenProfitable is enabled
if (hasExceededTimeLimit) if (hasExceededTimeLimit && (isPositionInProfit || isAtBreakeven))
{ {
if (Config.CloseEarlyWhenProfitable || isPositionInProfit || isAtBreakeven)
{
// Close when time limit is reached if:
// 1. CloseEarlyWhenProfitable is enabled (safety net), OR
// 2. Position is in profit/breakeven (when CloseEarlyWhenProfitable is disabled)
await LogInformation( await LogInformation(
$"Closing position due to time limit - Position opened at {positionForSignal.Open.Date}, " + $"Closing position due to time limit - Position opened at {positionForSignal.Open.Date}, " +
$"current time {currentTime}, max time limit {Config.MaxPositionTimeHours} hours. " + $"current time {currentTime}, max time limit {Config.MaxPositionTimeHours} hours. " +
$"Position is {(isPositionInProfit ? "in profit" : isAtBreakeven ? "at breakeven" : "at a loss")} " + $"Position is {(isPositionInProfit ? "in profit" : "at breakeven")} " +
$"(entry: {positionForSignal.Open.Price}, current: {lastCandle.Close}). " + $"(entry: {positionForSignal.Open.Price}, current: {lastCandle.Close}). " +
$"Current PNL: ${currentPnl:F2} ({pnlPercentage:F2}%)"); $"Current PNL: ${currentPnl:F2} ({pnlPercentage:F2}%). " +
$"CloseEarlyWhenProfitable is enabled.");
await CloseTrade(signal, positionForSignal, positionForSignal.Open, lastCandle.Close, true); await CloseTrade(signal, positionForSignal, positionForSignal.Open, lastCandle.Close, true);
return; return;
} }
else else if (hasExceededTimeLimit)
{ {
await LogInformation( await LogInformation(
$"Position has exceeded time limit ({Config.MaxPositionTimeHours} hours) but is at a loss " + $"Position has exceeded time limit ({Config.MaxPositionTimeHours} hours) but is at a loss " +
$"(entry: {positionForSignal.Open.Price}, current: {lastCandle.Close}). " + $"(entry: {positionForSignal.Open.Price}, current: {lastCandle.Close}). " +
$"Current PNL: ${currentPnl:F2} ({pnlPercentage:F2}%). " + $"Current PNL: ${currentPnl:F2} ({pnlPercentage:F2}%). " +
$"CloseEarlyWhenProfitable is disabled - waiting for profit or breakeven before closing."); $"CloseEarlyWhenProfitable is enabled - waiting for profit or breakeven before closing.");
}
}
else
{
// Time limit exceeded logic when CloseEarlyWhenProfitable is disabled
if (hasExceededTimeLimit)
{
var isPositionInProfit = await IsPositionInProfit(positionForSignal, lastCandle.Close);
var profitStatus = isPositionInProfit ? "in profit" :
Math.Abs(lastCandle.Close - positionForSignal.Open.Price) < 0.01m ? "at breakeven" : "at a loss";
await LogInformation(
$"Closing position due to time limit - Position opened at {positionForSignal.Open.Date}, " +
$"current time {currentTime}, max time limit {Config.MaxPositionTimeHours} hours. " +
$"Position is {profitStatus} " +
$"(entry: {positionForSignal.Open.Price}, current: {lastCandle.Close}). " +
$"Current PNL: ${currentPnl:F2} ({pnlPercentage:F2}%). " +
$"CloseEarlyWhenProfitable is disabled - closing regardless of profit status.");
await CloseTrade(signal, positionForSignal, positionForSignal.Open, lastCandle.Close, true);
return;
} }
} }
} }
@@ -665,7 +688,6 @@ public class TradingBot : Bot, ITradingBot
$"Position {previousSignal.Identifier} is not in profit (entry: {openedPosition.Open.Price}, current: {lastPrice}). " + $"Position {previousSignal.Identifier} is not in profit (entry: {openedPosition.Open.Price}, current: {lastPrice}). " +
$"Signal {signal.Identifier} will wait for position to become profitable before flipping."); $"Signal {signal.Identifier} will wait for position to become profitable before flipping.");
// Keep signal in waiting status to check again on next execution
SetSignalStatus(signal.Identifier, SignalStatus.Expired); SetSignalStatus(signal.Identifier, SignalStatus.Expired);
return; return;
} }
@@ -1046,7 +1068,7 @@ public class TradingBot : Bot, ITradingBot
private void SetSignalStatus(string signalIdentifier, SignalStatus signalStatus) private void SetSignalStatus(string signalIdentifier, SignalStatus signalStatus)
{ {
if (Signals.Any(s => s.Identifier == signalIdentifier)) if (Signals.Any(s => s.Identifier == signalIdentifier && s.Status != signalStatus))
{ {
Signals.First(s => s.Identifier == signalIdentifier).Status = signalStatus; Signals.First(s => s.Identifier == signalIdentifier).Status = signalStatus;
Logger.LogInformation($"Signal {signalIdentifier} is now {signalStatus}"); Logger.LogInformation($"Signal {signalIdentifier} is now {signalStatus}");

View File

@@ -146,7 +146,7 @@ namespace Managing.Application.ManageBot
CloseEarlyWhenProfitable = scalpingBotData.CloseEarlyWhenProfitable CloseEarlyWhenProfitable = scalpingBotData.CloseEarlyWhenProfitable
}; };
bot = CreateScalpingBot(scalpingConfig); bot = CreateTradingBot(scalpingConfig);
botTask = Task.Run(() => InitBot((ITradingBot)bot, backupBot)); botTask = Task.Run(() => InitBot((ITradingBot)bot, backupBot));
break; break;
@@ -176,7 +176,7 @@ namespace Managing.Application.ManageBot
CloseEarlyWhenProfitable = flippingBotData.CloseEarlyWhenProfitable CloseEarlyWhenProfitable = flippingBotData.CloseEarlyWhenProfitable
}; };
bot = CreateFlippingBot(flippingConfig); bot = CreateTradingBot(flippingConfig);
botTask = Task.Run(() => InitBot((ITradingBot)bot, backupBot)); botTask = Task.Run(() => InitBot((ITradingBot)bot, backupBot));
break; break;
} }
@@ -282,9 +282,35 @@ namespace Managing.Application.ManageBot
return false; return false;
} }
public ITradingBot CreateTradingBot(TradingBotConfig config)
{
return new TradingBot(
_exchangeService,
_tradingBotLogger,
_tradingService,
_accountService,
_messengerService,
this,
config);
}
public ITradingBot CreateBacktestTradingBot(TradingBotConfig config)
{
config.IsForBacktest = true;
return new TradingBot(
_exchangeService,
_tradingBotLogger,
_tradingService,
_accountService,
_messengerService,
this,
config);
}
public ITradingBot CreateScalpingBot(TradingBotConfig config) public ITradingBot CreateScalpingBot(TradingBotConfig config)
{ {
return new ScalpingBot( config.FlipPosition = false;
return new TradingBot(
_exchangeService, _exchangeService,
_tradingBotLogger, _tradingBotLogger,
_tradingService, _tradingService,
@@ -297,7 +323,8 @@ namespace Managing.Application.ManageBot
public ITradingBot CreateBacktestScalpingBot(TradingBotConfig config) public ITradingBot CreateBacktestScalpingBot(TradingBotConfig config)
{ {
config.IsForBacktest = true; config.IsForBacktest = true;
return new ScalpingBot( config.FlipPosition = false;
return new TradingBot(
_exchangeService, _exchangeService,
_tradingBotLogger, _tradingBotLogger,
_tradingService, _tradingService,
@@ -309,7 +336,8 @@ namespace Managing.Application.ManageBot
public ITradingBot CreateFlippingBot(TradingBotConfig config) public ITradingBot CreateFlippingBot(TradingBotConfig config)
{ {
return new FlippingBot( config.FlipPosition = true;
return new TradingBot(
_exchangeService, _exchangeService,
_tradingBotLogger, _tradingBotLogger,
_tradingService, _tradingService,
@@ -322,7 +350,8 @@ namespace Managing.Application.ManageBot
public ITradingBot CreateBacktestFlippingBot(TradingBotConfig config) public ITradingBot CreateBacktestFlippingBot(TradingBotConfig config)
{ {
config.IsForBacktest = true; config.IsForBacktest = true;
return new FlippingBot( config.FlipPosition = true;
return new TradingBot(
_exchangeService, _exchangeService,
_tradingBotLogger, _tradingBotLogger,
_tradingService, _tradingService,

View File

@@ -73,7 +73,7 @@ namespace Managing.Application.ManageBot
MaxLossStreak = request.Config.MaxLossStreak, MaxLossStreak = request.Config.MaxLossStreak,
MaxPositionTimeHours = request.Config.MaxPositionTimeHours, // Properly handle nullable value MaxPositionTimeHours = request.Config.MaxPositionTimeHours, // Properly handle nullable value
FlipOnlyWhenInProfit = request.Config.FlipOnlyWhenInProfit, FlipOnlyWhenInProfit = request.Config.FlipOnlyWhenInProfit,
FlipPosition = request.Config.FlipPosition, FlipPosition = request.Config.BotType == BotType.FlippingBot, // Set FlipPosition based on BotType
Name = request.Config.Name ?? request.Name, Name = request.Config.Name ?? request.Name,
CloseEarlyWhenProfitable = request.Config.CloseEarlyWhenProfitable CloseEarlyWhenProfitable = request.Config.CloseEarlyWhenProfitable
}; };
@@ -87,24 +87,15 @@ namespace Managing.Application.ManageBot
return bot.GetStatus(); return bot.GetStatus();
case BotType.ScalpingBot: case BotType.ScalpingBot:
var sBot = _botFactory.CreateScalpingBot(configToUse);
sBot.User = request.User;
// Log the configuration being used
await LogBotConfigurationAsync(sBot, "ScalpingBot created");
_botService.AddTradingBotToCache(sBot);
return sBot.GetStatus();
case BotType.FlippingBot: case BotType.FlippingBot:
var fBot = _botFactory.CreateFlippingBot(configToUse); var tradingBot = _botFactory.CreateTradingBot(configToUse);
fBot.User = request.User; tradingBot.User = request.User;
// Log the configuration being used // Log the configuration being used
await LogBotConfigurationAsync(fBot, "FlippingBot created"); await LogBotConfigurationAsync(tradingBot, $"{configToUse.BotType} created");
_botService.AddTradingBotToCache(fBot); _botService.AddTradingBotToCache(tradingBot);
return fBot.GetStatus(); return tradingBot.GetStatus();
} }
return botStatus.ToString(); return botStatus.ToString();
@@ -127,6 +118,7 @@ namespace Managing.Application.ManageBot
$"Balance: {config.BotTradingBalance}, " + $"Balance: {config.BotTradingBalance}, " +
$"MaxTime: {config.MaxPositionTimeHours?.ToString() ?? "Disabled"}, " + $"MaxTime: {config.MaxPositionTimeHours?.ToString() ?? "Disabled"}, " +
$"FlipOnlyProfit: {config.FlipOnlyWhenInProfit}, " + $"FlipOnlyProfit: {config.FlipOnlyWhenInProfit}, " +
$"FlipPosition: {config.FlipPosition}, " +
$"Cooldown: {config.CooldownPeriod}, " + $"Cooldown: {config.CooldownPeriod}, " +
$"MaxLoss: {config.MaxLossStreak}"; $"MaxLoss: {config.MaxLossStreak}";

View File

@@ -101,6 +101,7 @@ public static class WorkersBootstrap
// Repositories // Repositories
services.AddTransient<ICandleRepository, CandleRepository>(); services.AddTransient<ICandleRepository, CandleRepository>();
services.AddTransient<IAgentBalanceRepository, AgentBalanceRepository>();
services.AddTransient<IWorkerRepository, WorkerRepository>(); services.AddTransient<IWorkerRepository, WorkerRepository>();
services.AddTransient<IStatisticRepository, StatisticRepository>(); services.AddTransient<IStatisticRepository, StatisticRepository>();
services.AddTransient<ICandleRepository, CandleRepository>(); services.AddTransient<ICandleRepository, CandleRepository>();