1use chrono::{DateTime, Utc};
6use rust_decimal::Decimal;
7use serde::{Serialize, Deserialize};
8use uuid::Uuid;
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct Observation {
13 pub id: Uuid,
14 pub timestamp_us: i64,
15 pub symbol: String,
16 pub price: Decimal,
17 pub volume: Decimal,
18 pub spread: Decimal,
19 pub book_depth: BookDepth,
20
21 #[serde(skip_serializing_if = "Vec::is_empty", default)]
22 pub embedding: Vec<f32>,
23
24 #[serde(default)]
25 pub metadata: serde_json::Value,
26
27 pub provenance: Provenance,
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize, Default)]
31pub struct BookDepth {
32 pub bids: Vec<(Decimal, Decimal)>,
33 pub asks: Vec<(Decimal, Decimal)>,
34}
35
36impl Observation {
37 pub fn new(symbol: String, price: Decimal, volume: Decimal) -> Self {
38 let id = Uuid::new_v4();
39 let timestamp_us = Utc::now().timestamp_micros();
40
41 Self {
42 id,
43 timestamp_us,
44 symbol,
45 price,
46 volume,
47 spread: Decimal::ZERO,
48 book_depth: BookDepth::default(),
49 embedding: Vec::new(),
50 metadata: serde_json::json!({}),
51 provenance: Provenance::new("market_data_collector"),
52 }
53 }
54
55 pub fn with_embedding(mut self, embedding: Vec<f32>) -> Self {
56 self.embedding = embedding;
57 self
58 }
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
63pub struct Signal {
64 pub id: Uuid,
65 pub strategy_id: String,
66 pub timestamp_us: i64,
67 pub symbol: String,
68 pub direction: Direction,
69 pub confidence: f64,
70 pub features: Vec<f64>,
71 pub reasoning: String,
72 pub causal_links: Vec<Uuid>,
73
74 #[serde(skip_serializing_if = "Vec::is_empty", default)]
75 pub embedding: Vec<f32>,
76
77 pub provenance: Provenance,
78}
79
80#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
81pub enum Direction {
82 Long,
83 Short,
84 Neutral,
85 Close,
86}
87
88impl Signal {
89 pub fn new(strategy_id: String, symbol: String, direction: Direction, confidence: f64) -> Self {
90 Self {
91 id: Uuid::new_v4(),
92 strategy_id,
93 timestamp_us: Utc::now().timestamp_micros(),
94 symbol,
95 direction,
96 confidence,
97 features: Vec::new(),
98 reasoning: String::new(),
99 causal_links: Vec::new(),
100 embedding: Vec::new(),
101 provenance: Provenance::new("strategy_engine"),
102 }
103 }
104
105 pub fn with_embedding(mut self, embedding: Vec<f32>) -> Self {
106 self.embedding = embedding;
107 self
108 }
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize)]
113pub struct Order {
114 pub id: Uuid,
115 pub signal_id: Uuid,
116 pub symbol: String,
117 pub side: OrderSide,
118 pub quantity: u32,
119 pub order_type: OrderType,
120 pub limit_price: Option<Decimal>,
121 pub stop_price: Option<Decimal>,
122 pub status: OrderStatus,
123 pub timestamps: OrderTimestamps,
124 pub fills: Vec<Fill>,
125
126 #[serde(skip_serializing_if = "Vec::is_empty", default)]
127 pub embedding: Vec<f32>,
128
129 pub provenance: Provenance,
130}
131
132#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
133pub enum OrderSide {
134 Buy,
135 Sell,
136}
137
138#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
139pub enum OrderType {
140 Market,
141 Limit,
142 StopLoss,
143 StopLimit,
144}
145
146#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
147pub enum OrderStatus {
148 Pending,
149 Submitted,
150 PartiallyFilled,
151 Filled,
152 Cancelled,
153 Rejected,
154}
155
156#[derive(Debug, Clone, Serialize, Deserialize, Default)]
157pub struct OrderTimestamps {
158 pub created_us: i64,
159 pub submitted_us: Option<i64>,
160 pub first_fill_us: Option<i64>,
161 pub completed_us: Option<i64>,
162}
163
164#[derive(Debug, Clone, Serialize, Deserialize)]
165pub struct Fill {
166 pub timestamp_us: i64,
167 pub quantity: u32,
168 pub price: Decimal,
169 pub fee: Decimal,
170}
171
172impl Order {
173 pub fn new(signal_id: Uuid, symbol: String, side: OrderSide, quantity: u32) -> Self {
174 Self {
175 id: Uuid::new_v4(),
176 signal_id,
177 symbol,
178 side,
179 quantity,
180 order_type: OrderType::Market,
181 limit_price: None,
182 stop_price: None,
183 status: OrderStatus::Pending,
184 timestamps: OrderTimestamps {
185 created_us: Utc::now().timestamp_micros(),
186 ..Default::default()
187 },
188 fills: Vec::new(),
189 embedding: Vec::new(),
190 provenance: Provenance::new("order_manager"),
191 }
192 }
193
194 pub fn with_embedding(mut self, embedding: Vec<f32>) -> Self {
195 self.embedding = embedding;
196 self
197 }
198}
199
200#[derive(Debug, Clone, Serialize, Deserialize)]
202pub struct ReflexionTrace {
203 pub id: Uuid,
204 pub decision_id: Uuid,
205 pub decision_type: DecisionType,
206 pub trajectory: Vec<StateAction>,
207 pub verdict: Verdict,
208 pub learned_patterns: Vec<Pattern>,
209 pub counterfactuals: Vec<Counterfactual>,
210
211 #[serde(skip_serializing_if = "Vec::is_empty", default)]
212 pub embedding: Vec<f32>,
213
214 pub provenance: Provenance,
215}
216
217#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
218pub enum DecisionType {
219 Signal,
220 Order,
221 StrategySwitch,
222 RiskLimit,
223}
224
225#[derive(Debug, Clone, Serialize, Deserialize)]
226pub struct StateAction {
227 pub timestamp_us: i64,
228 pub state: PortfolioState,
229 pub action: TradingAction,
230 pub reward: f64,
231}
232
233#[derive(Debug, Clone, Serialize, Deserialize)]
234pub struct PortfolioState {
235 pub cash: Decimal,
236 pub unrealized_pnl: Decimal,
237 pub market_features: Vec<f64>,
238}
239
240#[derive(Debug, Clone, Serialize, Deserialize)]
241pub struct TradingAction {
242 pub action_type: ActionType,
243 pub symbol: String,
244 pub quantity: u32,
245}
246
247#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
248pub enum ActionType {
249 Buy,
250 Sell,
251 Hold,
252 ClosePosition,
253}
254
255#[derive(Debug, Clone, Serialize, Deserialize)]
256pub struct Verdict {
257 pub score: f64,
258 pub roi: f64,
259 pub sharpe: f64,
260 pub max_drawdown: f64,
261 pub explanation: String,
262 pub successes: Vec<String>,
263 pub failures: Vec<String>,
264}
265
266#[derive(Debug, Clone, Serialize, Deserialize)]
267pub struct Pattern {
268 pub pattern_type: PatternType,
269 pub description: String,
270 pub confidence: f64,
271 pub occurrences: usize,
272 pub embedding: Vec<f32>,
273}
274
275#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
276pub enum PatternType {
277 EntryTiming,
278 ExitTiming,
279 RiskManagement,
280 MarketRegime,
281 Correlation,
282}
283
284#[derive(Debug, Clone, Serialize, Deserialize)]
285pub struct Counterfactual {
286 pub description: String,
287 pub alternative_action: TradingAction,
288 pub estimated_outcome: f64,
289 pub probability: f64,
290}
291
292#[derive(Debug, Clone, Serialize, Deserialize)]
294pub struct Provenance {
295 pub creator: String,
296 pub created_us: i64,
297 pub parent_id: Option<Uuid>,
298
299 #[serde(skip_serializing_if = "Vec::is_empty", default)]
300 pub signature: Vec<u8>,
301
302 #[serde(skip_serializing_if = "Vec::is_empty", default)]
303 pub public_key: Vec<u8>,
304
305 #[serde(skip_serializing_if = "Vec::is_empty", default)]
306 pub hash: Vec<u8>,
307}
308
309impl Provenance {
310 pub fn new(creator: &str) -> Self {
311 Self {
312 creator: creator.to_string(),
313 created_us: Utc::now().timestamp_micros(),
314 parent_id: None,
315 signature: Vec::new(),
316 public_key: Vec::new(),
317 hash: Vec::new(),
318 }
319 }
320
321 pub fn with_parent(mut self, parent_id: Uuid) -> Self {
322 self.parent_id = Some(parent_id);
323 self
324 }
325}
326
327#[cfg(test)]
328mod tests {
329 use super::*;
330 use rust_decimal_macros::dec;
331
332 #[test]
333 fn test_observation_creation() {
334 let obs = Observation::new("AAPL".to_string(), dec!(150.00), dec!(1000));
335
336 assert_eq!(obs.symbol, "AAPL");
337 assert_eq!(obs.price, dec!(150.00));
338 assert_eq!(obs.volume, dec!(1000));
339 }
340
341 #[test]
342 fn test_signal_creation() {
343 let signal = Signal::new(
344 "momentum_v1".to_string(),
345 "AAPL".to_string(),
346 Direction::Long,
347 0.85,
348 );
349
350 assert_eq!(signal.strategy_id, "momentum_v1");
351 assert_eq!(signal.direction, Direction::Long);
352 assert_eq!(signal.confidence, 0.85);
353 }
354
355 #[test]
356 fn test_order_creation() {
357 let signal_id = Uuid::new_v4();
358 let order = Order::new(signal_id, "AAPL".to_string(), OrderSide::Buy, 100);
359
360 assert_eq!(order.signal_id, signal_id);
361 assert_eq!(order.quantity, 100);
362 assert_eq!(order.status, OrderStatus::Pending);
363 }
364
365 #[test]
366 fn test_provenance_with_parent() {
367 let parent_id = Uuid::new_v4();
368 let provenance = Provenance::new("test_creator").with_parent(parent_id);
369
370 assert_eq!(provenance.creator, "test_creator");
371 assert_eq!(provenance.parent_id, Some(parent_id));
372 }
373}