Sviluppo TradingBot
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
namespace DesktopBot.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Risultato semplificato della ricerca asset su Alpaca.
|
||||
/// </summary>
|
||||
public class AssetSearchResult
|
||||
{
|
||||
public string Symbol { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string AssetClass { get; set; }
|
||||
public string Exchange { get; set; }
|
||||
public bool Tradable { get; set; }
|
||||
|
||||
/// <summary>True quando questo asset è selezionato nel Market Watch panel.</summary>
|
||||
public bool IsSelected { get; set; }
|
||||
|
||||
public override string ToString() => $"{Symbol} — {Name}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
using System;
|
||||
using Alpaca.Markets;
|
||||
|
||||
namespace DesktopBot.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Modello per la configurazione del bot
|
||||
/// </summary>
|
||||
public class BotConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// Simbolo ticker da tradare (es. "AAPL", "TSLA")
|
||||
/// </summary>
|
||||
public string Symbol { get; set; } = "AAPL";
|
||||
|
||||
/// <summary>
|
||||
/// Quantità di azioni da acquistare per operazione
|
||||
/// </summary>
|
||||
public int Quantity { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Intervallo in secondi tra ogni controllo del bot
|
||||
/// </summary>
|
||||
public int CheckIntervalSeconds { get; set; } = 60;
|
||||
|
||||
/// <summary>
|
||||
/// Timeframe delle barre da analizzare: Minute (1min), Hour (1h), Day (1d).
|
||||
/// Default: Day per compatibilità con strategie esistenti.
|
||||
/// Per crypto ad alta frequenza, usare Minute.
|
||||
/// </summary>
|
||||
public BarTimeFrame AnalysisTimeFrame { get; set; } = BarTimeFrame.Day;
|
||||
|
||||
/// <summary>
|
||||
/// Numero di periodi (barre) da richiedere per l'analisi.
|
||||
/// Default: automatico in base alla strategia.
|
||||
/// Per strategie su 1min: 200-300 barre = 3-5 ore di storico.
|
||||
/// </summary>
|
||||
public int HistoricalBarCount { get; set; } = 0; // 0 = automatico
|
||||
|
||||
/// <summary>
|
||||
/// Percentuale di Stop Loss (es. 0.02 = 2%)
|
||||
/// </summary>
|
||||
public decimal StopLossPercentage { get; set; } = 0.02m;
|
||||
|
||||
/// <summary>
|
||||
/// Percentuale di Take Profit (es. 0.05 = 5%)
|
||||
/// </summary>
|
||||
public decimal TakeProfitPercentage { get; set; } = 0.05m;
|
||||
|
||||
/// <summary>
|
||||
/// Percentuale massima del portfolio da utilizzare per operazione (0.1 = 10%)
|
||||
/// </summary>
|
||||
public decimal MaxPositionSizePercent { get; set; } = 0.10m;
|
||||
|
||||
// ─── EMA CROSSOVER ────────────────────────────────────────────────
|
||||
/// <summary>Periodo EMA veloce (default 9)</summary>
|
||||
public int FastEmaPeriod { get; set; } = 9;
|
||||
|
||||
/// <summary>Periodo EMA lenta (default 21)</summary>
|
||||
public int SlowEmaPeriod { get; set; } = 21;
|
||||
|
||||
// ─── RSI ──────────────────────────────────────────────────────────
|
||||
/// <summary>Periodo RSI (default 14)</summary>
|
||||
public int RsiPeriod { get; set; } = 14;
|
||||
|
||||
/// <summary>Soglia ipervenduto (default 30)</summary>
|
||||
public decimal RsiOversoldThreshold { get; set; } = 30;
|
||||
|
||||
/// <summary>Soglia ipercomprato (default 70)</summary>
|
||||
public decimal RsiOverboughtThreshold { get; set; } = 70;
|
||||
|
||||
// ─── MACD ─────────────────────────────────────────────────────────
|
||||
/// <summary>Periodo EMA veloce MACD (default 12)</summary>
|
||||
public int MacdFastPeriod { get; set; } = 12;
|
||||
|
||||
/// <summary>Periodo EMA lenta MACD (default 26)</summary>
|
||||
public int MacdSlowPeriod { get; set; } = 26;
|
||||
|
||||
/// <summary>Periodo Signal Line MACD (default 9)</summary>
|
||||
public int MacdSignalPeriod { get; set; } = 9;
|
||||
|
||||
// ─── VOLATILITY BREAKOUT (Keltner + RVOL + CVD) ──────────────────
|
||||
/// <summary>Periodo ATR e canale Keltner (default 20)</summary>
|
||||
public int KeltnerPeriod { get; set; } = 20;
|
||||
|
||||
/// <summary>
|
||||
/// Moltiplicatore ATR per larghezza canale Keltner (default 2.0)
|
||||
/// Bande = EMA ± KeltnerMultiplier × ATR
|
||||
/// </summary>
|
||||
public decimal KeltnerMultiplier { get; set; } = 2.0m;
|
||||
|
||||
/// <summary>
|
||||
/// Soglia minima RVOL (Volume Relativo) per validare il breakout (default 2.0 = 2× il volume medio).
|
||||
/// Un valore elevato filtra le rotture false prive di supporto volumetrico istituzionale.
|
||||
/// </summary>
|
||||
public decimal RvolMinThreshold { get; set; } = 2.0m;
|
||||
|
||||
/// <summary>
|
||||
/// Moltiplicatore ATR per lo Stop Loss nei breakout (default 1.0).
|
||||
/// SL = punto di breakout ± AtrStopMultiplier × ATR
|
||||
/// </summary>
|
||||
public decimal AtrStopMultiplier { get; set; } = 1.0m;
|
||||
|
||||
// ─── KALMAN MEAN REVERSION ────────────────────────────────────────
|
||||
/// <summary>
|
||||
/// Fattore di decadimento δ (delta) del rumore di transizione Kalman (default 1e-5).
|
||||
/// W = δ/(1-δ) × I₂ — controlla la velocità di adattamento dell'hedge ratio.
|
||||
/// Valori piccoli → hedge ratio stabile; valori grandi → adattamento aggressivo.
|
||||
/// </summary>
|
||||
public double KalmanDelta { get; set; } = 1e-5;
|
||||
|
||||
/// <summary>
|
||||
/// Varianza del rumore di osservazione Kalman (default 1.0).
|
||||
/// Modella l'incertezza della misura di prezzo rispetto al fair value stimato.
|
||||
/// </summary>
|
||||
public double KalmanObservationVariance { get; set; } = 1.0;
|
||||
|
||||
/// <summary>
|
||||
/// Soglia Z-Score per entrata Long (default -2.0): il prezzo è sufficientemente sotto il fair value.
|
||||
/// </summary>
|
||||
public double KalmanEntryZScore { get; set; } = 2.0;
|
||||
|
||||
/// <summary>
|
||||
/// Soglia Z-Score per uscita / take profit (default 0.25): spread converge alla media.
|
||||
/// </summary>
|
||||
public double KalmanExitZScore { get; set; } = 0.25;
|
||||
|
||||
// ─── RISK MANAGEMENT ─────────────────────────────────────────────────
|
||||
/// <summary>
|
||||
/// Numero massimo di posizioni aperte contemporaneamente (default 3).
|
||||
/// Se il numero di posizioni aperte raggiunge questo limite, non verranno aperti nuovi ordini.
|
||||
/// </summary>
|
||||
public int MaxOpenPositions { get; set; } = 3;
|
||||
|
||||
/// <summary>
|
||||
/// Numero massimo di posizioni aperte per lo stesso asset (default 10).
|
||||
/// Impedisce di accumulare troppe posizioni sullo stesso simbolo.
|
||||
/// </summary>
|
||||
public int MaxOpenPositionsPerAsset { get; set; } = 10;
|
||||
|
||||
/// <summary>
|
||||
/// Percentuale massima del capitale totale che può essere allocata in posizioni aperte (default 30%).
|
||||
/// Evita di impegnare troppo capitale su tante posizioni piccole.
|
||||
/// Es: con equity=100k e MaxCapitalAllocatedPercent=0.30, non si può superare 30k allocati.
|
||||
/// </summary>
|
||||
public decimal MaxCapitalAllocatedPercent { get; set; } = 0.30m;
|
||||
|
||||
/// <summary>
|
||||
/// Soglia di profitto percentuale oltre la quale si considera di chiudere la posizione (lock profit).
|
||||
/// Es: 0.03 = chiude quando la posizione è in profitto di almeno il 3%.
|
||||
/// Se 0, il take-profit è gestito solo dall'ordine limit TP.
|
||||
/// </summary>
|
||||
public decimal ProfitLockPercent { get; set; } = 0.03m;
|
||||
|
||||
/// <summary>
|
||||
/// Perdita massima percentuale tollerata su una singola posizione aperta prima di tagliarla (default 2%).
|
||||
/// Questo agisce come stop-loss dinamico di seconda linea, indipendente dall'ordine stop piazzato.
|
||||
/// Es: 0.02 = chiude se la posizione perde più del 2% rispetto all'ingresso.
|
||||
/// </summary>
|
||||
public decimal MaxLossPercent { get; set; } = 0.02m;
|
||||
|
||||
/// <summary>
|
||||
/// Se true, sposta lo stop-loss al punto di pareggio (break-even) quando il profitto supera ProfitLockPercent/2.
|
||||
/// Protegge il capitale una volta che la posizione è in verde.
|
||||
/// </summary>
|
||||
public bool UseBreakEvenStop { get; set; } = true;
|
||||
|
||||
// ─── ASSET-STRATEGY OPTIMIZATION ─────────────────────────────────────
|
||||
/// <summary>
|
||||
/// Strategia raccomandata dal StrategyAdvisor per la classe d'asset corrente.
|
||||
/// Viene aggiornata automaticamente quando si associa un asset al bot.
|
||||
/// </summary>
|
||||
public TradingStrategy? RecommendedStrategy { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// True quando la strategia attiva corrisponde a quella raccomandata per l'asset.
|
||||
/// Usato dalla UI per mostrare il badge "Ottimizzato".
|
||||
/// </summary>
|
||||
public bool IsOptimizedForAsset
|
||||
=> RecommendedStrategy.HasValue && Strategy == RecommendedStrategy.Value;
|
||||
|
||||
/// <summary>
|
||||
/// True quando la configurazione è stata bloccata a seguito dell'associazione con un asset.
|
||||
/// Dopo il lock, i parametri critici della strategia non possono essere modificati liberamente.
|
||||
/// </summary>
|
||||
public bool IsLocked { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp del momento in cui la configurazione è stata bloccata.
|
||||
/// Null se la configurazione non è ancora stata bloccata.
|
||||
/// </summary>
|
||||
public DateTime? LockedAt { get; set; } = null;
|
||||
|
||||
// ─── STRATEGIA ATTIVA ─────────────────────────────────────────────
|
||||
/// <summary>Strategia di trading da utilizzare</summary>
|
||||
public TradingStrategy Strategy { get; set; } = TradingStrategy.EMA_CROSSOVER;
|
||||
|
||||
/// <summary>
|
||||
/// Blocca la configurazione corrente, impedendo modifiche successive alla strategia.
|
||||
/// Questo viene chiamato quando un bot viene associato a un asset.
|
||||
/// </summary>
|
||||
public void Lock()
|
||||
{
|
||||
if (!IsLocked)
|
||||
{
|
||||
IsLocked = true;
|
||||
LockedAt = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
// ─── LOGGING CONFIGURATION ──────────────────────────────────────────
|
||||
/// <summary>Configurazione dei limiti per i log e i dati storici.</summary>
|
||||
public LoggingConfiguration LoggingConfig { get; set; } = new LoggingConfiguration();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tipo di strategia di trading
|
||||
/// </summary>
|
||||
public enum TradingStrategy
|
||||
{
|
||||
/// <summary>Crossover di medie mobili esponenziali (EMA veloce vs EMA lenta)</summary>
|
||||
EMA_CROSSOVER,
|
||||
|
||||
/// <summary>RSI (Relative Strength Index) – ipervenduto/ipercomprato</summary>
|
||||
RSI,
|
||||
|
||||
/// <summary>MACD – divergenza tra EMA veloce e lenta con signal line</summary>
|
||||
MACD,
|
||||
|
||||
/// <summary>Volatility Breakout – Keltner Channel con filtri RVOL e CVD (Cap.3 del report)</summary>
|
||||
VOLATILITY_BREAKOUT,
|
||||
|
||||
/// <summary>Mean Reversion con Filtro di Kalman – stima dinamica del fair value (Cap.4 del report)</summary>
|
||||
KALMAN_MEAN_REVERSION
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
|
||||
namespace DesktopBot.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Rappresenta una singola istanza di bot configurata e associata a un asset.
|
||||
/// L'ID univoco viene incorporato nel ClientOrderId di ogni ordine Alpaca,
|
||||
/// così le posizioni aperte rimangono associabili al bot anche dopo un riavvio.
|
||||
///
|
||||
/// Formato ClientOrderId: "BOT_{BotId}_{timestamp}"
|
||||
/// Esempio: "BOT_3f2a1b_20250610T143022"
|
||||
///
|
||||
/// VINCOLO: Ogni bot è strettamente associato a un SINGOLO asset con una SINGOLA strategia.
|
||||
/// Una volta assegnato l'asset, il bot viene bloccato (IsAssetLocked=true) e non è più possibile
|
||||
/// modificare Symbol, AssetClass o Strategy.
|
||||
/// </summary>
|
||||
public class BotInstance
|
||||
{
|
||||
/// <summary>ID univoco del bot (6 hex chars, stabile nel tempo)</summary>
|
||||
public string BotId { get; set; } = Guid.NewGuid().ToString("N").Substring(0, 6);
|
||||
|
||||
/// <summary>Nome leggibile assegnato dall'utente (es. "EMA AAPL #1")</summary>
|
||||
public string Name { get; set; } = "Nuovo Bot";
|
||||
|
||||
/// <summary>Simbolo ticker associato (es. "AAPL", "MSFT")</summary>
|
||||
public string Symbol { get; set; } = "";
|
||||
|
||||
/// <summary>Nome dell'asset completo (es. "Apple Inc.")</summary>
|
||||
public string AssetName { get; set; } = "";
|
||||
|
||||
/// <summary>Classe dell'asset: "us_equity", "crypto", ecc.</summary>
|
||||
public string AssetClass { get; set; } = "us_equity";
|
||||
|
||||
/// <summary>
|
||||
/// True quando il bot è stato associato a un asset e la configurazione è bloccata.
|
||||
/// Dopo il lock, Symbol, AssetClass e Strategy non possono più essere modificati.
|
||||
/// </summary>
|
||||
public bool IsAssetLocked { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp del momento in cui il bot è stato associato all'asset e bloccato.
|
||||
/// Null se il bot non è ancora stato associato a un asset.
|
||||
/// </summary>
|
||||
public DateTime? LockedAt { get; set; } = null;
|
||||
|
||||
/// <summary>Bot attivo o sospeso</summary>
|
||||
public bool IsEnabled { get; set; } = true;
|
||||
|
||||
/// <summary>Configurazione della strategia</summary>
|
||||
public BotConfiguration Config { get; set; } = new BotConfiguration();
|
||||
|
||||
/// <summary>Data e ora di creazione del bot</summary>
|
||||
public DateTime CreatedAt { get; set; } = DateTime.Now;
|
||||
|
||||
/// <summary>Note libere dell'utente</summary>
|
||||
public string Notes { get; set; } = "";
|
||||
|
||||
/// <summary>Colore badge nella UI (hex, es. "#00E676")</summary>
|
||||
public string BadgeColor { get; set; } = "#00E676";
|
||||
|
||||
/// <summary>
|
||||
/// Blocca il bot associandolo definitivamente all'asset corrente.
|
||||
/// Dopo questa operazione, Symbol, AssetClass e Strategy diventano immutabili.
|
||||
/// </summary>
|
||||
public void LockToAsset()
|
||||
{
|
||||
if (!IsAssetLocked && !string.IsNullOrWhiteSpace(Symbol))
|
||||
{
|
||||
IsAssetLocked = true;
|
||||
LockedAt = DateTime.Now;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace DesktopBot.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Gestisce la persistenza delle istanze di bot in un file JSON locale.
|
||||
/// Percorso: %AppData%\TradingBot\bots.json
|
||||
/// </summary>
|
||||
public static class BotInstanceStore
|
||||
{
|
||||
private static readonly string StorePath = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||
"TradingBot",
|
||||
"bots.json"
|
||||
);
|
||||
|
||||
/// <summary>Carica tutti i bot salvati dal disco. Ritorna lista vuota se il file non esiste.</summary>
|
||||
public static List<BotInstance> Load()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!File.Exists(StorePath))
|
||||
return new List<BotInstance>();
|
||||
|
||||
var json = File.ReadAllText(StorePath, Encoding.UTF8);
|
||||
return JsonConvert.DeserializeObject<List<BotInstance>>(json) ?? new List<BotInstance>();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new List<BotInstance>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Salva tutti i bot su disco.</summary>
|
||||
public static void Save(IEnumerable<BotInstance> bots)
|
||||
{
|
||||
try
|
||||
{
|
||||
var dir = Path.GetDirectoryName(StorePath);
|
||||
if (!Directory.Exists(dir))
|
||||
Directory.CreateDirectory(dir);
|
||||
|
||||
var json = JsonConvert.SerializeObject(new List<BotInstance>(bots), Formatting.Indented);
|
||||
File.WriteAllText(StorePath, json, Encoding.UTF8);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Logging silenzioso: non bloccare la UI per errori di I/O
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
|
||||
namespace DesktopBot.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Modello per un log del bot
|
||||
/// </summary>
|
||||
public class BotLogEntry
|
||||
{
|
||||
public DateTime Timestamp { get; set; }
|
||||
public LogLevel Level { get; set; }
|
||||
public string Message { get; set; }
|
||||
public string Details { get; set; }
|
||||
|
||||
public BotLogEntry(LogLevel level, string message, string details = "")
|
||||
{
|
||||
Timestamp = DateTime.Now;
|
||||
Level = level;
|
||||
Message = message;
|
||||
Details = details;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Livello di log
|
||||
/// </summary>
|
||||
public enum LogLevel
|
||||
{
|
||||
Info,
|
||||
Success,
|
||||
Warning,
|
||||
Error
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
|
||||
namespace DesktopBot.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Record di un trade (aperto o chiuso) effettuato dal bot.
|
||||
/// </summary>
|
||||
public class BotTradeRecord
|
||||
{
|
||||
public string Symbol { get; set; }
|
||||
public string Side { get; set; } // "BUY" / "SELL"
|
||||
public decimal EntryPrice { get; set; }
|
||||
public decimal ExitPrice { get; set; } // 0 se ancora aperta
|
||||
public decimal Quantity { get; set; }
|
||||
public decimal StopLoss { get; set; }
|
||||
public decimal TakeProfit { get; set; }
|
||||
public decimal PnL { get; set; } // 0 se ancora aperta
|
||||
public DateTime OpenedAt { get; set; }
|
||||
public DateTime? ClosedAt { get; set; }
|
||||
public bool IsOpen => ClosedAt == null;
|
||||
public int Confidence { get; set; }
|
||||
|
||||
/// <summary>PnL percentuale sull'investimento iniziale.</summary>
|
||||
public decimal PnLPercent =>
|
||||
EntryPrice > 0 && Quantity > 0
|
||||
? PnL / (EntryPrice * Quantity) * 100m
|
||||
: 0m;
|
||||
|
||||
/// <summary>
|
||||
/// Badge testuale: APERTA / +X.XX% / -X.XX%
|
||||
/// </summary>
|
||||
public string PnLBadge =>
|
||||
IsOpen
|
||||
? "APERTA"
|
||||
: $"{PnL:+0.00;-0.00;0.00} ({PnLPercent:+0.0;-0.0;0.0}%)";
|
||||
|
||||
/// <summary>Stringa di stato colorabile via DataTrigger.</summary>
|
||||
public string Status => IsOpen ? "APERTA" : (PnL >= 0 ? "CHIUSA +" : "CHIUSA -");
|
||||
|
||||
/// <summary>
|
||||
/// Categoria PnL per i DataTrigger XAML ("open" / "profit" / "loss").
|
||||
/// </summary>
|
||||
public string PnLCategory =>
|
||||
IsOpen ? "open" :
|
||||
PnL > 0 ? "profit" : "loss";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
|
||||
namespace DesktopBot.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Configurazione globale per i limiti di memorizzazione dei log e dati storici.
|
||||
/// I valori sono conservativamente alti per mantenere il massimo di informazioni possibili.
|
||||
/// </summary>
|
||||
public class LoggingConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// Numero massimo di elementi nel log del bot (BotLog).
|
||||
/// Default: 5000 (mantiene ~8-10 ore di trading con CheckIntervalSeconds=60).
|
||||
/// </summary>
|
||||
public int MaxBotLogEntries { get; set; } = 5000;
|
||||
|
||||
/// <summary>
|
||||
/// Numero massimo di elementi nello storico trade (TradeHistory).
|
||||
/// Default: 2000 (mantiene mesi di operazioni).
|
||||
/// </summary>
|
||||
public int MaxTradeHistoryEntries { get; set; } = 2000;
|
||||
|
||||
/// <summary>
|
||||
/// Numero massimo di elementi nel log attività della dashboard (ActivityLog).
|
||||
/// Default: 5000 (cronologia completa della sessione di trading).
|
||||
/// </summary>
|
||||
public int MaxActivityLogEntries { get; set; } = 5000;
|
||||
|
||||
/// <summary>
|
||||
/// Numero massimo di elementi nel log live globale (LiveLog).
|
||||
/// Default: 10000 (log dettagliato completo di tutte le operazioni).
|
||||
/// </summary>
|
||||
public int MaxLiveLogEntries { get; set; } = 10000;
|
||||
|
||||
/// <summary>
|
||||
/// Numero massimo di punti dati nel grafico dei prezzi (PriceData).
|
||||
/// Default: 3000 (mantiene ore di dati a 1min, giorni a 15min).
|
||||
/// </summary>
|
||||
public int MaxPriceDataPoints { get; set; } = 3000;
|
||||
|
||||
/// <summary>
|
||||
/// Clona la configurazione corrente.
|
||||
/// </summary>
|
||||
public LoggingConfiguration Clone()
|
||||
{
|
||||
return new LoggingConfiguration
|
||||
{
|
||||
MaxBotLogEntries = this.MaxBotLogEntries,
|
||||
MaxTradeHistoryEntries = this.MaxTradeHistoryEntries,
|
||||
MaxActivityLogEntries = this.MaxActivityLogEntries,
|
||||
MaxLiveLogEntries = this.MaxLiveLogEntries,
|
||||
MaxPriceDataPoints = this.MaxPriceDataPoints
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using Alpaca.Markets;
|
||||
|
||||
namespace DesktopBot.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Segnale di trading generato da una strategia.
|
||||
/// </summary>
|
||||
public class TradingSignal
|
||||
{
|
||||
public SignalType Type { get; set; }
|
||||
public string Symbol { get; set; }
|
||||
public decimal Price { get; set; }
|
||||
public DateTime Timestamp { get; set; }
|
||||
public string Reason { get; set; }
|
||||
/// <summary>Confidenza del segnale (0–100).</summary>
|
||||
public int Confidence { get; set; }
|
||||
/// <summary>
|
||||
/// Livello di Stop Loss calcolato dalla strategia (0 = non impostato,
|
||||
/// viene usato il default percentuale di BotConfiguration).
|
||||
/// </summary>
|
||||
public decimal StopLoss { get; set; }
|
||||
/// <summary>
|
||||
/// Livello di Take Profit calcolato dalla strategia (0 = non impostato).
|
||||
/// </summary>
|
||||
public decimal TakeProfit { get; set; }
|
||||
|
||||
/// <summary>Lato dell'ordine Alpaca derivato dal tipo di segnale.</summary>
|
||||
public OrderSide Side => Type == SignalType.Sell ? OrderSide.Sell : OrderSide.Buy;
|
||||
}
|
||||
|
||||
public enum SignalType
|
||||
{
|
||||
None,
|
||||
Buy,
|
||||
Sell,
|
||||
Hold
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user