using System; using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; using System.Windows.Input; using Alpaca.Markets; using DesktopBot.Engine; using DesktopBot.Models; using DesktopBot.Services; namespace DesktopBot.ViewModels { /// /// ViewModel del pannello Bot Manager. /// Contiene un unico bot BTC/USD fisso, precaricato all'avvio. /// L'utente può soltanto avviarlo e fermarlo. /// public class BotsManagerViewModel : BaseViewModel { private readonly ITradingService _tradingService; // ── Collezione (sempre 1 elemento: il bot BTC/USD fisso) ───────────── public ObservableCollection Bots { get; } = new ObservableCollection(); /// Shortcut diretto al bot fisso BTC/USD. public BotInstanceViewModel BtcBot => Bots.FirstOrDefault(); // ── Grafico prezzi BTC/USD ───────────────────────────────────────── public PriceChartViewModel ChartVM { get; } // ── Stato UI ───────────────────────────────────────────────────────── private string _statusMessage; public string StatusMessage { get => _statusMessage; set => SetProperty(ref _statusMessage, value); } // ── Comandi ────────────────────────────────────────────────────────── public ICommand StartBotCommand { get; } public ICommand StopBotCommand { get; } public ICommand SaveAllCommand { get; } // ── Ctor ───────────────────────────────────────────────────────────── public BotsManagerViewModel(ITradingService tradingService) { _tradingService = tradingService ?? throw new ArgumentNullException(nameof(tradingService)); ChartVM = new PriceChartViewModel(tradingService); StartBotCommand = new RelayCommand(_ => BtcBot?.StartBot(), _ => BtcBot != null && !BtcBot.IsRunning); StopBotCommand = new RelayCommand(_ => BtcBot?.ForceStop(), _ => BtcBot != null && BtcBot.IsRunning); SaveAllCommand = new RelayCommand(_ => SaveAll()); EnsureBtcBotExists(); // Avvia streaming grafico in background _ = ChartVM.StartStreamingAsync(); } // ── Preload bot BTC/USD fisso ───────────────────────────────────────── private void EnsureBtcBotExists() { // Tenta di caricare da disco var saved = BotInstanceStore.Load(); var btcModel = saved.FirstOrDefault(m => string.Equals(m.Symbol, "BTCUSD", StringComparison.OrdinalIgnoreCase)); if (btcModel == null) { // Prima esecuzione: crea il bot BTC/USD con parametri ottimali btcModel = CreateBtcUsdBot(); BotInstanceStore.Save(new[] { btcModel }); } var vm = new BotInstanceViewModel(btcModel, _tradingService); // Il bot fisso non può essere rimosso — ignoriamo RemoveRequested Bots.Add(vm); StatusMessage = "Bot BTC/USD caricato — pronto all'avvio."; } private static BotInstance CreateBtcUsdBot() { var config = new BotConfiguration { Symbol = "BTCUSD", Quantity = 1, CheckIntervalSeconds = 60, AnalysisTimeFrame = BarTimeFrame.Minute, HistoricalBarCount = 200, // EMA ottimizzate per 1min BTC FastEmaPeriod = 5, SlowEmaPeriod = 20, // RSI RsiPeriod = 14, RsiOversoldThreshold = 30, RsiOverboughtThreshold = 70, // MACD MacdFastPeriod = 8, MacdSlowPeriod = 21, MacdSignalPeriod = 5, // Keltner / RVOL KeltnerPeriod = 20, KeltnerMultiplier = 2.0m, RvolMinThreshold = 2.0m, AtrStopMultiplier = 1.5m, // Kalman KalmanDelta = 5e-6, KalmanObservationVariance = 1.0, KalmanEntryZScore = 1.8, KalmanExitZScore = 0.3, // Risk StopLossPercentage = 0.02m, TakeProfitPercentage = 0.04m, MaxPositionSizePercent = 0.10m, // Algoritmo BTC/USD avanzato (dispatch automatico nell'engine) Strategy = TradingStrategy.VOLATILITY_BREAKOUT, RecommendedStrategy = TradingStrategy.VOLATILITY_BREAKOUT, IsLocked = true, LockedAt = DateTime.Now }; var model = new BotInstance { Name = "BTC/USD — Algoritmo Avanzato", BadgeColor = "#F7931A", // arancione Bitcoin Config = config, Notes = "Bot predefinito BTC/USD. Algoritmo multi-segnale: Regime Detector + Kalman + ATR Sizing.", CreatedAt = DateTime.Now, IsEnabled = true }; // Blocca asset e config (bot fisso) model.Symbol = "BTCUSD"; model.AssetName = "Bitcoin / US Dollar"; model.AssetClass = "crypto"; model.LockToAsset(); return model; } // ── Persistenza ────────────────────────────────────────────────────── public void SaveAll() { BotInstanceStore.Save(Bots.Select(vm => vm.Model)); StatusMessage = $"Salvato — {DateTime.Now:HH:mm:ss}"; } // ── Start / Stop esposto ai comandi ─────────────────────────────────── private async Task StartAllAsync() { if (BtcBot != null && !BtcBot.IsRunning) BtcBot.StartBot(); await Task.CompletedTask; } private void StopAll() { if (BtcBot?.IsRunning == true) BtcBot.ForceStop(); StatusMessage = "Bot fermato."; } } }