Clean code, remove warning for future and spot

This commit is contained in:
2025-12-11 14:36:35 +07:00
parent df8c199cce
commit 1426f0b560
17 changed files with 314 additions and 388 deletions

View File

@@ -94,7 +94,7 @@ public class SpotBot : TradingBotBase
// Try to get current price from exchange
currentPrice = await ServiceScopeHelpers.WithScopedService<IExchangeService, decimal>(
_scopeFactory,
async exchangeService => { return await exchangeService.GetCurrentPrice(Account, Config.Ticker); });
async exchangeService => await exchangeService.GetCurrentPrice(Account, Config.Ticker));
}
if (currentPrice == 0)
@@ -144,10 +144,7 @@ public class SpotBot : TradingBotBase
{
// For live trading, get real-time candle from exchange
return await ServiceScopeHelpers.WithScopedService<IExchangeService, Candle>(_scopeFactory,
async exchangeService =>
{
return await exchangeService.GetCandle(Account, Config.Ticker, DateTime.UtcNow);
});
async exchangeService => await exchangeService.GetCandle(Account, Config.Ticker, DateTime.UtcNow));
}
protected override async Task<bool> CheckBrokerPositions()
@@ -164,7 +161,7 @@ public class SpotBot : TradingBotBase
if (hasOpenPosition)
{
// We have an internal position - verify it matches broker balance
if (tokenBalance != null && tokenBalance.Amount > 0)
if (tokenBalance is { Amount: > 0 })
{
await LogDebugAsync(
$"✅ Spot Position Verified\n" +
@@ -174,17 +171,16 @@ public class SpotBot : TradingBotBase
$"Position matches broker balance");
return false; // Position already open, cannot open new one
}
else
{
await LogWarningAsync(
$"⚠️ Position Mismatch\n" +
$"Ticker: {Config.Ticker}\n" +
$"Internal position exists but no token balance found\n" +
$"Position may need synchronization");
return false; // Don't allow opening new position until resolved
}
await LogWarningAsync(
$"⚠️ Position Mismatch\n" +
$"Ticker: {Config.Ticker}\n" +
$"Internal position exists but no token balance found\n" +
$"Position may need synchronization");
return false; // Don't allow opening new position until resolved
}
else if (tokenBalance != null && tokenBalance.Value > 1m)
if (tokenBalance is { Value: > 1m })
{
// We have a token balance but no internal position - orphaned position
await LogWarningAsync(
@@ -212,7 +208,7 @@ public class SpotBot : TradingBotBase
if (Config.TradingType == TradingType.BacktestSpot) return;
await ServiceScopeHelpers.WithScopedService<IAccountService>(_scopeFactory, async accountService =>
{
var account = await accountService.GetAccountByAccountName(Config.AccountName, false, false);
var account = await accountService.GetAccountByAccountName(Config.AccountName, false);
Account = account;
});
}
@@ -227,7 +223,7 @@ public class SpotBot : TradingBotBase
_scopeFactory,
async exchangeService => await exchangeService.GetBalance(Account, Config.Ticker));
if (tokenBalance != null && tokenBalance.Amount > 0)
if (tokenBalance is { Amount: > 0 })
{
// Verify that the token balance matches the position amount with 0.1% tolerance
var positionQuantity = internalPosition.Open.Quantity;
@@ -281,7 +277,7 @@ public class SpotBot : TradingBotBase
// Calculate and update PnL based on current price
var currentPrice = await ServiceScopeHelpers.WithScopedService<IExchangeService, decimal>(
_scopeFactory,
async exchangeService => { return await exchangeService.GetCurrentPrice(Account, Config.Ticker); });
async exchangeService => await exchangeService.GetCurrentPrice(Account, Config.Ticker));
if (currentPrice > 0)
{
@@ -353,17 +349,16 @@ public class SpotBot : TradingBotBase
await LogDebugAsync(
$"🔍 Checking Spot Position History for Position: `{position.Identifier}`\nTicker: `{Config.Ticker}`");
List<Position> positionHistory = null;
await ServiceScopeHelpers.WithScopedService<IExchangeService>(_scopeFactory,
var positionHistory = await ServiceScopeHelpers.WithScopedService<IExchangeService, List<Position>>(
_scopeFactory,
async exchangeService =>
{
var fromDate = DateTime.UtcNow.AddHours(-24);
var toDate = DateTime.UtcNow;
positionHistory =
await exchangeService.GetSpotPositionHistory(Account, Config.Ticker, fromDate, toDate);
return await exchangeService.GetSpotPositionHistory(Account, Config.Ticker, fromDate, toDate);
});
if (positionHistory != null && positionHistory.Any())
if (positionHistory != null && positionHistory.Count != 0)
{
var recentPosition = positionHistory
.OrderByDescending(p => p.Date)
@@ -415,28 +410,28 @@ public class SpotBot : TradingBotBase
}
}
protected override async Task MonitorSynthRisk(LightSignal signal, Position position)
protected override Task MonitorSynthRisk(LightSignal signal, Position position)
{
// Spot trading doesn't use Synth risk monitoring (futures-specific feature)
return;
return Task.CompletedTask;
}
protected override async Task<bool> RecoverOpenPositionFromBroker(LightSignal signal, Position positionForSignal)
protected override Task<bool> RecoverOpenPositionFromBroker(LightSignal signal, Position positionForSignal)
{
// Spot trading doesn't have broker positions to recover
// Positions are token balances, not tracked positions
return false;
return Task.FromResult(false);
}
protected override async Task<bool> ReconcileWithBrokerHistory(Position position, Candle currentCandle)
protected override Task<bool> ReconcileWithBrokerHistory(Position position, Candle currentCandle)
{
// Spot trading doesn't have broker position history like futures
// Return false to continue with candle-based calculation
return false;
return Task.FromResult(false);
}
protected override async Task<(decimal closingPrice, bool pnlCalculated)> CalculatePositionClosingFromCandles(
Position position, Candle currentCandle, bool forceMarketClose, decimal? forcedClosingPrice)
protected override Task<(decimal closingPrice, bool pnlCalculated)> CalculatePositionClosingFromCandles(
Position position, Candle? currentCandle, bool forceMarketClose, decimal? forcedClosingPrice)
{
decimal closingPrice = 0;
bool pnlCalculated = false;
@@ -529,7 +524,7 @@ public class SpotBot : TradingBotBase
? closingPrice > position.Open.Price
: closingPrice < position.Open.Price;
if (isManualCloseProfitable)
if (isManualCloseProfitable && position.TakeProfit1 != null)
{
position.TakeProfit1.SetPrice(closingPrice, 2);
position.TakeProfit1.SetDate(currentCandle.Date);
@@ -542,9 +537,9 @@ public class SpotBot : TradingBotBase
}
else
{
position.StopLoss.SetPrice(closingPrice, 2);
position.StopLoss.SetDate(currentCandle.Date);
position.StopLoss.SetStatus(TradeStatus.Filled);
position.StopLoss?.SetPrice(closingPrice, 2);
position.StopLoss?.SetDate(currentCandle.Date);
position.StopLoss?.SetStatus(TradeStatus.Filled);
if (position.TakeProfit1 != null)
{
@@ -561,11 +556,11 @@ public class SpotBot : TradingBotBase
pnlCalculated = true;
}
return (closingPrice, pnlCalculated);
return Task.FromResult((closingPrice, pnlCalculated));
}
protected override async Task UpdateSignalsCore(IReadOnlyList<Candle> candles,
Dictionary<IndicatorType, IndicatorsResultBase> preCalculatedIndicatorValues = null)
Dictionary<IndicatorType, IndicatorsResultBase>? preCalculatedIndicatorValues = null)
{
// For spot trading, always fetch signals regardless of open positions
// Check if we're in cooldown period
@@ -625,7 +620,7 @@ public class SpotBot : TradingBotBase
return !await IsInCooldownPeriodAsync() && await CheckLossStreak(signal);
}
protected override async Task<Position> HandleFlipPosition(LightSignal signal, Position openedPosition,
protected override async Task<Position?> HandleFlipPosition(LightSignal signal, Position openedPosition,
LightSignal previousSignal, decimal lastPrice)
{
// For spot trading, SHORT signals should close the open LONG position
@@ -694,10 +689,8 @@ public class SpotBot : TradingBotBase
.WithScopedServices<IExchangeService, IAccountService, ITradingService, Position>(
_scopeFactory,
async (exchangeService, accountService, tradingService) =>
{
return await new OpenSpotPositionCommandHandler(exchangeService, accountService, tradingService)
.Handle(command);
});
await new OpenSpotPositionCommandHandler(exchangeService, accountService, tradingService)
.Handle(command));
return position;
}
@@ -725,7 +718,7 @@ public class SpotBot : TradingBotBase
await SetPositionStatus(signal.Identifier, PositionStatus.Finished);
}
await HandleClosedPosition(closedPosition, forceMarketClose ? lastPrice : (decimal?)null,
await HandleClosedPosition(closedPosition, forceMarketClose ? lastPrice : null,
forceMarketClose);
}
else
@@ -742,7 +735,7 @@ public class SpotBot : TradingBotBase
// Trade close on exchange => Should close trade manually
await SetPositionStatus(signal.Identifier, PositionStatus.Finished);
// Ensure trade dates are properly updated even for canceled/rejected positions
await HandleClosedPosition(position, forceMarketClose ? lastPrice : (decimal?)null,
await HandleClosedPosition(position, forceMarketClose ? lastPrice : null,
forceMarketClose);
}
}