using System; using System.Threading; using System.Threading.Tasks; using System.Windows.Input; using DesktopBot.Engine; using DesktopBot.Models; using DesktopBot.Services; namespace DesktopBot.ViewModels { public class MainViewModel : BaseViewModel { private readonly ITradingService _tradingService; private readonly AutomatedBotEngine _botEngine; private readonly AlpacaPingService _pingService; public PingViewModel PingVM { get; } = new PingViewModel(); // ── Auto-refresh periodico ───────────────────────────────────────── /// Intervallo (secondi) per l'aggiornamento frequente: posizioni e ordini. private const int FastRefreshSeconds = 30; /// Intervallo (secondi) per l'aggiornamento lento: balance, wallet, dashboard. private const int SlowRefreshSeconds = 60; private CancellationTokenSource _autoRefreshCts; private int _refreshCycle; // contatore cicli per sfalsare il refresh lento private BaseViewModel _currentViewModel; private string _selectedTab; public DashboardViewModel DashboardVM { get; } public BotsManagerViewModel BotsVM { get; } public LiveLogViewModel LiveLogVM { get; } public WalletViewModel WalletVM { get; } public SettingsViewModel SettingsVM { get; } public BalanceViewModel BalanceVM { get; } public PositionsViewModel PositionsVM { get; } public OrdersViewModel OrdersVM { get; } public BaseViewModel CurrentViewModel { get => _currentViewModel; set => SetProperty(ref _currentViewModel, value); } public string SelectedTab { get => _selectedTab; set { if (SetProperty(ref _selectedTab, value)) NavigateToTab(value); } } public ICommand NavigateCommand { get; } public MainViewModel() { _tradingService = new AlpacaTradingService(); _botEngine = new AutomatedBotEngine(_tradingService); _pingService = new AlpacaPingService(); _pingService.PingCompleted += (_, r) => PingVM.Update(r); DashboardVM = new DashboardViewModel(_tradingService, _botEngine); BotsVM = new BotsManagerViewModel(_tradingService); LiveLogVM = new LiveLogViewModel(_botEngine); WalletVM = new WalletViewModel(_tradingService); SettingsVM = new SettingsViewModel(_tradingService, OnCredentialsSaved); BalanceVM = new BalanceViewModel(_tradingService); PositionsVM = new PositionsViewModel(_tradingService); OrdersVM = new OrdersViewModel(_tradingService); NavigateCommand = new RelayCommand(param => SelectedTab = param?.ToString()); SubscribeToBotEvents(); var saved = CredentialService.LoadCredentials(); if (saved != null) { _tradingService.Initialize(saved.ApiKey, saved.ApiSecret, saved.IsPaper); _pingService.SetEnvironment(saved.IsPaper); _pingService.Start(10); CurrentViewModel = DashboardVM; SelectedTab = "Dashboard"; _ = LoadInitialDataAsync(); } else { CurrentViewModel = SettingsVM; SelectedTab = "Settings"; } } private void NavigateToTab(string tabName) { CurrentViewModel = tabName switch { "Dashboard" => (BaseViewModel)DashboardVM, "Bot" => BotsVM, "LiveLog" => LiveLogVM, "Wallet" => WalletVM, "Settings" => SettingsVM, "Balance" => BalanceVM, "Positions" => PositionsVM, "Orders" => OrdersVM, _ => DashboardVM }; } private void SubscribeToBotEvents() { _botEngine.LogGenerated += (sender, log) => LiveLogVM.AddLog(log); _botEngine.EquityUpdated += (sender, equity) => DashboardVM.UpdateEquity(equity); } private async Task LoadInitialDataAsync() { await Task.WhenAll( DashboardVM.LoadAsync(), WalletVM.LoadAsync(), BalanceVM.LoadAsync(), PositionsVM.LoadAsync(), OrdersVM.LoadAsync() ); StartAutoRefresh(); } // ── Auto-refresh periodico ───────────────────────────────────────── private void StartAutoRefresh() { _autoRefreshCts?.Cancel(); _autoRefreshCts = new CancellationTokenSource(); _refreshCycle = 0; _ = AutoRefreshLoopAsync(_autoRefreshCts.Token); } private async Task AutoRefreshLoopAsync(CancellationToken ct) { try { while (!ct.IsCancellationRequested) { await Task.Delay(TimeSpan.FromSeconds(FastRefreshSeconds), ct); if (ct.IsCancellationRequested) break; _refreshCycle++; // Refresh frequente: posizioni aperte e ordini recenti var fastTasks = new System.Collections.Generic.List { SafeRefresh(PositionsVM.LoadAsync), SafeRefresh(OrdersVM.LoadAsync) }; // Refresh lento (ogni 2 cicli = 60s): balance, wallet, dashboard if (_refreshCycle % 2 == 0) { fastTasks.Add(SafeRefresh(BalanceVM.LoadAsync)); fastTasks.Add(SafeRefresh(WalletVM.LoadAsync)); fastTasks.Add(SafeRefresh(DashboardVM.LoadAsync)); } await Task.WhenAll(fastTasks); } } catch (OperationCanceledException) { /* atteso */ } } private static async Task SafeRefresh(Func loader) { try { await loader(); } catch { /* non bloccare il ciclo per errori singoli di rete */ } } private void OnCredentialsSaved(string apiKey, string apiSecret, bool isPaper) { SelectedTab = "Dashboard"; _ = LoadInitialDataAsync(); } public void InitializeWithCredentials(string apiKey, string apiSecret, bool isPaper) { _tradingService.Initialize(apiKey, apiSecret, isPaper); } } }