Files
Encelado/TradingBot/Services/SimpleMovingAverageStrategy.cs
Alberto Balbo 5532ad2473 Supporto Unraid/Docker nativo, healthcheck e template
- Configurazione Kestrel ottimizzata per ambienti Docker/Unraid: porta 8080 in produzione, HTTPS redirect solo in sviluppo
- Endpoint /health sempre attivo per healthcheck automatici
- Aggiunti file docker-compose.yml e unraid-template.xml per deploy e gestione nativa su Unraid (senza Portainer)
- Nuova guida UNRAID_NATIVE_INSTALL.md per installazione, update e troubleshooting su Unraid
- Logging e appsettings separati per Development/Production
- launchSettings.json aggiornato e semplificato
- Rimosso package Azure Containers Tools dal csproj; aggiunto target MSBuild per push automatico su Gitea Registry dopo publish
- Algoritmo SMA più robusto: filtra dati nulli/invalidi e gestisce casi di dati insufficienti
- Pronto per deploy professionale, aggiornamento e gestione semplificata in ambienti containerizzati
2025-12-17 14:34:52 +01:00

88 lines
3.0 KiB
C#

using TradingBot.Models;
namespace TradingBot.Services;
public class SimpleMovingAverageStrategy : ITradingStrategy
{
private readonly int _shortPeriod = 5;
private readonly int _longPeriod = 10;
public string Name => "Simple Moving Average (SMA)";
public Task<TradingSignal> AnalyzeAsync(string symbol, List<MarketPrice> historicalPrices)
{
// Filtra null e valori invalidi prima di usare la lista
if (historicalPrices == null || historicalPrices.Count < _longPeriod)
{
return Task.FromResult(new TradingSignal
{
Symbol = symbol,
Type = SignalType.Hold,
Price = historicalPrices?.LastOrDefault()?.Price ?? 0,
Reason = "Dati insufficienti per l'analisi",
Timestamp = DateTime.UtcNow
});
}
// Filtra oggetti null e ordina
var recentPrices = historicalPrices
.Where(p => p != null && p.Price > 0)
.OrderByDescending(p => p.Timestamp)
.Take(_longPeriod)
.ToList();
// Verifica ancora la count dopo il filtro
if (recentPrices.Count < _longPeriod)
{
return Task.FromResult(new TradingSignal
{
Symbol = symbol,
Type = SignalType.Hold,
Price = recentPrices.LastOrDefault()?.Price ?? 0,
Reason = "Dati insufficienti per l'analisi dopo il filtro",
Timestamp = DateTime.UtcNow
});
}
var shortSMA = recentPrices.Take(_shortPeriod).Average(p => p.Price);
var longSMA = recentPrices.Average(p => p.Price);
var currentPrice = recentPrices.First().Price;
// Strategia: Compra quando la SMA breve incrocia sopra la SMA lunga
// Vendi quando la SMA breve incrocia sotto la SMA lunga
if (shortSMA > longSMA * 1.02m) // 2% sopra
{
return Task.FromResult(new TradingSignal
{
Symbol = symbol,
Type = SignalType.Buy,
Price = currentPrice,
Reason = $"SMA breve ({shortSMA:F2}) > SMA lunga ({longSMA:F2}) - Trend rialzista",
Timestamp = DateTime.UtcNow
});
}
else if (shortSMA < longSMA * 0.98m) // 2% sotto
{
return Task.FromResult(new TradingSignal
{
Symbol = symbol,
Type = SignalType.Sell,
Price = currentPrice,
Reason = $"SMA breve ({shortSMA:F2}) < SMA lunga ({longSMA:F2}) - Trend ribassista",
Timestamp = DateTime.UtcNow
});
}
else
{
return Task.FromResult(new TradingSignal
{
Symbol = symbol,
Type = SignalType.Hold,
Price = currentPrice,
Reason = $"SMA breve ({shortSMA:F2}) ? SMA lunga ({longSMA:F2}) - Nessun segnale chiaro",
Timestamp = DateTime.UtcNow
});
}
}
}