Files
Encelado/DesktopBot/ViewModels/BotsManagerViewModel.cs
T
2026-06-09 18:29:41 +02:00

174 lines
8.6 KiB
C#

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
{
/// <summary>
/// ViewModel del pannello Bot Manager.
/// Contiene un unico bot BTC/USD fisso, precaricato all'avvio.
/// L'utente può soltanto avviarlo e fermarlo.
/// </summary>
public class BotsManagerViewModel : BaseViewModel
{
private readonly ITradingService _tradingService;
// ── Collezione (sempre 1 elemento: il bot BTC/USD fisso) ─────────────
public ObservableCollection<BotInstanceViewModel> Bots { get; }
= new ObservableCollection<BotInstanceViewModel>();
/// <summary>Shortcut diretto al bot fisso BTC/USD.</summary>
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.";
}
}
}