Fix WinRate 0% bug: Optimize TradeReconciliationWorker with bulk SQL and reset Trader analytics flag
This commit is contained in:
@@ -16,7 +16,7 @@ public class TradeReconciliationWorker : BackgroundService
|
|||||||
private readonly ILogger<TradeReconciliationWorker> _logger;
|
private readonly ILogger<TradeReconciliationWorker> _logger;
|
||||||
|
|
||||||
private const int BatchSize = 250;
|
private const int BatchSize = 250;
|
||||||
private const int IntervalMinutes = 15;
|
private const int IntervalSeconds = 30;
|
||||||
|
|
||||||
public TradeReconciliationWorker(IServiceProvider services, ILogger<TradeReconciliationWorker> logger)
|
public TradeReconciliationWorker(IServiceProvider services, ILogger<TradeReconciliationWorker> logger)
|
||||||
{
|
{
|
||||||
@@ -26,7 +26,7 @@ public class TradeReconciliationWorker : BackgroundService
|
|||||||
|
|
||||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("🛠️ TradeReconciliationWorker started (batch: {Batch}, interval: {Min}m)", BatchSize, IntervalMinutes);
|
_logger.LogInformation("🛠️ TradeReconciliationWorker started (batch: {Batch}, interval: {Sec}s)", BatchSize, IntervalSeconds);
|
||||||
|
|
||||||
// Initial delay to let other workers settle
|
// Initial delay to let other workers settle
|
||||||
await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken);
|
await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken);
|
||||||
@@ -52,7 +52,7 @@ public class TradeReconciliationWorker : BackgroundService
|
|||||||
_logger.LogError(ex, "Error in TradeReconciliationWorker cycle");
|
_logger.LogError(ex, "Error in TradeReconciliationWorker cycle");
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.Delay(TimeSpan.FromMinutes(IntervalMinutes), stoppingToken);
|
await Task.Delay(TimeSpan.FromSeconds(IntervalSeconds), stoppingToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogInformation("🛠️ TradeReconciliationWorker stopped");
|
_logger.LogInformation("🛠️ TradeReconciliationWorker stopped");
|
||||||
@@ -61,37 +61,44 @@ public class TradeReconciliationWorker : BackgroundService
|
|||||||
private async Task<int> ReconcileBatchAsync(CancellationToken ct)
|
private async Task<int> ReconcileBatchAsync(CancellationToken ct)
|
||||||
{
|
{
|
||||||
using var scope = _services.CreateScope();
|
using var scope = _services.CreateScope();
|
||||||
var tradeRepo = scope.ServiceProvider.GetRequiredService<ITradeRepository>();
|
var db = scope.ServiceProvider.GetRequiredService<Predictalytics.Infrastructure.Data.AppDbContext>();
|
||||||
var marketRepo = scope.ServiceProvider.GetRequiredService<IMarketRepository>();
|
|
||||||
|
|
||||||
var orphanedTrades = await tradeRepo.GetOrphanedTradesAsync(BatchSize, ct);
|
|
||||||
if (orphanedTrades.Count == 0) return 0;
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
foreach (var trade in orphanedTrades)
|
|
||||||
{
|
|
||||||
if (ct.IsCancellationRequested) break;
|
|
||||||
|
|
||||||
|
// Bulk update orphaned trades
|
||||||
|
int reconciledCount = 0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var outcome = await marketRepo.GetOutcomeByTokenIdAsync(trade.AssetId, ct);
|
reconciledCount = await Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.ExecuteSqlRawAsync(db.Database, @"
|
||||||
if (outcome != null)
|
UPDATE Trades t
|
||||||
{
|
INNER JOIN MarketOutcomes o ON t.AssetId = o.TokenId
|
||||||
trade.MarketOutcomeId = outcome.Id;
|
INNER JOIN Markets m ON o.MarketId = m.Id
|
||||||
trade.Outcome = outcome.Label;
|
SET t.MarketOutcomeId = o.Id,
|
||||||
if (outcome.Market != null)
|
t.Outcome = o.Label,
|
||||||
trade.DbMarketId = outcome.Market.Id;
|
t.DbMarketId = m.Id
|
||||||
|
WHERE t.MarketOutcomeId IS NULL AND t.AssetId != '';
|
||||||
|
", ct);
|
||||||
|
|
||||||
await tradeRepo.UpdateAsync(trade, ct);
|
if (reconciledCount > 0)
|
||||||
count++;
|
{
|
||||||
|
// Force re-analysis of traders who now have new linked trades that haven't been applied
|
||||||
|
await Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.ExecuteSqlRawAsync(db.Database, @"
|
||||||
|
UPDATE Traders t
|
||||||
|
SET LastAnalyzedAt = NULL
|
||||||
|
WHERE LastAnalyzedAt IS NOT NULL
|
||||||
|
AND EXISTS (
|
||||||
|
SELECT 1 FROM Trades tr
|
||||||
|
LEFT JOIN TraderPositions tp ON tr.TraderId = tp.TraderId AND tr.MarketOutcomeId = tp.MarketOutcomeId
|
||||||
|
WHERE tr.TraderId = t.Id
|
||||||
|
AND tr.MarketOutcomeId IS NOT NULL
|
||||||
|
AND (tp.Id IS NULL OR tr.Id > tp.LastAppliedTradeId)
|
||||||
|
);
|
||||||
|
", ct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Failed to reconcile trade {TradeId}: {Msg}", trade.Id, ex.Message);
|
_logger.LogError(ex, "Error executing bulk reconciliation SQL");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return reconciledCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user