119 lines
5.0 KiB
C#
119 lines
5.0 KiB
C#
using System;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using FinlyticCore.Services;
|
|
using FinlyticTechnicals.Util;
|
|
using Microsoft.Extensions.Hosting;
|
|
|
|
namespace FinlyticTechnicals.Services;
|
|
|
|
public class TechnicalScannerBackgroundService : BackgroundService
|
|
{
|
|
private readonly ITechnicalUniverseManager _universeManager;
|
|
private readonly ITechnicalScoringEngine _scoringEngine;
|
|
private readonly ISettingsService _settingsService;
|
|
private readonly IFinlyticLogger<TechnicalScannerBackgroundService> _logger;
|
|
|
|
public TechnicalScannerBackgroundService(
|
|
ITechnicalUniverseManager universeManager,
|
|
ITechnicalScoringEngine scoringEngine,
|
|
ISettingsService settingsService,
|
|
IFinlyticLogger<TechnicalScannerBackgroundService> logger)
|
|
{
|
|
_universeManager = universeManager;
|
|
_scoringEngine = scoringEngine;
|
|
_settingsService = settingsService;
|
|
_logger = logger;
|
|
}
|
|
|
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
{
|
|
await _logger.LogInfoAsync(SettingKeys.TechnicalAnalysisChannel,
|
|
"[TechnicalScanner] Starting Technical Universe Scanner Background Service...");
|
|
|
|
// Initial delay for MQTT connections to stabilize
|
|
await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
|
|
|
|
// Initial synchronization of Universe
|
|
await _universeManager.RefreshFavoritesAsync(stoppingToken);
|
|
await _universeManager.RefreshDiscoveryAsync(stoppingToken);
|
|
|
|
DateTime lastFavoritesSyncUtc = DateTime.UtcNow;
|
|
DateTime lastDiscoverySyncUtc = DateTime.UtcNow;
|
|
|
|
while (!stoppingToken.IsCancellationRequested)
|
|
{
|
|
try
|
|
{
|
|
DateTime now = DateTime.UtcNow;
|
|
|
|
// 1. Check Periodic Sync Timers
|
|
if (now - lastFavoritesSyncUtc >= TimeSpan.FromMinutes(15))
|
|
{
|
|
await _universeManager.RefreshFavoritesAsync(stoppingToken);
|
|
lastFavoritesSyncUtc = DateTime.UtcNow;
|
|
}
|
|
|
|
if (now - lastDiscoverySyncUtc >= TimeSpan.FromMinutes(30))
|
|
{
|
|
await _universeManager.RefreshDiscoveryAsync(stoppingToken);
|
|
lastDiscoverySyncUtc = DateTime.UtcNow;
|
|
}
|
|
|
|
// 2. Retrieve Active Prioritized Scan Universe
|
|
var universe = await _universeManager.GetActiveUniverseAsync(stoppingToken);
|
|
if (universe.Count > 0)
|
|
{
|
|
await _logger.LogInfoAsync(SettingKeys.TechnicalAnalysisChannel,
|
|
"[TechnicalScanner] Scanning {Count} assets in active universe across all strategies...", universe.Count);
|
|
|
|
foreach (var entry in universe)
|
|
{
|
|
if (stoppingToken.IsCancellationRequested) break;
|
|
|
|
try
|
|
{
|
|
var setups = await _scoringEngine.AnalyzeIsinAsync(entry.Isin, entry.Symbol, entry.Source, entry.AddedAtUtc, stoppingToken);
|
|
if (setups.Count > 0)
|
|
{
|
|
await _logger.LogInfoAsync(SettingKeys.TechnicalAnalysisChannel,
|
|
"[TechnicalScanner] Found {Count} active setup(s) for ISIN {Isin} (Top Score: {Score:F1})",
|
|
setups.Count, entry.Isin, setups[0].QualityScore);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
await _logger.LogWarningAsync(SettingKeys.TechnicalAnalysisChannel, ex,
|
|
"[TechnicalScanner] Error analyzing ISIN {Isin}", entry.Isin);
|
|
}
|
|
|
|
// Gentle throttle between asset analysis runs
|
|
await Task.Delay(250, stoppingToken);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
await _logger.LogInfoAsync(SettingKeys.TechnicalAnalysisChannel,
|
|
"[TechnicalScanner] Scan universe is currently empty. Waiting for next cycle.");
|
|
}
|
|
|
|
// Wait 60 seconds before next full universe evaluation pass
|
|
await Task.Delay(TimeSpan.FromSeconds(60), stoppingToken);
|
|
}
|
|
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
|
|
{
|
|
break;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
await _logger.LogErrorAsync(SettingKeys.TechnicalAnalysisChannel, ex,
|
|
"[TechnicalScanner] Unexpected error in scanner loop. Retrying in 30 seconds.");
|
|
await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken);
|
|
}
|
|
}
|
|
|
|
await _logger.LogInfoAsync(SettingKeys.TechnicalAnalysisChannel,
|
|
"[TechnicalScanner] Technical Universe Scanner Background Service stopped.");
|
|
}
|
|
}
|