More fix
This commit is contained in:
@@ -37,10 +37,37 @@ namespace Managing.Application.Bots.Base
|
||||
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)
|
||||
{
|
||||
config.BotType = BotType.ScalpingBot;
|
||||
return new ScalpingBot(
|
||||
config.FlipPosition = false;
|
||||
return new TradingBot(
|
||||
_exchangeService,
|
||||
_tradingBotLogger,
|
||||
_tradingService,
|
||||
@@ -54,7 +81,8 @@ namespace Managing.Application.Bots.Base
|
||||
{
|
||||
config.BotType = BotType.ScalpingBot;
|
||||
config.IsForBacktest = true;
|
||||
return new ScalpingBot(
|
||||
config.FlipPosition = false;
|
||||
return new TradingBot(
|
||||
_exchangeService,
|
||||
_tradingBotLogger,
|
||||
_tradingService,
|
||||
@@ -67,7 +95,8 @@ namespace Managing.Application.Bots.Base
|
||||
public ITradingBot CreateFlippingBot(TradingBotConfig config)
|
||||
{
|
||||
config.BotType = BotType.FlippingBot;
|
||||
return new FlippingBot(
|
||||
config.FlipPosition = true;
|
||||
return new TradingBot(
|
||||
_exchangeService,
|
||||
_tradingBotLogger,
|
||||
_tradingService,
|
||||
@@ -81,7 +110,8 @@ namespace Managing.Application.Bots.Base
|
||||
{
|
||||
config.BotType = BotType.FlippingBot;
|
||||
config.IsForBacktest = true;
|
||||
return new FlippingBot(
|
||||
config.FlipPosition = true;
|
||||
return new TradingBot(
|
||||
_exchangeService,
|
||||
_tradingBotLogger,
|
||||
_tradingService,
|
||||
|
||||
@@ -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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -471,51 +471,74 @@ public class TradingBot : Bot, ITradingBot
|
||||
// Check time-based position management (only if MaxPositionTimeHours is set)
|
||||
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);
|
||||
|
||||
|
||||
// Calculate current unrealized PNL for logging
|
||||
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
|
||||
if (Config.CloseEarlyWhenProfitable && (isPositionInProfit || isAtBreakeven))
|
||||
if (Config.CloseEarlyWhenProfitable)
|
||||
{
|
||||
await LogInformation(
|
||||
$"Closing position early due to profitability - Position opened at {positionForSignal.Open.Date}, " +
|
||||
$"current time {currentTime}. Position is {(isPositionInProfit ? "in profit" : "at breakeven")} " +
|
||||
$"(entry: {positionForSignal.Open.Price}, current: {lastCandle.Close}). " +
|
||||
$"Current PNL: ${currentPnl:F2} ({pnlPercentage:F2}%). " +
|
||||
$"CloseEarlyWhenProfitable is enabled.");
|
||||
await CloseTrade(signal, positionForSignal, positionForSignal.Open, lastCandle.Close, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Time limit exceeded logic
|
||||
if (hasExceededTimeLimit)
|
||||
{
|
||||
if (Config.CloseEarlyWhenProfitable || isPositionInProfit || isAtBreakeven)
|
||||
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)
|
||||
{
|
||||
// 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(
|
||||
$"Closing position due to time limit - Position opened at {positionForSignal.Open.Date}, " +
|
||||
$"current time {currentTime}, max time limit {Config.MaxPositionTimeHours} hours. " +
|
||||
$"Position is {(isPositionInProfit ? "in profit" : isAtBreakeven ? "at breakeven" : "at a loss")} " +
|
||||
$"Closing position early due to profitability - Position opened at {positionForSignal.Open.Date}, " +
|
||||
$"current time {currentTime}. Position is {(isPositionInProfit ? "in profit" : "at breakeven")} " +
|
||||
$"(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);
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
// Time limit exceeded logic when CloseEarlyWhenProfitable is enabled
|
||||
if (hasExceededTimeLimit && (isPositionInProfit || isAtBreakeven))
|
||||
{
|
||||
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 {(isPositionInProfit ? "in profit" : "at breakeven")} " +
|
||||
$"(entry: {positionForSignal.Open.Price}, current: {lastCandle.Close}). " +
|
||||
$"Current PNL: ${currentPnl:F2} ({pnlPercentage:F2}%). " +
|
||||
$"CloseEarlyWhenProfitable is enabled.");
|
||||
await CloseTrade(signal, positionForSignal, positionForSignal.Open, lastCandle.Close, true);
|
||||
return;
|
||||
}
|
||||
else if (hasExceededTimeLimit)
|
||||
{
|
||||
await LogInformation(
|
||||
$"Position has exceeded time limit ({Config.MaxPositionTimeHours} hours) but is at a loss " +
|
||||
$"(entry: {positionForSignal.Open.Price}, current: {lastCandle.Close}). " +
|
||||
$"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}). " +
|
||||
$"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);
|
||||
return;
|
||||
}
|
||||
@@ -1046,7 +1068,7 @@ public class TradingBot : Bot, ITradingBot
|
||||
|
||||
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;
|
||||
Logger.LogInformation($"Signal {signalIdentifier} is now {signalStatus}");
|
||||
@@ -1294,7 +1316,7 @@ public class TradingBot : Bot, ITradingBot
|
||||
|
||||
var timeOpen = currentTime - position.Open.Date;
|
||||
var maxTimeAllowed = TimeSpan.FromHours((double)Config.MaxPositionTimeHours.Value);
|
||||
|
||||
|
||||
return timeOpen >= maxTimeAllowed;
|
||||
}
|
||||
|
||||
@@ -1360,11 +1382,11 @@ public class TradingBot : Bot, ITradingBot
|
||||
|
||||
// Log the configuration update
|
||||
await LogInformation($"Updating bot configuration. Previous config: " +
|
||||
$"Balance: {Config.BotTradingBalance}, " +
|
||||
$"MaxTime: {Config.MaxPositionTimeHours?.ToString() ?? "Disabled"}, " +
|
||||
$"FlipOnlyProfit: {Config.FlipOnlyWhenInProfit}, " +
|
||||
$"Cooldown: {Config.CooldownPeriod}, " +
|
||||
$"MaxLoss: {Config.MaxLossStreak}");
|
||||
$"Balance: {Config.BotTradingBalance}, " +
|
||||
$"MaxTime: {Config.MaxPositionTimeHours?.ToString() ?? "Disabled"}, " +
|
||||
$"FlipOnlyProfit: {Config.FlipOnlyWhenInProfit}, " +
|
||||
$"Cooldown: {Config.CooldownPeriod}, " +
|
||||
$"MaxLoss: {Config.MaxLossStreak}");
|
||||
|
||||
// Update the configuration
|
||||
Config = newConfig;
|
||||
@@ -1388,11 +1410,11 @@ public class TradingBot : Bot, ITradingBot
|
||||
}
|
||||
|
||||
await LogInformation($"Bot configuration updated successfully. New config: " +
|
||||
$"Balance: {Config.BotTradingBalance}, " +
|
||||
$"MaxTime: {Config.MaxPositionTimeHours?.ToString() ?? "Disabled"}, " +
|
||||
$"FlipOnlyProfit: {Config.FlipOnlyWhenInProfit}, " +
|
||||
$"Cooldown: {Config.CooldownPeriod}, " +
|
||||
$"MaxLoss: {Config.MaxLossStreak}");
|
||||
$"Balance: {Config.BotTradingBalance}, " +
|
||||
$"MaxTime: {Config.MaxPositionTimeHours?.ToString() ?? "Disabled"}, " +
|
||||
$"FlipOnlyProfit: {Config.FlipOnlyWhenInProfit}, " +
|
||||
$"Cooldown: {Config.CooldownPeriod}, " +
|
||||
$"MaxLoss: {Config.MaxLossStreak}");
|
||||
|
||||
// Save the updated configuration as backup
|
||||
if (!Config.IsForBacktest)
|
||||
|
||||
Reference in New Issue
Block a user