using System; using System.Collections.Generic; using DesktopBot.Models; namespace DesktopBot.Engine { /// /// Motore di raccomandazione strategia. /// Per ogni combinazione asset-class / volatilità / tipologia di mercato restituisce /// la strategia ottimale e i parametri pre-calibrati. /// /// Logica ispirata agli approcci professionali: /// Crypto → alta volatilità 24/7 → VOLATILITY_BREAKOUT /// Equity → orario di mercato → EMA_CROSSOVER o MACD /// ETF → bassa volatilità → KALMAN_MEAN_REVERSION /// FX/FX-alike → mean-reverting → RSI /// public static class StrategyAdvisor { // ── Profili per asset class ───────────────────────────────────────── private static readonly Dictionary _profiles = new Dictionary(StringComparer.OrdinalIgnoreCase) { // ── Crypto ────────────────────────────────────────────────────── ["crypto"] = new[] { new StrategyProfile( TradingStrategy.VOLATILITY_BREAKOUT, "Volatility Breakout (1min)", "Strategia ad alta frequenza per crypto: breakout su barre da 1 minuto con filtro RVOL e CVD.", "🚀", "#FF6D00", isRecommended: true, cfg => { cfg.KeltnerPeriod = 20; cfg.KeltnerMultiplier = 2.0m; cfg.RvolMinThreshold = 2.5m; // Soglia RVOL più alta per crypto ad alta volatilità cfg.AtrStopMultiplier = 1.0m; cfg.CheckIntervalSeconds = 60; // Tick ogni 60 secondi cfg.AnalysisTimeFrame = Alpaca.Markets.BarTimeFrame.Minute; // Barre da 1 minuto cfg.HistoricalBarCount = 200; // 200 barre = 3.3 ore di storico cfg.StopLossPercentage = 0.03m; // 3% SL per volatilità crypto cfg.TakeProfitPercentage = 0.06m; // 6% TP, ratio 1:2 }), new StrategyProfile( TradingStrategy.KALMAN_MEAN_REVERSION, "Kalman Mean Reversion (1min)", "Mean-reversion adattiva su crypto range-bound con analisi a 1 minuto.", "🔬", "#40C4FF", isRecommended: false, cfg => { cfg.KalmanDelta = 1e-5; cfg.KalmanObservationVariance = 1.0; cfg.KalmanEntryZScore = 2.0; cfg.KalmanExitZScore = 0.25; cfg.CheckIntervalSeconds = 120; cfg.AnalysisTimeFrame = Alpaca.Markets.BarTimeFrame.Minute; cfg.HistoricalBarCount = 300; // 5 ore di storico cfg.StopLossPercentage = 0.03m; cfg.TakeProfitPercentage = 0.06m; }), new StrategyProfile( TradingStrategy.EMA_CROSSOVER, "EMA Crossover (1min)", "Trend-following veloce su barre da 1 minuto — ottimale per BTC/USD in trend forte.", "⚡", "#00E676", isRecommended: false, cfg => { cfg.FastEmaPeriod = 5; // EMA veloce 5 periodi (5 minuti) cfg.SlowEmaPeriod = 15; // EMA lenta 15 periodi (15 minuti) cfg.CheckIntervalSeconds = 60; // Tick ogni 60 secondi cfg.AnalysisTimeFrame = Alpaca.Markets.BarTimeFrame.Minute; cfg.HistoricalBarCount = 150; // 2.5 ore di storico cfg.StopLossPercentage = 0.025m; // 2.5% SL cfg.TakeProfitPercentage = 0.05m; // 5% TP }), }, // ── US Equity ──────────────────────────────────────────────────── ["us_equity"] = new[] { new StrategyProfile( TradingStrategy.EMA_CROSSOVER, "EMA Crossover", "Strategia trend-following classica, ottimale su azioni con trend chiari.", "📈", "#00E676", isRecommended: true, cfg => { cfg.FastEmaPeriod = 9; cfg.SlowEmaPeriod = 21; cfg.CheckIntervalSeconds = 60; cfg.StopLossPercentage = 0.02m; cfg.TakeProfitPercentage = 0.04m; }), new StrategyProfile( TradingStrategy.MACD, "MACD", "Momentum con istogramma MACD — eccellente su mid/large cap con trend.", "⚡", "#EA80FC", isRecommended: false, cfg => { cfg.MacdFastPeriod = 12; cfg.MacdSlowPeriod = 26; cfg.MacdSignalPeriod = 9; cfg.CheckIntervalSeconds = 60; cfg.StopLossPercentage = 0.02m; cfg.TakeProfitPercentage = 0.04m; }), new StrategyProfile( TradingStrategy.RSI, "RSI Reversal", "Ottimale per azioni in range o in correzione — compra ipervenduto.", "📊", "#FFFF00", isRecommended: false, cfg => { cfg.RsiPeriod = 14; cfg.RsiOversoldThreshold = 30m; cfg.RsiOverboughtThreshold = 70m; cfg.CheckIntervalSeconds = 120; cfg.StopLossPercentage = 0.02m; cfg.TakeProfitPercentage = 0.035m; }), }, // ── ETF (mappato come us_equity con parametri diversi) ─────────── ["etf"] = new[] { new StrategyProfile( TradingStrategy.KALMAN_MEAN_REVERSION, "Kalman Mean Reversion", "ETF tendono a mean-revert: il filtro Kalman ne stima il fair value.", "🔬", "#40C4FF", isRecommended: true, cfg => { cfg.KalmanDelta = 1e-5; cfg.KalmanObservationVariance = 0.8; cfg.KalmanEntryZScore = 1.8; cfg.KalmanExitZScore = 0.2; cfg.CheckIntervalSeconds = 300; cfg.StopLossPercentage = 0.015m; cfg.TakeProfitPercentage = 0.03m; }), new StrategyProfile( TradingStrategy.EMA_CROSSOVER, "EMA Crossover", "Trend-following conservativo su ETF ad alta liquidità.", "📈", "#00E676", isRecommended: false, cfg => { cfg.FastEmaPeriod = 12; cfg.SlowEmaPeriod = 26; cfg.CheckIntervalSeconds = 120; cfg.StopLossPercentage = 0.015m; cfg.TakeProfitPercentage = 0.03m; }), }, }; // ── Fallback: usa equity ───────────────────────────────────────────── private static StrategyProfile[] GetProfiles(string assetClass) { if (string.IsNullOrEmpty(assetClass)) return _profiles["us_equity"]; var key = NormalizeClass(assetClass); return _profiles.TryGetValue(key, out var p) ? p : _profiles["us_equity"]; } /// Restituisce tutti i profili strategia disponibili per la classe dell'asset. public static StrategyProfile[] GetAvailableProfiles(string assetClass) => GetProfiles(assetClass); /// Restituisce il profilo raccomandato (primo marcato IsRecommended). public static StrategyProfile GetRecommended(string assetClass) { var profiles = GetProfiles(assetClass); foreach (var p in profiles) if (p.IsRecommended) return p; return profiles[0]; } /// /// Applica i parametri ottimali del profilo raccomandato alla configurazione. /// Mantiene Symbol, Quantity e Name invariati. /// public static void ApplyOptimalConfig(BotConfiguration cfg, string assetClass) { var profile = GetRecommended(assetClass); cfg.Strategy = profile.Strategy; profile.ApplyParameters(cfg); } private static string NormalizeClass(string assetClass) { // Alpaca restituisce "us_equity", "crypto", ecc. var lower = assetClass.ToLowerInvariant().Replace("-", "_"); if (lower.Contains("crypto")) return "crypto"; if (lower.Contains("etf")) return "etf"; return lower; } } // ── StrategyProfile ────────────────────────────────────────────────────── /// Descrive una strategia disponibile per una classe di asset, con i parametri pre-calibrati. public sealed class StrategyProfile { public TradingStrategy Strategy { get; } public string DisplayName { get; } public string Description { get; } public string Icon { get; } public string AccentColor { get; } public bool IsRecommended { get; } private readonly Action _applyParameters; public StrategyProfile( TradingStrategy strategy, string displayName, string description, string icon, string accentColor, bool isRecommended, Action applyParameters) { Strategy = strategy; DisplayName = displayName; Description = description; Icon = icon; AccentColor = accentColor; IsRecommended = isRecommended; _applyParameters = applyParameters; } public void ApplyParameters(BotConfiguration cfg) => _applyParameters(cfg); } }