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:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user