using System; using System.Threading; using System.Threading.Tasks; using FinlyticAnalyzer.Util; using FinlyticCore.Models.Analyzer; using FinlyticCore.Services; using FinlyticCore.Services.Yahoo; namespace FinlyticAnalyzer.Services; public class VixTrackerService : IVixTrackerService { private readonly YahooFinanceClient _yahooClient; private readonly IFinlyticLogger _finlyticLogger; private decimal _currentVix = 18.5m; private VixMarketRegime _currentRegime = VixMarketRegime.Normal; private readonly object _lock = new(); public VixTrackerService(YahooFinanceClient yahooClient, IFinlyticLogger finlyticLogger) { _yahooClient = yahooClient; _finlyticLogger = finlyticLogger; } public decimal GetCurrentVix() { lock (_lock) { return _currentVix; } } public VixMarketRegime GetCurrentRegime() { lock (_lock) { return _currentRegime; } } public void UpdateVixFromTick(decimal vixValue) { if (vixValue <= 0m) return; lock (_lock) { var oldRegime = _currentRegime; var oldVix = _currentVix; _currentVix = vixValue; _currentRegime = CalculateRegime(vixValue); if (oldRegime != _currentRegime) { _ = _finlyticLogger.LogWarningAsync(SettingKeys.AnalyzerChannel, "[VixTrackerService] [VIX REGIME SHIFT] Markt-Regime gewechselt: {OldRegime} -> {NewRegime} (VIX: {Vix:F2})", oldRegime, _currentRegime, _currentVix); } else if (Math.Abs(oldVix - vixValue) >= 0.5m) { _ = _finlyticLogger.LogInfoAsync(SettingKeys.AnalyzerChannel, "[VixTrackerService] VIX aktualisiert: {Vix:F2} (Regime: {Regime})", _currentVix, _currentRegime); } } } public async Task PollVixAsync(CancellationToken cancellationToken = default) { try { var vix = await _yahooClient.GetLivePriceAsync("^VIX", cancellationToken); if (vix.HasValue && vix.Value > 0m) { UpdateVixFromTick(vix.Value); return vix.Value; } } catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) { } catch (Exception ex) { await _finlyticLogger.LogWarningAsync(SettingKeys.AnalyzerChannel, ex, "[VixTrackerService] Fehler beim Abfragen von ^VIX über YahooFinanceClient. Nutze gecachten Wert {Vix}.", GetCurrentVix()); } return GetCurrentVix(); } private static VixMarketRegime CalculateRegime(decimal vix) { return vix switch { < 15.0m => VixMarketRegime.LowVol, >= 15.0m and < 20.0m => VixMarketRegime.Normal, >= 20.0m and < 30.0m => VixMarketRegime.HighVol, _ => VixMarketRegime.Panic }; } }