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 PredictorMetricsUpdate {
44 symbol: String,
45 market: String,
46 predictor: String,
47 horizon: String,
48 r2: Option<f64>,
49 hit_rate: Option<f64>,
50 mae: Option<f64>,
51 sample_count: u64,
52 updated_at_ms: u64,
53 },
54 ExitPolicyUpdate {
55 symbol: String,
56 source_tag: String,
57 stop_price: Option<f64>,
58 expected_holding_ms: Option<u64>,
59 protective_stop_ok: Option<bool>,
60 },
61 PortfolioStateUpdate {
62 snapshot: PortfolioStateSnapshot,
63 },
64 RegimeUpdate {
65 symbol: String,
66 regime: MarketRegimeSignal,
67 },
68 RiskRateSnapshot {
69 global: RateBudgetSnapshot,
70 orders: RateBudgetSnapshot,
71 account: RateBudgetSnapshot,
72 market_data: RateBudgetSnapshot,
73 },
74 CloseAllRequested {
75 job_id: u64,
76 total: usize,
77 symbols: Vec<String>,
78 },
79 CloseAllProgress {
80 job_id: u64,
81 symbol: String,
82 completed: usize,
83 total: usize,
84 failed: usize,
85 reason: Option<String>,
86 },
87 CloseAllFinished {
88 job_id: u64,
89 completed: usize,
90 total: usize,
91 failed: usize,
92 },
93 TickDropped,
94 LogRecord(LogRecord),
95 LogMessage(String),
96 Error(String),
97}
98
99#[derive(Debug, Clone, Default)]
100pub struct PredictorMetricEntry {
101 pub symbol: String,
102 pub market: String,
103 pub predictor: String,
104 pub horizon: String,
105 pub r2: Option<f64>,
106 pub hit_rate: Option<f64>,
107 pub mae: Option<f64>,
108 pub sample_count: u64,
109 pub updated_at_ms: u64,
110}
111
112#[derive(Debug, Clone, Default)]
113pub struct ExitPolicyEntry {
114 pub stop_price: Option<f64>,
115 pub expected_holding_ms: Option<u64>,
116 pub protective_stop_ok: Option<bool>,
117 pub updated_at_ms: u64,
118}
119
120#[derive(Debug, Clone, Default)]
121pub struct AssetPnlEntry {
122 pub is_futures: bool,
123 pub side: Option<OrderSide>,
124 pub position_qty: f64,
125 pub entry_price: f64,
126 pub realized_pnl_usdt: f64,
127 pub unrealized_pnl_usdt: f64,
128}
129
130#[derive(Debug, Clone, Copy, PartialEq, Eq)]
131pub enum MarketRegime {
132 TrendUp,
133 TrendDown,
134 Range,
135 Unknown,
136}
137
138impl Default for MarketRegime {
139 fn default() -> Self {
140 Self::Unknown
141 }
142}
143
144#[derive(Debug, Clone, Copy, Default)]
145pub struct MarketRegimeSignal {
146 pub regime: MarketRegime,
147 pub confidence: f64,
148 pub ema_fast: f64,
149 pub ema_slow: f64,
150 pub vol_ratio: f64,
151 pub slope: f64,
152 pub updated_at_ms: u64,
153}
154
155#[derive(Debug, Clone, Default)]
156pub struct PortfolioStateSnapshot {
157 pub by_symbol: HashMap<String, AssetPnlEntry>,
158 pub total_realized_pnl_usdt: f64,
159 pub total_unrealized_pnl_usdt: f64,
160 pub open_orders_count: usize,
161 pub reserved_cash_usdt: f64,
162 pub gross_exposure_usdt: f64,
163 pub net_exposure_usdt: f64,
164}
165
166#[derive(Debug, Clone, Copy, PartialEq, Eq)]
167pub enum LogLevel {
168 Debug,
169 Info,
170 Warn,
171 Error,
172}
173
174#[derive(Debug, Clone, Copy, PartialEq, Eq)]
175pub enum LogDomain {
176 Ws,
177 Strategy,
178 Risk,
179 Order,
180 Portfolio,
181 Ui,
182 System,
183}
184
185#[derive(Debug, Clone)]
186pub struct LogRecord {
187 pub ts_ms: u64,
188 pub level: LogLevel,
189 pub domain: LogDomain,
190 pub event: &'static str,
191 pub symbol: Option<String>,
192 pub strategy_tag: Option<String>,
193 pub trace_id: Option<String>,
194 pub msg: String,
195}
196
197impl LogRecord {
198 pub fn new(
199 level: LogLevel,
200 domain: LogDomain,
201 event: &'static str,
202 msg: impl Into<String>,
203 ) -> Self {
204 Self {
205 ts_ms: chrono::Utc::now().timestamp_millis() as u64,
206 level,
207 domain,
208 event,
209 symbol: None,
210 strategy_tag: None,
211 trace_id: None,
212 msg: msg.into(),
213 }
214 }
215}