Adapt spot for recovery
This commit is contained in:
@@ -209,37 +209,6 @@ public class FuturesBot : TradingBotBase, ITradingBot
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task VerifyAndUpdateBalanceAsync()
|
|
||||||
{
|
|
||||||
// Live trading: verify real USDC balance
|
|
||||||
if (Config.TradingType == TradingType.BacktestFutures) return;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var actualBalance = await ServiceScopeHelpers.WithScopedService<IExchangeService, decimal>(_scopeFactory,
|
|
||||||
async exchangeService =>
|
|
||||||
{
|
|
||||||
var balances = await exchangeService.GetBalances(Account);
|
|
||||||
var usdcBalance = balances.FirstOrDefault(b => b.TokenName?.ToUpper() == "USDC");
|
|
||||||
return usdcBalance?.Amount ?? 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (actualBalance < Config.BotTradingBalance)
|
|
||||||
{
|
|
||||||
Logger.LogWarning(
|
|
||||||
"Actual USDC balance ({ActualBalance:F2}) is less than configured balance ({ConfiguredBalance:F2}). Updating configuration.",
|
|
||||||
actualBalance, Config.BotTradingBalance);
|
|
||||||
|
|
||||||
var newConfig = Config;
|
|
||||||
newConfig.BotTradingBalance = actualBalance;
|
|
||||||
await UpdateConfiguration(newConfig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.LogError(ex, "Error verifying and updating balance");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override async Task SynchronizeWithBrokerPositions(Position internalPosition, Position positionForSignal,
|
protected override async Task SynchronizeWithBrokerPositions(Position internalPosition, Position positionForSignal,
|
||||||
List<Position> brokerPositions)
|
List<Position> brokerPositions)
|
||||||
|
|||||||
@@ -233,37 +233,6 @@ public class SpotBot : TradingBotBase, ITradingBot
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task VerifyAndUpdateBalanceAsync()
|
|
||||||
{
|
|
||||||
// Live trading: verify real USDC balance for spot trading
|
|
||||||
if (Config.TradingType == TradingType.BacktestSpot) return;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var actualBalance = await ServiceScopeHelpers.WithScopedService<IExchangeService, decimal>(_scopeFactory,
|
|
||||||
async exchangeService =>
|
|
||||||
{
|
|
||||||
var balances = await exchangeService.GetBalances(Account);
|
|
||||||
var usdcBalance = balances.FirstOrDefault(b => b.TokenName?.ToUpper() == "USDC");
|
|
||||||
return usdcBalance?.Amount ?? 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (actualBalance < Config.BotTradingBalance)
|
|
||||||
{
|
|
||||||
Logger.LogWarning(
|
|
||||||
"Actual USDC balance ({ActualBalance:F2}) is less than configured balance ({ConfiguredBalance:F2}). Updating configuration.",
|
|
||||||
actualBalance, Config.BotTradingBalance);
|
|
||||||
|
|
||||||
var newConfig = Config;
|
|
||||||
newConfig.BotTradingBalance = actualBalance;
|
|
||||||
await UpdateConfiguration(newConfig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.LogError(ex, "Error verifying and updating balance");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override async Task SynchronizeWithBrokerPositions(Position internalPosition, Position positionForSignal,
|
protected override async Task SynchronizeWithBrokerPositions(Position internalPosition, Position positionForSignal,
|
||||||
List<Position> brokerPositions)
|
List<Position> brokerPositions)
|
||||||
@@ -282,7 +251,31 @@ public class SpotBot : TradingBotBase, ITradingBot
|
|||||||
|
|
||||||
if (tokenBalance != null && tokenBalance.Amount > 0)
|
if (tokenBalance != null && tokenBalance.Amount > 0)
|
||||||
{
|
{
|
||||||
// Token balance exists - verify position is filled
|
// Verify that the token balance matches the position amount with 0.1% tolerance
|
||||||
|
var positionQuantity = internalPosition.Open.Quantity;
|
||||||
|
var tokenBalanceAmount = tokenBalance.Amount;
|
||||||
|
|
||||||
|
if (positionQuantity > 0)
|
||||||
|
{
|
||||||
|
var tolerance = positionQuantity * 0.001m; // 0.1% tolerance
|
||||||
|
var difference = Math.Abs(tokenBalanceAmount - positionQuantity);
|
||||||
|
|
||||||
|
if (difference > tolerance)
|
||||||
|
{
|
||||||
|
await LogWarningAsync(
|
||||||
|
$"⚠️ Token Balance Mismatch - Position Verification Failed\n" +
|
||||||
|
$"Position: `{internalPosition.Identifier}`\n" +
|
||||||
|
$"Position Quantity: `{positionQuantity:F5}`\n" +
|
||||||
|
$"Token Balance: `{tokenBalanceAmount:F5}`\n" +
|
||||||
|
$"Difference: `{difference:F5}`\n" +
|
||||||
|
$"Tolerance (0.1%): `{tolerance:F5}`\n" +
|
||||||
|
$"Token balance does not match position amount within tolerance\n" +
|
||||||
|
$"Skipping position synchronization");
|
||||||
|
return; // Skip processing if amounts don't match
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token balance exists and matches position - verify position is filled
|
||||||
var previousPositionStatus = internalPosition.Status;
|
var previousPositionStatus = internalPosition.Status;
|
||||||
|
|
||||||
// Position found on broker (token balance exists), means the position is filled
|
// Position found on broker (token balance exists), means the position is filled
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ public abstract class TradingBotBase : ITradingBot
|
|||||||
|
|
||||||
public async Task LoadAccount()
|
public async Task LoadAccount()
|
||||||
{
|
{
|
||||||
if (Config.TradingType == TradingType.BacktestFutures) return;
|
if (TradingBox.IsBacktestTrading(Config.TradingType)) return;
|
||||||
await ServiceScopeHelpers.WithScopedService<IAccountService>(_scopeFactory, async accountService =>
|
await ServiceScopeHelpers.WithScopedService<IAccountService>(_scopeFactory, async accountService =>
|
||||||
{
|
{
|
||||||
var account = await accountService.GetAccountByAccountName(Config.AccountName, false, false);
|
var account = await accountService.GetAccountByAccountName(Config.AccountName, false, false);
|
||||||
@@ -182,7 +182,7 @@ public abstract class TradingBotBase : ITradingBot
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task VerifyAndUpdateBalance()
|
public async Task VerifyAndUpdateBalance()
|
||||||
{
|
{
|
||||||
if (Config.TradingType == TradingType.BacktestFutures) return;
|
if (TradingBox.IsBacktestTrading(Config.TradingType)) return;
|
||||||
if (Account == null)
|
if (Account == null)
|
||||||
{
|
{
|
||||||
Logger.LogWarning("Cannot verify balance: Account is null");
|
Logger.LogWarning("Cannot verify balance: Account is null");
|
||||||
@@ -367,12 +367,8 @@ public abstract class TradingBotBase : ITradingBot
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// First, process all existing positions that are not finished
|
// First, process all existing positions that are not finished
|
||||||
// Optimized: Inline the filter to avoid LINQ overhead
|
foreach (var position in Positions.Values.Where(p => !p.IsFinished()))
|
||||||
foreach (var position in Positions.Values)
|
|
||||||
{
|
{
|
||||||
if (position.IsFinished())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var signalForPosition = Signals[position.SignalIdentifier];
|
var signalForPosition = Signals[position.SignalIdentifier];
|
||||||
if (signalForPosition == null)
|
if (signalForPosition == null)
|
||||||
{
|
{
|
||||||
@@ -436,7 +432,7 @@ public abstract class TradingBotBase : ITradingBot
|
|||||||
|
|
||||||
protected void UpdateWalletBalances()
|
protected void UpdateWalletBalances()
|
||||||
{
|
{
|
||||||
var date = Config.TradingType == TradingType.BacktestFutures
|
var date = TradingBox.IsBacktestTrading(Config.TradingType)
|
||||||
? LastCandle?.Date ?? DateTime.UtcNow
|
? LastCandle?.Date ?? DateTime.UtcNow
|
||||||
: DateTime.UtcNow;
|
: DateTime.UtcNow;
|
||||||
|
|
||||||
@@ -485,13 +481,13 @@ public abstract class TradingBotBase : ITradingBot
|
|||||||
Candle lastCandle = null;
|
Candle lastCandle = null;
|
||||||
await ServiceScopeHelpers.WithScopedService<IExchangeService>(_scopeFactory, async exchangeService =>
|
await ServiceScopeHelpers.WithScopedService<IExchangeService>(_scopeFactory, async exchangeService =>
|
||||||
{
|
{
|
||||||
lastCandle = Config.TradingType == TradingType.BacktestFutures
|
lastCandle = TradingBox.IsBacktestTrading(Config.TradingType)
|
||||||
? LastCandle
|
? LastCandle
|
||||||
: await exchangeService.GetCandle(Account, Config.Ticker,
|
: await exchangeService.GetCandle(Account, Config.Ticker,
|
||||||
DateTime.UtcNow);
|
DateTime.UtcNow);
|
||||||
});
|
});
|
||||||
|
|
||||||
var currentTime = Config.TradingType == TradingType.BacktestFutures ? lastCandle.Date : DateTime.UtcNow;
|
var currentTime = TradingBox.IsBacktestTrading(Config.TradingType) ? lastCandle.Date : DateTime.UtcNow;
|
||||||
var currentPnl = positionForSignal.ProfitAndLoss?.Net ?? 0;
|
var currentPnl = positionForSignal.ProfitAndLoss?.Net ?? 0;
|
||||||
var pnlPercentage = TradingBox.CalculatePnLPercentage(currentPnl, positionForSignal.Open.Price,
|
var pnlPercentage = TradingBox.CalculatePnLPercentage(currentPnl, positionForSignal.Open.Price,
|
||||||
positionForSignal.Open.Quantity);
|
positionForSignal.Open.Quantity);
|
||||||
@@ -1020,7 +1016,7 @@ public abstract class TradingBotBase : ITradingBot
|
|||||||
signal.Date,
|
signal.Date,
|
||||||
Account.User,
|
Account.User,
|
||||||
Config.BotTradingBalance,
|
Config.BotTradingBalance,
|
||||||
Config.TradingType == TradingType.BacktestFutures,
|
TradingBox.IsBacktestTrading(Config.TradingType),
|
||||||
lastPrice,
|
lastPrice,
|
||||||
signalIdentifier: signal.Identifier,
|
signalIdentifier: signal.Identifier,
|
||||||
initiatorIdentifier: Identifier,
|
initiatorIdentifier: Identifier,
|
||||||
@@ -1245,7 +1241,7 @@ public abstract class TradingBotBase : ITradingBot
|
|||||||
|
|
||||||
// Update the last position closing time for cooldown period tracking
|
// Update the last position closing time for cooldown period tracking
|
||||||
// Only update if position was actually filled
|
// Only update if position was actually filled
|
||||||
LastPositionClosingTime = Config.TradingType == TradingType.BacktestFutures
|
LastPositionClosingTime = TradingBox.IsBacktestTrading(Config.TradingType)
|
||||||
? currentCandle.Date
|
? currentCandle.Date
|
||||||
: DateTime.UtcNow;
|
: DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
@@ -1498,7 +1494,7 @@ public abstract class TradingBotBase : ITradingBot
|
|||||||
signal,
|
signal,
|
||||||
currentPrice,
|
currentPrice,
|
||||||
Config,
|
Config,
|
||||||
Config.TradingType == TradingType.BacktestFutures);
|
TradingBox.IsBacktestTrading(Config.TradingType));
|
||||||
|
|
||||||
if (signalValidationResult.Confidence == Confidence.None ||
|
if (signalValidationResult.Confidence == Confidence.None ||
|
||||||
signalValidationResult.Confidence == Confidence.Low ||
|
signalValidationResult.Confidence == Confidence.Low ||
|
||||||
@@ -1859,7 +1855,7 @@ public abstract class TradingBotBase : ITradingBot
|
|||||||
// Calculate cooldown end time based on last position closing time
|
// Calculate cooldown end time based on last position closing time
|
||||||
var cooldownEndTime =
|
var cooldownEndTime =
|
||||||
TradingBox.CalculateCooldownEndTime(LastPositionClosingTime.Value, Config.Timeframe, Config.CooldownPeriod);
|
TradingBox.CalculateCooldownEndTime(LastPositionClosingTime.Value, Config.Timeframe, Config.CooldownPeriod);
|
||||||
var isInCooldown = (Config.TradingType == TradingType.BacktestFutures ? LastCandle.Date : DateTime.UtcNow) <
|
var isInCooldown = (TradingBox.IsBacktestTrading(Config.TradingType) ? LastCandle.Date : DateTime.UtcNow) <
|
||||||
cooldownEndTime;
|
cooldownEndTime;
|
||||||
|
|
||||||
if (isInCooldown)
|
if (isInCooldown)
|
||||||
@@ -1917,7 +1913,7 @@ public abstract class TradingBotBase : ITradingBot
|
|||||||
private async Task NotifyAgentAndPlatformGrainAsync(NotificationEventType eventType,
|
private async Task NotifyAgentAndPlatformGrainAsync(NotificationEventType eventType,
|
||||||
Position position)
|
Position position)
|
||||||
{
|
{
|
||||||
if (Config.TradingType == TradingType.BacktestFutures)
|
if (TradingBox.IsBacktestTrading(Config.TradingType))
|
||||||
{
|
{
|
||||||
return; // Skip notifications for backtest
|
return; // Skip notifications for backtest
|
||||||
}
|
}
|
||||||
@@ -2064,7 +2060,7 @@ public abstract class TradingBotBase : ITradingBot
|
|||||||
|
|
||||||
protected virtual async Task LogInformationAsync(string message)
|
protected virtual async Task LogInformationAsync(string message)
|
||||||
{
|
{
|
||||||
if (Config.TradingType == TradingType.BacktestFutures)
|
if (TradingBox.IsBacktestTrading(Config.TradingType))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Logger.LogInformation(message);
|
Logger.LogInformation(message);
|
||||||
@@ -2081,7 +2077,7 @@ public abstract class TradingBotBase : ITradingBot
|
|||||||
|
|
||||||
protected virtual async Task LogWarningAsync(string message)
|
protected virtual async Task LogWarningAsync(string message)
|
||||||
{
|
{
|
||||||
if (Config.TradingType == TradingType.BacktestFutures)
|
if (TradingBox.IsBacktestTrading(Config.TradingType))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
message = $"[{Config.Name}] {message}";
|
message = $"[{Config.Name}] {message}";
|
||||||
@@ -2098,7 +2094,7 @@ public abstract class TradingBotBase : ITradingBot
|
|||||||
|
|
||||||
protected virtual async Task LogDebugAsync(string message)
|
protected virtual async Task LogDebugAsync(string message)
|
||||||
{
|
{
|
||||||
if (Config.TradingType == TradingType.BacktestFutures)
|
if (TradingBox.IsBacktestTrading(Config.TradingType))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Logger.LogDebug(message);
|
Logger.LogDebug(message);
|
||||||
|
|||||||
@@ -1348,9 +1348,15 @@ public static class TradingBox
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsBacktestTrading(TradingType tradingType)
|
||||||
|
{
|
||||||
|
return !IsLiveTrading(tradingType);
|
||||||
|
}
|
||||||
|
|
||||||
public static TradingType GetLiveTradingType(TradingType tradingType)
|
public static TradingType GetLiveTradingType(TradingType tradingType)
|
||||||
{
|
{
|
||||||
return tradingType switch {
|
return tradingType switch
|
||||||
|
{
|
||||||
TradingType.BacktestFutures => TradingType.Futures,
|
TradingType.BacktestFutures => TradingType.Futures,
|
||||||
TradingType.BacktestSpot => TradingType.Spot,
|
TradingType.BacktestSpot => TradingType.Spot,
|
||||||
_ => throw new InvalidOperationException($"Unsupported TradingType for live trading: {tradingType}")
|
_ => throw new InvalidOperationException($"Unsupported TradingType for live trading: {tradingType}")
|
||||||
|
|||||||
Reference in New Issue
Block a user