Enhance TradingBot logging with detailed status updates and emojis for better readability and user experience.
This commit is contained in:
@@ -327,7 +327,7 @@ public class TradingBot : Bot, ITradingBot
|
||||
Signals.Add(recreatedSignal);
|
||||
|
||||
await LogInformation(
|
||||
$"Successfully recreated signal {recreatedSignal.Identifier} for position {position.Identifier}");
|
||||
$"🔍 **Signal Recovery Success**\nRecreated signal: `{recreatedSignal.Identifier}`\nFor position: `{position.Identifier}`");
|
||||
return recreatedSignal;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -344,7 +344,7 @@ public class TradingBot : Bot, ITradingBot
|
||||
var signalForPosition = Signals.FirstOrDefault(s => 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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user