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
This commit is contained in:
2025-12-17 14:34:52 +01:00
parent 8ee8dc7e71
commit 5532ad2473
9 changed files with 573 additions and 18 deletions

View File

@@ -11,19 +11,38 @@ public class SimpleMovingAverageStrategy : ITradingStrategy
public Task<TradingSignal> AnalyzeAsync(string symbol, List<MarketPrice> historicalPrices)
{
if (historicalPrices.Count < _longPeriod)
// 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,
Price = historicalPrices?.LastOrDefault()?.Price ?? 0,
Reason = "Dati insufficienti per l'analisi",
Timestamp = DateTime.UtcNow
});
}
var recentPrices = historicalPrices.OrderByDescending(p => p.Timestamp).Take(_longPeriod).ToList();
// 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);