using TradingBot.Models; namespace TradingBot.Services; /// /// RSI-based trading strategy /// Buy when RSI < oversold threshold, Sell when RSI > overbought threshold /// public class RSIStrategy : ITradingStrategy { public string Name => "RSI Strategy"; public string Description => "Strategia basata su Relative Strength Index. Compra in zona ipervenduto, vende in zona ipercomprato."; private readonly decimal _oversoldThreshold; private readonly decimal _overboughtThreshold; private readonly int _period; public RSIStrategy(decimal oversoldThreshold = 30, decimal overboughtThreshold = 70, int period = 14) { _oversoldThreshold = oversoldThreshold; _overboughtThreshold = overboughtThreshold; _period = period; } public Task AnalyzeAsync(string symbol, List priceHistory) { if (priceHistory == null || priceHistory.Count < _period + 1) { return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Hold, Confidence = 0, Reason = "Dati insufficienti per RSI" }); } var prices = priceHistory.Select(p => p.Price).ToList(); var rsi = TechnicalAnalysis.CalculateRSI(prices, _period); if (rsi < _oversoldThreshold) { return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Buy, Confidence = (decimal)(((_oversoldThreshold - rsi) / _oversoldThreshold) * 100), Reason = $"RSI in zona ipervenduto: {rsi:F2}" }); } else if (rsi > _overboughtThreshold) { return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Sell, Confidence = (decimal)(((rsi - _overboughtThreshold) / (100 - _overboughtThreshold)) * 100), Reason = $"RSI in zona ipercomprato: {rsi:F2}" }); } return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Hold, Confidence = 50, Reason = $"RSI neutro: {rsi:F2}" }); } } /// /// MACD-based trading strategy /// Buy on bullish crossover, Sell on bearish crossover /// public class MACDStrategy : ITradingStrategy { public string Name => "MACD Strategy"; public string Description => "Strategia basata su MACD crossover. Compra su incrocio rialzista, vende su incrocio ribassista."; public Task AnalyzeAsync(string symbol, List priceHistory) { if (priceHistory == null || priceHistory.Count < 26) { return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Hold, Confidence = 0, Reason = "Dati insufficienti per MACD" }); } var prices = priceHistory.Select(p => p.Price).ToList(); var (macd, signal, histogram) = TechnicalAnalysis.CalculateMACD(prices); if (histogram > 0 && Math.Abs(histogram) > 0.1m) { var confidence = Math.Min((decimal)(Math.Abs((double)histogram) * 10), 100); return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Buy, Confidence = confidence, Reason = $"MACD crossover rialzista, histogram: {histogram:F2}" }); } else if (histogram < 0 && Math.Abs(histogram) > 0.1m) { var confidence = Math.Min((decimal)(Math.Abs((double)histogram) * 10), 100); return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Sell, Confidence = confidence, Reason = $"MACD crossover ribassista, histogram: {histogram:F2}" }); } return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Hold, Confidence = 30, Reason = "MACD vicino a equilibrio" }); } } /// /// Bollinger Bands strategy /// Buy when price touches lower band, Sell when price touches upper band /// public class BollingerBandsStrategy : ITradingStrategy { public string Name => "Bollinger Bands"; public string Description => "Compra quando il prezzo tocca la banda inferiore, vende alla banda superiore."; private readonly int _period; private readonly decimal _standardDeviations; public BollingerBandsStrategy(int period = 20, decimal standardDeviations = 2) { _period = period; _standardDeviations = standardDeviations; } public Task AnalyzeAsync(string symbol, List priceHistory) { if (priceHistory == null || priceHistory.Count < _period) { return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Hold, Confidence = 0, Reason = "Dati insufficienti per Bollinger Bands" }); } var prices = priceHistory.Select(p => p.Price).ToList(); var (upper, middle, lower) = TechnicalAnalysis.CalculateBollingerBands(prices, _period, _standardDeviations); var currentPrice = prices.Last(); var distanceToLower = ((currentPrice - lower) / lower) * 100; var distanceToUpper = ((upper - currentPrice) / upper) * 100; if (distanceToLower < 2) // Within 2% of lower band { return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Buy, Confidence = 80, Reason = $"Prezzo vicino banda inferiore: ${currentPrice:F2} vs ${lower:F2}" }); } else if (distanceToUpper < 2) // Within 2% of upper band { return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Sell, Confidence = 80, Reason = $"Prezzo vicino banda superiore: ${currentPrice:F2} vs ${upper:F2}" }); } return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Hold, Confidence = 40, Reason = "Prezzo tra le bande" }); } } /// /// Mean Reversion strategy /// Assumes price will return to average /// public class MeanReversionStrategy : ITradingStrategy { public string Name => "Mean Reversion"; public string Description => "Sfrutta il ritorno del prezzo verso la media. Compra sotto media, vende sopra media."; private readonly int _period; private readonly decimal _deviationThreshold; public MeanReversionStrategy(int period = 20, decimal deviationThreshold = 5) { _period = period; _deviationThreshold = deviationThreshold; } public Task AnalyzeAsync(string symbol, List priceHistory) { if (priceHistory == null || priceHistory.Count < _period) { return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Hold, Confidence = 0, Reason = "Dati insufficienti" }); } var prices = priceHistory.Select(p => p.Price).TakeLast(_period).ToList(); var mean = prices.Average(); var currentPrice = prices.Last(); var deviation = ((currentPrice - mean) / mean) * 100; if (deviation < -_deviationThreshold) { return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Buy, Confidence = Math.Min((decimal)Math.Abs((double)deviation) * 10, 100), Reason = $"Prezzo {deviation:F2}% sotto media, probabile rimbalzo" }); } else if (deviation > _deviationThreshold) { return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Sell, Confidence = Math.Min((decimal)Math.Abs((double)deviation) * 10, 100), Reason = $"Prezzo {deviation:F2}% sopra media, probabile correzione" }); } return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Hold, Confidence = 50, Reason = "Prezzo vicino alla media" }); } } /// /// Momentum strategy /// Follows strong trends /// public class MomentumStrategy : ITradingStrategy { public string Name => "Momentum"; public string Description => "Segue i trend forti. Compra su momentum positivo, vende su momentum negativo."; private readonly int _period; public MomentumStrategy(int period = 10) { _period = period; } public Task AnalyzeAsync(string symbol, List priceHistory) { if (priceHistory == null || priceHistory.Count < _period + 5) { return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Hold, Confidence = 0, Reason = "Dati insufficienti" }); } var prices = priceHistory.Select(p => p.Price).ToList(); var currentPrice = prices.Last(); var pastPrice = prices[^_period]; var momentum = ((currentPrice - pastPrice) / pastPrice) * 100; // Calculate rate of change var recentPrices = prices.TakeLast(5).ToList(); var priceChanges = new List(); for (int i = 1; i < recentPrices.Count; i++) { priceChanges.Add(((recentPrices[i] - recentPrices[i - 1]) / recentPrices[i - 1]) * 100); } var avgChange = priceChanges.Average(); if (momentum > 3 && avgChange > 0) { return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Buy, Confidence = Math.Min((decimal)Math.Abs((double)momentum) * 15, 100), Reason = $"Forte momentum positivo: {momentum:F2}%" }); } else if (momentum < -3 && avgChange < 0) { return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Sell, Confidence = Math.Min((decimal)Math.Abs((double)momentum) * 15, 100), Reason = $"Forte momentum negativo: {momentum:F2}%" }); } return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Hold, Confidence = 30, Reason = "Momentum debole o neutro" }); } } /// /// EMA Crossover strategy (Golden Cross / Death Cross) /// Buy when fast EMA crosses above slow EMA, Sell on opposite /// public class EMACrossoverStrategy : ITradingStrategy { public string Name => "EMA Crossover"; public string Description => "Golden Cross/Death Cross. Compra quando EMA veloce supera EMA lenta."; private readonly int _fastPeriod; private readonly int _slowPeriod; public EMACrossoverStrategy(int fastPeriod = 12, int slowPeriod = 26) { _fastPeriod = fastPeriod; _slowPeriod = slowPeriod; } public Task AnalyzeAsync(string symbol, List priceHistory) { if (priceHistory == null || priceHistory.Count < _slowPeriod + 5) { return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Hold, Confidence = 0, Reason = "Dati insufficienti" }); } var prices = priceHistory.Select(p => p.Price).ToList(); var fastEMA = TechnicalAnalysis.CalculateEMA(prices, _fastPeriod); var slowEMA = TechnicalAnalysis.CalculateEMA(prices, _slowPeriod); // Calculate previous EMAs to detect crossover var prevPrices = prices.Take(prices.Count - 1).ToList(); var prevFastEMA = TechnicalAnalysis.CalculateEMA(prevPrices, _fastPeriod); var prevSlowEMA = TechnicalAnalysis.CalculateEMA(prevPrices, _slowPeriod); var currentDiff = fastEMA - slowEMA; var prevDiff = prevFastEMA - prevSlowEMA; // Golden Cross (bullish) if (currentDiff > 0 && prevDiff <= 0) { return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Buy, Confidence = 85, Reason = $"Golden Cross! EMA{_fastPeriod} crossed above EMA{_slowPeriod}" }); } // Death Cross (bearish) else if (currentDiff < 0 && prevDiff >= 0) { return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Sell, Confidence = 85, Reason = $"Death Cross! EMA{_fastPeriod} crossed below EMA{_slowPeriod}" }); } // Trend continuation else if (currentDiff > 0) { return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Hold, Confidence = 60, Reason = "EMA fast sopra slow - trend rialzista confermato" }); } else { return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Hold, Confidence = 40, Reason = "EMA fast sotto slow - trend ribassista confermato" }); } } } /// /// Scalping strategy for short-term gains /// public class ScalpingStrategy : ITradingStrategy { public string Name => "Scalping"; public string Description => "Strategia per guadagni rapidi a breve termine. Alta frequenza, piccoli profitti."; public Task AnalyzeAsync(string symbol, List priceHistory) { if (priceHistory == null || priceHistory.Count < 10) { return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Hold, Confidence = 0, Reason = "Dati insufficienti" }); } var recentPrices = priceHistory.Select(p => p.Price).TakeLast(10).ToList(); var currentPrice = recentPrices.Last(); var shortMA = recentPrices.TakeLast(3).Average(); var mediumMA = recentPrices.TakeLast(7).Average(); // Calculate short-term volatility var priceChanges = new List(); for (int i = 1; i < recentPrices.Count; i++) { priceChanges.Add(Math.Abs(recentPrices[i] - recentPrices[i - 1])); } var avgVolatility = priceChanges.Average(); var recentChange = Math.Abs(currentPrice - recentPrices[^2]); // Quick reversal detection if (currentPrice < shortMA && shortMA < mediumMA && recentChange > avgVolatility * 1.5m) { return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Buy, Confidence = 70, Reason = "Possibile rimbalzo rapido" }); } else if (currentPrice > shortMA && shortMA > mediumMA && recentChange > avgVolatility * 1.5m) { return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Sell, Confidence = 70, Reason = "Possibile correzione rapida" }); } return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Hold, Confidence = 30, Reason = "Attesa opportunitą scalping" }); } } /// /// Breakout strategy /// Trades on price breaking resistance/support levels /// public class BreakoutStrategy : ITradingStrategy { public string Name => "Breakout"; public string Description => "Compra su rottura resistenza, vende su rottura supporto. Cattura breakout significativi."; private readonly int _lookbackPeriod; public BreakoutStrategy(int lookbackPeriod = 20) { _lookbackPeriod = lookbackPeriod; } public Task AnalyzeAsync(string symbol, List priceHistory) { if (priceHistory == null || priceHistory.Count < _lookbackPeriod) { return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Hold, Confidence = 0, Reason = "Dati insufficienti" }); } var prices = priceHistory.Select(p => p.Price).ToList(); var recentPrices = prices.TakeLast(_lookbackPeriod).ToList(); var currentPrice = prices.Last(); var resistance = recentPrices.Max(); var support = recentPrices.Min(); var range = resistance - support; // Breakout above resistance if (currentPrice > resistance * 1.01m) // 1% above previous high { return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Buy, Confidence = 80, Reason = $"Breakout sopra resistenza: ${resistance:F2}" }); } // Breakdown below support else if (currentPrice < support * 0.99m) // 1% below previous low { return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Sell, Confidence = 80, Reason = $"Breakdown sotto supporto: ${support:F2}" }); } return Task.FromResult(new TradingSignal { Symbol = symbol, Type = SignalType.Hold, Confidence = 40, Reason = $"Prezzo in range ${support:F2} - ${resistance:F2}" }); } }