Fix AgentName

This commit is contained in:
2025-10-10 16:08:50 +07:00
parent 7b92aa5727
commit 652c01b8bb
4 changed files with 121 additions and 10 deletions

View File

@@ -1,4 +1,5 @@
using Managing.Application.Abstractions;
using System.Diagnostics;
using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Grains;
using Managing.Application.Abstractions.Services;
using Managing.Application.Trading.Commands;
@@ -26,6 +27,7 @@ public class TradingBotBase : ITradingBot
{
public readonly ILogger<TradingBotBase> Logger;
private readonly IServiceScopeFactory _scopeFactory;
private const int NEW_POSITION_GRACE_SECONDS = 45; // grace window before evaluating missing orders
public TradingBotConfig Config { get; set; }
public Account Account { get; set; }
@@ -492,8 +494,18 @@ public class TradingBotBase : ITradingBot
}
}
if (internalPosition.Status == PositionStatus.New)
if (internalPosition.Status == PositionStatus.New)
{
// Grace period: give the broker time to register open orders before we evaluate
var now = Config.IsForBacktest ? (LastCandle?.Date ?? DateTime.UtcNow) : DateTime.UtcNow;
var secondsSinceOpenRequest = (now - positionForSignal.Open.Date).TotalSeconds;
if (secondsSinceOpenRequest < NEW_POSITION_GRACE_SECONDS)
{
var remaining = NEW_POSITION_GRACE_SECONDS - secondsSinceOpenRequest;
await LogInformation($"⏳ Waiting for broker confirmation\nElapsed: `{secondsSinceOpenRequest:F0}s`\nGrace left: `{remaining:F0}s`");
return; // skip early checks until grace period elapses
}
var orders = await ServiceScopeHelpers.WithScopedService<IExchangeService, List<Trade>>(_scopeFactory,
async exchangeService =>
{
@@ -609,11 +621,30 @@ public class TradingBotBase : ITradingBot
else
{
await LogWarning(
$"❌ Position Never Filled\nNo position on exchange and no orders\nPosition was never filled and will be marked as canceled.");
$"❌ Position Never Filled\nNo position on exchange and no orders\nChecking position history before marking as canceled.");
// Position was never filled (still in New status), so just mark it as canceled
// Don't call HandleClosedPosition as that would incorrectly add volume/PnL
await SetPositionStatus(signal.Identifier, PositionStatus.Canceled);
// Check if position exists in exchange history with PnL before canceling
bool positionFoundInHistory = await CheckPositionInExchangeHistory(positionForSignal);
if (positionFoundInHistory)
{
// Position was actually filled and closed, process it properly
await HandleClosedPosition(positionForSignal);
await LogInformation(
$"✅ Position Found in Exchange History\n" +
$"Position was actually filled and closed\n" +
$"Processing with HandleClosedPosition");
}
else
{
// Position was never filled, just mark as canceled without processing PnL
positionForSignal.Status = PositionStatus.Canceled;
await SetPositionStatus(signal.Identifier, PositionStatus.Canceled);
await UpdatePositionDatabase(positionForSignal);
await LogWarning(
$"❌ Position Confirmed Never Filled\nNo position in exchange history\nMarking as canceled without PnL processing");
}
SetSignalStatus(signal.Identifier, SignalStatus.Expired);
}
}
@@ -1346,6 +1377,8 @@ public class TradingBotBase : ITradingBot
// Skip the candle-based PnL calculation since we have actual GMX data
goto SkipCandleBasedCalculation;
}else{
}
}
@@ -1728,6 +1761,24 @@ public class TradingBotBase : ITradingBot
try
{
var position = Positions.Values.First(p => p.SignalIdentifier == signalIdentifier);
if (positionStatus.Equals(PositionStatus.Canceled)){
var stackTrace = new StackTrace(true);
var callingMethod = stackTrace.GetFrame(1)?.GetMethod();
var callingMethodName = callingMethod?.DeclaringType?.Name + "." + callingMethod?.Name;
var exception = new InvalidOperationException($"Position {signalIdentifier} is already canceled for User {Account.User.Name}");
exception.Data["SignalIdentifier"] = signalIdentifier;
exception.Data["PositionId"] = position.Identifier;
exception.Data["CurrentStatus"] = position.Status.ToString();
exception.Data["RequestedStatus"] = positionStatus.ToString();
exception.Data["AccountName"] = Account.Name;
exception.Data["BotName"] = Config.Name;
exception.Data["CallingMethod"] = callingMethodName;
exception.Data["CallStack"] = Environment.StackTrace;
SentrySdk.CaptureException(exception);
}
if (!position.Status.Equals(positionStatus))
{
Positions.Values.First(p => p.SignalIdentifier == signalIdentifier).Status = positionStatus;
@@ -2480,4 +2531,64 @@ public class TradingBotBase : ITradingBot
Logger.LogError(ex, "Failed to send notifications: {EventType} for bot {BotId}", eventType, Identifier);
}
}
/// <summary>
/// Checks if a position exists in the exchange history with PnL data.
/// This helps determine if a position was actually filled and closed on the exchange
/// even if the bot's internal tracking shows it as never filled.
/// </summary>
/// <param name="position">The position to check</param>
/// <returns>True if position found in exchange history with PnL, false otherwise</returns>
private async Task<bool> CheckPositionInExchangeHistory(Position position)
{
if (Config.IsForBacktest)
{
// For backtests, we don't have exchange history, so return false
return false;
}
try
{
Logger.LogDebug(
$"🔍 Checking Position History for Position: `{position.Identifier}`\nTicker: `{Config.Ticker}`");
List<Position> positionHistory = null;
await ServiceScopeHelpers.WithScopedService<IExchangeService>(_scopeFactory,
async exchangeService =>
{
// Get position history from the last 24 hours
var fromDate = DateTime.UtcNow.AddHours(-24);
var toDate = DateTime.UtcNow;
positionHistory =
await exchangeService.GetPositionHistory(Account, Config.Ticker, fromDate, toDate);
});
// Check if there's a recent position with PnL data
if (positionHistory != null && positionHistory.Any())
{
var recentPosition = positionHistory
.OrderByDescending(p => p.Open?.Date ?? DateTime.MinValue)
.FirstOrDefault();
if (recentPosition != null && recentPosition.ProfitAndLoss != null)
{
Logger.LogDebug(
$"✅ Position Found in Exchange History\n" +
$"Position: `{position.Identifier}`\n" +
$"Exchange PnL: `${recentPosition.ProfitAndLoss.Realized:F2}`\n" +
$"Position was actually filled and closed");
return true;
}
}
Logger.LogDebug(
$"❌ No Position Found in Exchange History\nPosition: `{position.Identifier}`\nPosition was never filled");
return false;
}
catch (Exception ex)
{
Logger.LogError(ex, "Error checking position history for position {PositionId}", position.Identifier);
return false;
}
}
}