Sviluppo TradingBot

This commit is contained in:
2026-06-09 18:29:41 +02:00
parent 61f1e59964
commit e3c0bd51b2
133 changed files with 24903 additions and 1 deletions
+184
View File
@@ -0,0 +1,184 @@
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 ─────────────────────────────────────────
/// <summary>Intervallo (secondi) per l'aggiornamento frequente: posizioni e ordini.</summary>
private const int FastRefreshSeconds = 30;
/// <summary>Intervallo (secondi) per l'aggiornamento lento: balance, wallet, dashboard.</summary>
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<Task>
{
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<Task> 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);
}
}
}