Nuove: multi-strategy, indicatori avanzati, posizioni

- Sidebar portfolio con metriche dettagliate (Totale, Investito, Disponibile, P&L, ROI) e aggiornamento real-time
- Sistema multi-strategia: 8 strategie assegnabili per asset, voting decisionale, pagina Trading Control
- Nuova pagina Posizioni: gestione, chiusura manuale, P&L non realizzato, notifiche
- Sistema indicatori tecnici: 7+ indicatori configurabili, segnali real-time, raccomandazioni, storico segnali
- Refactoring TradingBotService per capitale, P&L, ROI, eventi
- Nuovi modelli e servizi per strategie/indicatori, persistenza configurazioni
- UI/UX: navigazione aggiornata, widget, modali, responsive
- Aggiornamento README e CHANGELOG con tutte le novità
This commit is contained in:
2026-01-06 17:49:07 +01:00
parent c229c50f1d
commit 64f3511695
18 changed files with 4266 additions and 41 deletions

View File

@@ -8,6 +8,8 @@ public class TradingBotService
private readonly ITradingStrategy _strategy;
private readonly TradeHistoryService _historyService;
private readonly LoggingService _loggingService;
private readonly IndicatorsService _indicatorsService;
private readonly TradingStrategiesService _strategiesService;
private readonly Dictionary<string, AssetConfiguration> _assetConfigs = new();
private readonly Dictionary<string, AssetStatistics> _assetStats = new();
private readonly List<Trade> _trades = new();
@@ -34,12 +36,16 @@ public class TradingBotService
IMarketDataService marketDataService,
ITradingStrategy strategy,
TradeHistoryService historyService,
LoggingService loggingService)
LoggingService loggingService,
IndicatorsService indicatorsService,
TradingStrategiesService strategiesService)
{
_marketDataService = marketDataService;
_strategy = strategy;
_historyService = historyService;
_loggingService = loggingService;
_indicatorsService = indicatorsService;
_strategiesService = strategiesService;
Status.CurrentStrategy = strategy.Name;
// Subscribe to simulated market updates if available
@@ -484,8 +490,138 @@ public class TradingBotService
_indicators[symbol] = indicators;
OnIndicatorsUpdated?.Invoke(symbol, indicators);
// Update IndicatorsService statuses
UpdateIndicatorStatuses(symbol, indicators, prices);
}
private void UpdateIndicatorStatuses(string symbol, TechnicalIndicators indicators, List<decimal> prices)
{
// Update RSI status
var rsiConfig = _indicatorsService.GetIndicators().Values.FirstOrDefault(i => i.Id == "rsi");
if (rsiConfig?.IsEnabled == true)
{
var rsiStatus = new IndicatorStatus
{
IndicatorId = "rsi",
Symbol = symbol,
CurrentValue = indicators.RSI,
Condition = indicators.RSI > (rsiConfig.OverboughtThreshold ?? 70) ? MarketCondition.Overbought :
indicators.RSI < (rsiConfig.OversoldThreshold ?? 30) ? MarketCondition.Oversold :
MarketCondition.Neutral,
Recommendation = indicators.RSI > (rsiConfig.OverboughtThreshold ?? 70) ? "Possibile vendita" :
indicators.RSI < (rsiConfig.OversoldThreshold ?? 30) ? "Possibile acquisto" :
"Attendi conferma"
};
_indicatorsService.UpdateIndicatorStatus("rsi", symbol, rsiStatus);
// Generate signal if crossing threshold
if (indicators.RSI < 30)
{
_indicatorsService.GenerateSignal(new IndicatorSignal
{
IndicatorId = "rsi",
IndicatorName = "RSI",
Symbol = symbol,
Type = SignalType.Buy,
Strength = indicators.RSI < 20 ? SignalStrength.VeryStrong : SignalStrength.Strong,
Message = $"RSI in zona ipervenduto: {indicators.RSI:F2}",
Value = indicators.RSI
});
}
else if (indicators.RSI > 70)
{
_indicatorsService.GenerateSignal(new IndicatorSignal
{
IndicatorId = "rsi",
IndicatorName = "RSI",
Symbol = symbol,
Type = SignalType.Sell,
Strength = indicators.RSI > 80 ? SignalStrength.VeryStrong : SignalStrength.Strong,
Message = $"RSI in zona ipercomprato: {indicators.RSI:F2}",
Value = indicators.RSI
});
}
}
// Update MACD status
var macdConfig = _indicatorsService.GetIndicators().Values.FirstOrDefault(i => i.Id == "macd");
if (macdConfig?.IsEnabled == true)
{
var macdStatus = new IndicatorStatus
{
IndicatorId = "macd",
Symbol = symbol,
CurrentValue = indicators.MACD,
Condition = indicators.Histogram > 0 ? MarketCondition.Bullish : MarketCondition.Bearish,
Recommendation = indicators.Histogram > 0 ? "Trend rialzista" : "Trend ribassista"
};
_indicatorsService.UpdateIndicatorStatus("macd", symbol, macdStatus);
// Generate signal on crossover
if (Math.Abs(indicators.Histogram) < 0.5m) // Near crossover
{
_indicatorsService.GenerateSignal(new IndicatorSignal
{
IndicatorId = "macd",
IndicatorName = "MACD",
Symbol = symbol,
Type = indicators.Histogram > 0 ? SignalType.Buy : SignalType.Sell,
Strength = SignalStrength.Moderate,
Message = $"MACD {(indicators.Histogram > 0 ? "bullish" : "bearish")} crossover",
Value = indicators.MACD
});
}
}
// Update SMA statuses
var currentPrice = prices.Last();
var sma20Config = _indicatorsService.GetIndicators().Values.FirstOrDefault(i => i.Id == "sma_20");
if (sma20Config?.IsEnabled == true && prices.Count >= 20)
{
var sma20 = prices.TakeLast(20).Average();
var sma20Status = new IndicatorStatus
{
IndicatorId = "sma_20",
Symbol = symbol,
CurrentValue = sma20,
Condition = currentPrice > sma20 ? MarketCondition.Bullish : MarketCondition.Bearish,
Recommendation = currentPrice > sma20 ? "Prezzo sopra media" : "Prezzo sotto media"
};
_indicatorsService.UpdateIndicatorStatus("sma_20", symbol, sma20Status);
}
var sma50Config = _indicatorsService.GetIndicators().Values.FirstOrDefault(i => i.Id == "sma_50");
if (sma50Config?.IsEnabled == true && prices.Count >= 50)
{
var sma50 = prices.TakeLast(50).Average();
var sma50Status = new IndicatorStatus
{
IndicatorId = "sma_50",
Symbol = symbol,
CurrentValue = sma50,
Condition = currentPrice > sma50 ? MarketCondition.Bullish : MarketCondition.Bearish,
Recommendation = currentPrice > sma50 ? "Trend rialzista medio termine" : "Trend ribassista medio termine"
};
_indicatorsService.UpdateIndicatorStatus("sma_50", symbol, sma50Status);
}
// Update EMA status
var ema12Config = _indicatorsService.GetIndicators().Values.FirstOrDefault(i => i.Id == "ema_12");
if (ema12Config?.IsEnabled == true)
{
var ema12Status = new IndicatorStatus
{
IndicatorId = "ema_12",
Symbol = symbol,
CurrentValue = indicators.EMA12,
Condition = currentPrice > indicators.EMA12 ? MarketCondition.Bullish : MarketCondition.Bearish,
Recommendation = currentPrice > indicators.EMA12 ? "Trend positivo" : "Trend negativo"
};
_indicatorsService.UpdateIndicatorStatus("ema_12", symbol, ema12Status);
}
}
private void UpdateAssetStatistics(string symbol, Trade trade, decimal? realizedProfit = null)
{
if (!_assetStats.TryGetValue(symbol, out var stats))
@@ -631,4 +767,30 @@ public class TradingBotService
OnStatusChanged?.Invoke();
await Task.CompletedTask;
}
/// <summary>
/// Manually close a position
/// </summary>
public async Task ClosePositionManuallyAsync(string symbol)
{
if (!_activePositions.TryGetValue(symbol, out var position))
{
throw new InvalidOperationException($"No active position found for {symbol}");
}
if (!_assetConfigs.TryGetValue(symbol, out var config))
{
throw new InvalidOperationException($"Asset configuration not found for {symbol}");
}
// Get current market price
var latestPrice = GetLatestPrice(symbol);
if (latestPrice == null || latestPrice.Price <= 0)
{
throw new InvalidOperationException($"Cannot get current price for {symbol}");
}
// Execute sell
await ExecuteSellAsync(symbol, latestPrice.Price, config.CurrentHoldings, config);
}
}