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);
}
}