174 lines
8.6 KiB
C#
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.";
|
|
}
|
|
}
|
|
}
|
|
|