1use std::collections::HashMap;
2
3use crate::model::candle::Candle;
4use crate::model::order::OrderSide;
5use crate::model::signal::Signal;
6use crate::model::tick::Tick;
7use crate::order_manager::{OrderHistorySnapshot, OrderHistoryStats, OrderUpdate};
8use crate::risk_module::RateBudgetSnapshot;
9
10#[derive(Debug, Clone)]
11pub enum WsConnectionStatus {
12 Connected,
13 Disconnected,
14 Reconnecting { attempt: u32, delay_ms: u64 },
15}
16
17#[derive(Debug, Clone)]
18pub enum AppEvent {
19 MarketTick(Tick),
20 StrategySignal {
21 signal: Signal,
22 symbol: String,
23 source_tag: String,
24 price: Option<f64>,
25 timestamp_ms: u64,
26 },
27 StrategyState {
28 fast_sma: Option<f64>,
29 slow_sma: Option<f64>,
30 },
31 OrderUpdate(OrderUpdate),
32 WsStatus(WsConnectionStatus),
33 HistoricalCandles {
34 candles: Vec<Candle>,
35 interval_ms: u64,
36 interval: String,
37 },
38 BalanceUpdate(HashMap<String, f64>),
39 OrderHistoryUpdate(OrderHistorySnapshot),
40 StrategyStatsUpdate {
41 strategy_stats: HashMap<String, OrderHistoryStats>,
42 },
43 EvSnapshotUpdate {
44 symbol: String,
45 source_tag: String,
46 ev: f64,
47 entry_ev: Option<f64>,
48 p_win: f64,
49 gate_mode: String,
50 gate_blocked: bool,
51 },
52 PredictorMetricsUpdate {
53 symbol: String,
54 market: String,
55 predictor: String,
56 horizon: String,
57 r2: Option<f64>,
58 hit_rate: Option<f64>,
59 mae: Option<f64>,
60 sample_count: u64,
61 updated_at_ms: u64,
62 },
63 ExitPolicyUpdate {
64 symbol: String,
65 source_tag: String,
66 stop_price: Option<f64>,
67 expected_holding_ms: Option<u64>,
68 protective_stop_ok: Option<bool>,
69 },
70 AssetPnlUpdate {
71 by_symbol: HashMap<String, AssetPnlEntry>,
72 },
73 RiskRateSnapshot {
74 global: RateBudgetSnapshot,
75 orders: RateBudgetSnapshot,
76 account: RateBudgetSnapshot,
77 market_data: RateBudgetSnapshot,
78 },
79 CloseAllRequested {
80 job_id: u64,
81 total: usize,
82 symbols: Vec<String>,
83 },
84 CloseAllProgress {
85 job_id: u64,
86 symbol: String,
87 completed: usize,
88 total: usize,
89 failed: usize,
90 reason: Option<String>,
91 },
92 CloseAllFinished {
93 job_id: u64,
94 completed: usize,
95 total: usize,
96 failed: usize,
97 },
98 TickDropped,
99 LogRecord(LogRecord),
100 LogMessage(String),
101 Error(String),
102}
103
104#[derive(Debug, Clone, Default)]
105pub struct EvSnapshotEntry {
106 pub ev: f64,
107 pub entry_ev: Option<f64>,
108 pub p_win: f64,
109 pub gate_mode: String,
110 pub gate_blocked: bool,
111 pub updated_at_ms: u64,
112}
113
114#[derive(Debug, Clone, Default)]
115pub struct PredictorMetricEntry {
116 pub symbol: String,
117 pub market: String,
118 pub predictor: String,
119 pub horizon: String,
120 pub r2: Option<f64>,
121 pub hit_rate: Option<f64>,
122 pub mae: Option<f64>,
123 pub sample_count: u64,
124 pub updated_at_ms: u64,
125}
126
127#[derive(Debug, Clone, Default)]
128pub struct ExitPolicyEntry {
129 pub stop_price: Option<f64>,
130 pub expected_holding_ms: Option<u64>,
131 pub protective_stop_ok: Option<bool>,
132 pub updated_at_ms: u64,
133}
134
135#[derive(Debug, Clone, Default)]
136pub struct AssetPnlEntry {
137 pub is_futures: bool,
138 pub side: Option<OrderSide>,
139 pub position_qty: f64,
140 pub entry_price: f64,
141 pub realized_pnl_usdt: f64,
142 pub unrealized_pnl_usdt: f64,
143}
144
145#[derive(Debug, Clone, Copy, PartialEq, Eq)]
146pub enum LogLevel {
147 Debug,
148 Info,
149 Warn,
150 Error,
151}
152
153#[derive(Debug, Clone, Copy, PartialEq, Eq)]
154pub enum LogDomain {
155 Ws,
156 Strategy,
157 Risk,
158 Order,
159 Portfolio,
160 Ui,
161 System,
162}
163
164#[derive(Debug, Clone)]
165pub struct LogRecord {
166 pub ts_ms: u64,
167 pub level: LogLevel,
168 pub domain: LogDomain,
169 pub event: &'static str,
170 pub symbol: Option<String>,
171 pub strategy_tag: Option<String>,
172 pub trace_id: Option<String>,
173 pub msg: String,
174}
175
176impl LogRecord {
177 pub fn new(
178 level: LogLevel,
179 domain: LogDomain,
180 event: &'static str,
181 msg: impl Into<String>,
182 ) -> Self {
183 Self {
184 ts_ms: chrono::Utc::now().timestamp_millis() as u64,
185 level,
186 domain,
187 event,
188 symbol: None,
189 strategy_tag: None,
190 trace_id: None,
191 msg: msg.into(),
192 }
193 }
194}