Fix AgentName
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user