From ca1301e837bf3043b2cfa18141f473d35d45a1f4 Mon Sep 17 00:00:00 2001 From: cryptooda Date: Mon, 9 Jun 2025 01:21:38 +0700 Subject: [PATCH] Enhance TradingBot logging with detailed status updates and emojis for better readability and user experience. --- .DS_Store | Bin 10244 -> 10244 bytes src/Managing.Application/Bots/TradingBot.cs | 84 +++++++++----------- 2 files changed, 38 insertions(+), 46 deletions(-) diff --git a/.DS_Store b/.DS_Store index de40e0009a94d28f1e852d6a7490a49011ca85f9..62eff10df3413d0c4ea696acda4f9f317f7d0c29 100644 GIT binary patch delta 53 zcmZn(XbITxUWjq$?cL>Wf_H14u9LKYnUEx2= JW>(REOaS~05&!@I delta 51 zcmZn(XbITxUWjqW s.Identifier == position.SignalIdentifier); if (signalForPosition == null) { - await LogInformation($"Signal not found for position {position.Identifier}. Recreating signal..."); + await LogInformation($"πŸ” **Signal Recovery**\nSignal not found for position `{position.Identifier}`\nRecreating signal from position data..."); // Recreate the signal based on position information signalForPosition = await RecreateSignalFromPosition(position); @@ -360,7 +360,7 @@ public class TradingBot : Bot, ITradingBot if (signalForPosition.Status != SignalStatus.PositionOpen && position.Status != PositionStatus.Finished) { await LogInformation( - $"Updating signal {signalForPosition.Identifier} status from {signalForPosition.Status} to PositionOpen"); + $"πŸ”„ **Signal Status Update**\nSignal: `{signalForPosition.Identifier}`\nStatus: `{signalForPosition.Status}` β†’ `PositionOpen`"); SetSignalStatus(signalForPosition.Identifier, SignalStatus.PositionOpen); } @@ -399,7 +399,7 @@ public class TradingBot : Bot, ITradingBot { try { - Logger.LogInformation($"Updating position {positionForSignal.SignalIdentifier}"); + Logger.LogInformation($"πŸ“Š **Position Update**\nUpdating position: `{positionForSignal.SignalIdentifier}`"); var position = Config.IsForBacktest ? positionForSignal @@ -449,12 +449,12 @@ public class TradingBot : Bot, ITradingBot if (timeSinceRequest.TotalMinutes >= waitTimeMinutes) { await LogWarning( - $"Too many open orders ({orders.Count()}) for unfilled position and {waitTimeMinutes} minutes have passed. Canceling all orders and marking position as canceled."); + $"⚠️ **Order Cleanup**\nToo many open orders: `{orders.Count()}`\nPosition: `{positionForSignal.Identifier}`\nTime elapsed: `{waitTimeMinutes}min`\nCanceling all orders..."); try { await ExchangeService.CancelOrder(Account, Config.Ticker); - await LogInformation($"Successfully canceled all orders for {Config.Ticker}"); + await LogInformation($"βœ… **Orders Canceled**\nSuccessfully canceled all orders for: `{Config.Ticker}`"); } catch (Exception ex) { @@ -469,19 +469,19 @@ public class TradingBot : Bot, ITradingBot { var remainingMinutes = waitTimeMinutes - timeSinceRequest.TotalMinutes; await LogInformation( - $"Position has {orders.Count()} open orders but only {timeSinceRequest.TotalMinutes:F1} minutes have passed. Waiting {remainingMinutes:F1} more minutes before canceling."); + $"⏳ **Waiting for Orders**\nPosition has `{orders.Count()}` open orders\nElapsed: `{timeSinceRequest.TotalMinutes:F1}min`\nWaiting `{remainingMinutes:F1}min` more before canceling"); } } else { await LogInformation( - $"Cannot update Position. Position is still waiting for opening. There is {orders.Count()} open orders."); + $"⏸️ **Position Pending**\nPosition still waiting to open\n`{orders.Count()}` open orders remaining"); } } else { await LogWarning( - $"Cannot update Position. No position on exchange and no orders. Position {signal.Identifier} might be closed already."); + $"❌ **Position Not Found**\nNo position on exchange and no orders\nSignal: `{signal.Identifier}`\nPosition might be already closed"); await HandleClosedPosition(positionForSignal); } } @@ -528,19 +528,14 @@ public class TradingBot : Bot, ITradingBot var profitStatus = isPositionInProfit ? "in profit" : "at a loss"; await LogInformation( - $"Closing position due to time limit ({Config.MaxPositionTimeHours} hours exceeded) - " + - $"Position is {profitStatus} (entry: {positionForSignal.Open.Price}, current: {lastCandle.Close}). " + - $"Realized PNL: ${currentPnl:F2} ({pnlPercentage:F2}%)"); + $"⏰ **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}%`)"); await CloseTrade(signal, positionForSignal, positionForSignal.Open, lastCandle.Close, true); return; } else { await LogInformation( - $"Time limit exceeded but position is at a loss " + - $"(entry: {positionForSignal.Open.Price}, current: {lastCandle.Close}). " + - $"Realized PNL: ${currentPnl:F2} ({pnlPercentage:F2}%). " + - $"Waiting for profit before closing (CloseEarlyWhenProfitable enabled)."); + $"⏳ **Time Limit - Waiting**\nTime limit exceeded but position at loss\nπŸ“‰ Entry: `${positionForSignal.Open.Price}` β†’ Current: `${lastCandle.Close}`\nπŸ’° Realized PNL: `${currentPnl:F2}` (`{pnlPercentage:F2}%`\n🎯 Waiting for profit before closing (CloseEarlyWhenProfitable enabled)"); } } @@ -549,7 +544,7 @@ public class TradingBot : Bot, ITradingBot { if (positionForSignal.StopLoss.Price >= lastCandle.Low) { - await LogInformation($"Closing position - SL hit at {positionForSignal.StopLoss.Price}"); + await LogInformation($"πŸ›‘ **Stop Loss Hit**\nClosing LONG position\nPrice: `${positionForSignal.StopLoss.Price}`"); await CloseTrade(signal, positionForSignal, positionForSignal.StopLoss, positionForSignal.StopLoss.Price, true); positionForSignal.StopLoss.SetStatus(TradeStatus.Filled); @@ -557,14 +552,14 @@ public class TradingBot : Bot, ITradingBot else if (positionForSignal.TakeProfit1.Price <= lastCandle.High && positionForSignal.TakeProfit1.Status != TradeStatus.Filled) { - await LogInformation($"Closing position - TP1 hit at {positionForSignal.TakeProfit1.Price}"); + await LogInformation($"🎯 **Take Profit 1 Hit**\nClosing LONG position\nPrice: `${positionForSignal.TakeProfit1.Price}`"); await CloseTrade(signal, positionForSignal, positionForSignal.TakeProfit1, positionForSignal.TakeProfit1.Price, positionForSignal.TakeProfit2 == null); positionForSignal.TakeProfit1.SetStatus(TradeStatus.Filled); } else if (positionForSignal.TakeProfit2?.Price <= lastCandle.High) { - await LogInformation($"Closing position - TP2 hit at {positionForSignal.TakeProfit2.Price}"); + await LogInformation($"🎯 **Take Profit 2 Hit**\nClosing LONG position\nPrice: `${positionForSignal.TakeProfit2.Price}`"); await CloseTrade(signal, positionForSignal, positionForSignal.TakeProfit2, positionForSignal.TakeProfit2.Price, true); positionForSignal.TakeProfit2.SetStatus(TradeStatus.Filled); @@ -574,7 +569,7 @@ public class TradingBot : Bot, ITradingBot { if (positionForSignal.StopLoss.Price <= lastCandle.High) { - await LogInformation($"Closing position - SL hit at {positionForSignal.StopLoss.Price}"); + await LogInformation($"πŸ›‘ **Stop Loss Hit**\nClosing SHORT position\nPrice: `${positionForSignal.StopLoss.Price}`"); await CloseTrade(signal, positionForSignal, positionForSignal.StopLoss, positionForSignal.StopLoss.Price, true); positionForSignal.StopLoss.SetStatus(TradeStatus.Filled); @@ -582,14 +577,14 @@ public class TradingBot : Bot, ITradingBot else if (positionForSignal.TakeProfit1.Price >= lastCandle.Low && positionForSignal.TakeProfit1.Status != TradeStatus.Filled) { - await LogInformation($"Closing position - TP1 hit at {positionForSignal.TakeProfit1.Price}"); + await LogInformation($"🎯 **Take Profit 1 Hit**\nClosing SHORT position\nPrice: `${positionForSignal.TakeProfit1.Price}`"); await CloseTrade(signal, positionForSignal, positionForSignal.TakeProfit1, positionForSignal.TakeProfit1.Price, positionForSignal.TakeProfit2 == null); positionForSignal.TakeProfit1.SetStatus(TradeStatus.Filled); } else if (positionForSignal.TakeProfit2?.Price >= lastCandle.Low) { - await LogInformation($"Closing position - TP2 hit at {positionForSignal.TakeProfit2.Price}"); + await LogInformation($"🎯 **Take Profit 2 Hit**\nClosing SHORT position\nPrice: `${positionForSignal.TakeProfit2.Price}`"); await CloseTrade(signal, positionForSignal, positionForSignal.TakeProfit2, positionForSignal.TakeProfit2.Price, true); positionForSignal.TakeProfit2.SetStatus(TradeStatus.Filled); @@ -636,9 +631,8 @@ public class TradingBot : Bot, ITradingBot // Check if signal is the opposite side => flip the position if (openedPosition.OriginDirection == signal.Direction) { - // An operation is already open for the same direction await LogInformation( - $"Signal {signal.Identifier} try to open a position but {previousSignal.Identifier} is already open for the same direction"); + $"πŸ“ **Same Direction Signal**\nSignal `{signal.Identifier}` tried to open position\nBut `{previousSignal.Identifier}` already open for same direction"); SetSignalStatus(signal.Identifier, SignalStatus.Expired); } else @@ -660,19 +654,18 @@ public class TradingBot : Bot, ITradingBot : "FlipOnlyWhenInProfit is disabled"; await LogInformation( - $"Try to flip the position because of an opposite direction signal and {flipReason}"); + $"πŸ”„ **Position Flip Initiated**\nFlipping position due to opposite signal\nReason: {flipReason}"); await CloseTrade(previousSignal, openedPosition, openedPosition.Open, lastPrice, true); await SetPositionStatus(previousSignal.Identifier, PositionStatus.Flipped); await OpenPosition(signal); await LogInformation( - $"Position {previousSignal.Identifier} flipped by {signal.Identifier} at {lastPrice}$"); + $"βœ… **Position Flipped**\nPosition: `{previousSignal.Identifier}` β†’ `{signal.Identifier}`\nPrice: `${lastPrice}`"); } else { var currentPnl = openedPosition.ProfitAndLoss?.Realized ?? 0; await LogInformation( - $"Position {previousSignal.Identifier} is not in profit (PnL: ${currentPnl:F2}). " + - $"Signal {signal.Identifier} will wait for position to become profitable before flipping."); + $"πŸ’Έ **Flip Blocked - Not Profitable**\nPosition `{previousSignal.Identifier}` PnL: `${currentPnl:F2}`\nSignal `{signal.Identifier}` will wait for profitability"); SetSignalStatus(signal.Identifier, SignalStatus.Expired); return; @@ -681,7 +674,7 @@ public class TradingBot : Bot, ITradingBot else { await LogInformation( - $"A position is already open for signal {previousSignal.Identifier}. Position flipping is currently not enable, the position will not be flipped."); + $"🚫 **Flip Disabled**\nPosition already open for: `{previousSignal.Identifier}`\nFlipping disabled, new signal expired"); SetSignalStatus(signal.Identifier, SignalStatus.Expired); } } @@ -695,7 +688,7 @@ public class TradingBot : Bot, ITradingBot } await LogInformation( - $"Open position - Date: {signal.Date:T} - SignalIdentifier : {signal.Identifier}"); + $"πŸš€ **Opening Position**\nTime: `{signal.Date:HH:mm:ss}`\nSignal: `{signal.Identifier}`"); try { @@ -752,7 +745,7 @@ public class TradingBot : Bot, ITradingBot // Early return if we're in backtest mode and haven't executed yet if (!Config.IsForBacktest && ExecutionCount < 1) { - await LogInformation("Cannot open position: Bot hasn't executed yet"); + await LogInformation("⏳ **Bot Not Ready**\nCannot open position\nBot hasn't executed first cycle yet"); return false; } @@ -805,9 +798,7 @@ public class TradingBot : Bot, ITradingBot var lastPosition = recentPositions.First(); if (lastPosition.OriginDirection == signal.Direction) { - await LogWarning($"Cannot open position: Max loss streak ({Config.MaxLossStreak}) reached. " + - $"Last {recentPositions.Count} trades were losses. " + - $"Last position was {lastPosition.OriginDirection}, waiting for a signal in the opposite direction."); + await LogWarning($"πŸ”₯ **Loss Streak Limit**\nCannot open position\nMax loss streak: `{Config.MaxLossStreak}` reached\nπŸ“‰ Last `{recentPositions.Count}` trades were losses\n🎯 Last position: `{lastPosition.OriginDirection}`\nWaiting for opposite direction signal"); return false; } @@ -845,7 +836,7 @@ public class TradingBot : Bot, ITradingBot } catch (Exception ex) { - await LogWarning($"Error checking broker positions: {ex.Message}"); + await LogWarning($"❌ **Broker Position Check Failed**\nError checking broker positions\n{ex.Message}"); return false; } } @@ -864,7 +855,7 @@ public class TradingBot : Bot, ITradingBot var cooldownCandle = OptimizedCandles.TakeLast((int)Config.CooldownPeriod).FirstOrDefault(); if (cooldownCandle == null) { - await LogWarning("Cannot check cooldown period: Not enough candles available"); + await LogWarning("πŸ“Š **Cooldown Check Failed**\nCannot check cooldown\nNot enough candles available"); return false; } @@ -879,7 +870,7 @@ public class TradingBot : Bot, ITradingBot if (!canOpenPosition) { await LogInformation( - $"Position cannot be opened: Cooldown period not elapsed. Last position date: {positionSignal.Date}, Cooldown candle date: {cooldownCandle.Date}"); + $"⏳ **Cooldown Active**\nPosition blocked by cooldown period\nπŸ“… Last Position: `{positionSignal.Date:MM/dd HH:mm}`\nπŸ•’ Cooldown Until: `{cooldownCandle.Date:MM/dd HH:mm}`"); } return canOpenPosition; @@ -896,8 +887,7 @@ public class TradingBot : Bot, ITradingBot } await LogInformation( - $"Trying to close trade {Config.Ticker} at {lastPrice} - Type : {tradeToClose.TradeType} - Quantity : {tradeToClose.Quantity} " + - $"- Closing Position : {tradeClosingPosition}"); + $"πŸ”§ **Closing Trade**\nTicker: `{Config.Ticker}`\nPrice: `${lastPrice}`\nπŸ“‹ Type: `{tradeToClose.TradeType}`\nπŸ“Š Quantity: `{tradeToClose.Quantity}`\n🎯 Closing Position: `{(tradeClosingPosition ? "Yes" : "No")}`"); // Get status of position before closing it. The position might be already close by the exchange if (!Config.IsForBacktest && await ExchangeService.GetQuantityInPosition(Account, Config.Ticker) == 0) @@ -966,7 +956,7 @@ public class TradingBot : Bot, ITradingBot await SetPositionStatus(position.SignalIdentifier, PositionStatus.Finished); Logger.LogInformation( - $"Position {position.SignalIdentifier} type correctly close. Pnl on position : {position.ProfitAndLoss?.Realized}"); + $"βœ… **Position Closed Successfully**\nPosition: `{position.SignalIdentifier}`\nPnL: `${position.ProfitAndLoss?.Realized:F2}`"); // Update the bot's trading balance after position is closed if (position.ProfitAndLoss != null) @@ -977,7 +967,7 @@ public class TradingBot : Bot, ITradingBot // Subtract fees Config.BotTradingBalance -= GetPositionFees(position); - Logger.LogInformation($"Updated bot trading balance to: {Config.BotTradingBalance}"); + Logger.LogInformation($"πŸ’° **Balance Updated**\nNew bot trading balance: `${Config.BotTradingBalance:F2}`"); } } else @@ -1008,7 +998,7 @@ public class TradingBot : Bot, ITradingBot if (cancelClose) { - Logger.LogInformation($"Position still open, cancel close orders&"); + Logger.LogInformation($"Position still open, cancel close orders"); } else { @@ -1037,7 +1027,7 @@ public class TradingBot : Bot, ITradingBot if (!position.Status.Equals(positionStatus)) { Positions.First(p => p.SignalIdentifier == signalIdentifier).Status = positionStatus; - await LogInformation($"Position {signalIdentifier} new status {position.Status} => {positionStatus}"); + await LogInformation($"πŸ“Š **Position Status Change**\nPosition: `{signalIdentifier}`\nStatus: `{position.Status}` β†’ `{positionStatus}`"); } SetSignalStatus(signalIdentifier, @@ -1128,7 +1118,7 @@ public class TradingBot : Bot, ITradingBot public async Task ToggleIsForWatchOnly() { Config.IsForWatchingOnly = !Config.IsForWatchingOnly; - await LogInformation($"Watch only toggle for bot : {Name} - Watch only : {Config.IsForWatchingOnly}"); + await LogInformation($"πŸ”„ **Watch Mode Toggle**\nBot: `{Name}`\nWatch Only: `{(Config.IsForWatchingOnly ? "ON" : "OFF")}`"); } private async Task LogInformation(string message) @@ -1163,7 +1153,9 @@ public class TradingBot : Bot, ITradingBot { if (!Config.IsForBacktest) { - await MessengerService.SendTradeMessage(message, isBadBehavior, Account?.User); + // Add bot name at the top of every message + var messageWithBotName = $"πŸ€– **{Name}**\n{message}"; + await MessengerService.SendTradeMessage(messageWithBotName, isBadBehavior, Account?.User); } } @@ -1261,7 +1253,7 @@ public class TradingBot : Bot, ITradingBot throw new Exception("Failed to open position"); } - Logger.LogInformation($"Manually opened position {position.Identifier} for signal {signal.Identifier}"); + Logger.LogInformation($"πŸ‘€ **Manual Position Opened**\nPosition: `{position.Identifier}`\nSignal: `{signal.Identifier}`"); return position; }