Coverage Report

Created: 2025-10-06 12:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/home/jgrusewski/Work/foxhunt/common/src/types.rs
Line
Count
Source
1
//! Common data types used across services
2
//!
3
//! This module provides shared data types that are used throughout
4
//! the Foxhunt HFT trading system. This includes both infrastructure types
5
//! and core trading types migrated from foxhunt-common-types.
6
7
use crate::error::ErrorCategory;
8
use chrono::{DateTime, Utc};
9
// ELIMINATED: Re-exports removed to force explicit imports
10
// NO RE-EXPORTS: Import rust_decimal::Decimal directly in each crate that needs it
11
use rust_decimal::Decimal; // Internal use only - other crates must import directly
12
use serde::{Deserialize, Serialize};
13
use serde_json::Value;
14
use std::collections::HashMap;
15
use std::sync::{Arc, Mutex, RwLock};
16
17
use crate::error::{CommonError, ErrorCategory as CommonErrorCategory};
18
use num_traits::FromPrimitive;
19
use std::convert::TryFrom;
20
use std::fmt;
21
use std::iter::Sum;
22
use std::num::ParseIntError;
23
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
24
use std::str::FromStr;
25
use uuid::Uuid;
26
27
// =============================================================================
28
// Type Aliases for Complex Types
29
// =============================================================================
30
31
/// Common error type for async operations
32
pub type AsyncResult<T> = Result<T, Box<dyn std::error::Error + Send + Sync>>;
33
34
/// Thread-safe hash map for shared state
35
pub type SharedHashMap<K, V> = Arc<RwLock<HashMap<K, V>>>;
36
37
/// Thread-safe hash map with Mutex for shared state
38
pub type MutexHashMap<K, V> = Arc<Mutex<HashMap<K, V>>>;
39
40
/// Thread-safe container for any value
41
pub type SharedValue<T> = Arc<RwLock<T>>;
42
43
/// Thread-safe container with Mutex for any value
44
pub type MutexValue<T> = Arc<Mutex<T>>;
45
46
// Trading-specific type aliases
47
/// Map of positions by symbol
48
pub type PositionMap<T> = SharedHashMap<String, T>;
49
50
/// Map of orders by order ID
51
pub type OrderMap<T> = SharedHashMap<String, T>;
52
53
/// Map of accounts by account ID
54
pub type AccountMap<T> = SharedHashMap<String, T>;
55
56
/// Map of instruments by instrument ID
57
pub type InstrumentMap<T> = SharedHashMap<String, T>;
58
59
/// Map of market data by symbol
60
pub type MarketDataMap<T> = SharedHashMap<String, T>;
61
62
/// Cache entry with timestamp
63
pub type CacheEntry<T> = (T, DateTime<Utc>);
64
65
/// Cache map with timestamped entries
66
pub type CacheMap<K, V> = SharedHashMap<K, CacheEntry<V>>;
67
68
/// Risk factor loadings by instrument
69
pub type RiskFactorMap = SharedHashMap<String, HashMap<String, Decimal>>;
70
71
/// Performance metrics history
72
pub type PerformanceHistory<T> = SharedHashMap<String, std::collections::VecDeque<T>>;
73
74
/// Model registry for ML models
75
pub type ModelRegistry<T> = SharedHashMap<String, T>;
76
77
/// Generic configuration cache
78
pub type ConfigCache<K, V> = SharedHashMap<K, V>;
79
80
// =============================================================================
81
// Event Types - Moved from trading_engine to enforce pure client architecture
82
// =============================================================================
83
84
/// Order events for the complete order lifecycle
85
#[derive(Debug, Clone, Serialize, Deserialize)]
86
pub struct OrderEvent {
87
    /// Unique identifier for the order
88
    pub order_id: OrderId,
89
    /// Trading symbol for the order
90
    pub symbol: Symbol,
91
    /// Type of order (market, limit, stop, etc.)
92
    pub order_type: OrderType,
93
    /// Order side (buy or sell)
94
    pub side: OrderSide,
95
    /// Order quantity
96
    pub quantity: Quantity,
97
    /// Order price (None for market orders)
98
    pub price: Option<Price>,
99
    /// Timestamp when the event occurred
100
    pub timestamp: DateTime<Utc>,
101
    /// Strategy or client identifier
102
    pub strategy_id: String,
103
    /// Order event type (placed, modified, cancelled)
104
    pub event_type: OrderEventType,
105
    /// Previous quantity for modifications
106
    pub previous_quantity: Option<Quantity>,
107
    /// Previous price for modifications
108
    pub previous_price: Option<Price>,
109
    /// Reason for cancellation or modification
110
    pub reason: Option<String>,
111
}
112
113
/// Types of order events
114
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
115
pub enum OrderEventType {
116
    /// Order was placed
117
    Placed,
118
    /// Order was modified
119
    Modified,
120
    /// Order was cancelled
121
    Cancelled,
122
    /// Order was rejected
123
    Rejected,
124
}
125
126
// =============================================================================
127
// Core Data Types
128
// =============================================================================
129
130
/// Unique identifier for services
131
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
132
pub struct ServiceId(pub String);
133
134
impl ServiceId {
135
    /// Create a new service ID
136
2
    pub fn new<S: Into<String>>(id: S) -> Self {
137
2
        Self(id.into())
138
2
    }
139
140
    /// Get the inner string value
141
    /// Get the execution ID as a string slice
142
    /// Get execution ID as string slice
143
2
    pub fn as_str(&self) -> &str {
144
2
        &self.0
145
2
    }
146
}
147
148
impl fmt::Display for ServiceId {
149
1
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150
1
        write!(f, "{}", self.0)
151
1
    }
152
}
153
154
impl From<&str> for ServiceId {
155
0
    fn from(s: &str) -> Self {
156
0
        Self(s.to_owned())
157
0
    }
158
}
159
160
impl From<String> for ServiceId {
161
1
    fn from(s: String) -> Self {
162
1
        Self(s)
163
1
    }
164
}
165
166
/// Service status enumeration
167
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
168
pub enum ServiceStatus {
169
    /// Service is starting up
170
    Starting,
171
    /// Service is running normally
172
    Running,
173
    /// Service is degraded but functional
174
    Degraded,
175
    /// Service is stopping
176
    Stopping,
177
    /// Service is stopped
178
    Stopped,
179
    /// Service has encountered an error
180
    Error,
181
    /// Service is in maintenance mode
182
    Maintenance,
183
}
184
185
impl fmt::Display for ServiceStatus {
186
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187
0
        match self {
188
0
            Self::Starting => write!(f, "STARTING"),
189
0
            Self::Running => write!(f, "RUNNING"),
190
0
            Self::Degraded => write!(f, "DEGRADED"),
191
0
            Self::Stopping => write!(f, "STOPPING"),
192
0
            Self::Stopped => write!(f, "STOPPED"),
193
0
            Self::Error => write!(f, "ERROR"),
194
0
            Self::Maintenance => write!(f, "MAINTENANCE"),
195
        }
196
0
    }
197
}
198
199
impl ServiceStatus {
200
    /// Check if the service is healthy
201
4
    pub fn is_healthy(&self) -> bool {
202
4
        
matches!2
(self, Self::Running | Self::Starting)
203
4
    }
204
205
    /// Check if the service is available for requests
206
4
    pub fn is_available(&self) -> bool {
207
4
        
matches!2
(self, Self::Running | Self::Degraded)
208
4
    }
209
}
210
211
/// Configuration version for tracking changes
212
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
213
pub struct ConfigVersion {
214
    /// Version number
215
    pub version: u64,
216
    /// Timestamp when version was created
217
    pub timestamp: DateTime<Utc>,
218
    /// Optional description of changes
219
    pub description: Option<String>,
220
}
221
222
impl ConfigVersion {
223
    /// Create a new config version
224
1
    pub fn new(version: u64) -> Self {
225
1
        Self {
226
1
            version,
227
1
            timestamp: Utc::now(),
228
1
            description: None,
229
1
        }
230
1
    }
231
232
    /// Create a new config version with description
233
1
    pub fn with_description<S: Into<String>>(version: u64, description: S) -> Self {
234
1
        Self {
235
1
            version,
236
1
            timestamp: Utc::now(),
237
1
            description: Some(description.into()),
238
1
        }
239
1
    }
240
}
241
242
// TECHNICAL DEBT ELIMINATED - Use DateTime<Utc> directly instead of Timestamp alias
243
244
/// Timestamp type alias for consistency across the system
245
pub type Timestamp = DateTime<Utc>;
246
247
/// Request ID for tracing and correlation
248
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
249
pub struct RequestId(pub Uuid);
250
251
impl Default for RequestId {
252
    /// Create a default request ID with a new UUID
253
0
    fn default() -> Self {
254
0
        Self::new()
255
0
    }
256
}
257
258
impl RequestId {
259
    /// Generate a new random request ID
260
2
    pub fn new() -> Self {
261
2
        Self(Uuid::new_v4())
262
2
    }
263
264
    /// Create from UUID
265
0
    pub fn from_uuid(uuid: Uuid) -> Self {
266
0
        Self(uuid)
267
0
    }
268
269
    /// Get the inner UUID
270
0
    pub fn as_uuid(&self) -> Uuid {
271
0
        self.0
272
0
    }
273
}
274
275
// Default implementation is now in the derive macro above
276
277
// =============================================================================
278
// MARKET DATA EVENT TYPES (Consolidated from data and trading_engine crates)
279
// =============================================================================
280
281
/// Market data event types - CANONICAL DEFINITION
282
#[derive(Debug, Clone, Serialize, Deserialize)]
283
pub enum MarketDataEvent {
284
    /// Quote update (bid/ask)
285
    Quote(QuoteEvent),
286
    /// Trade execution
287
    Trade(TradeEvent),
288
    /// Aggregate trade data
289
    Aggregate(Aggregate),
290
    /// Bar/candle data
291
    Bar(BarEvent),
292
    /// Level 2 market data update
293
    Level2(Level2Update),
294
    /// Market status update
295
    Status(MarketStatus),
296
    /// Connection status updates
297
    ConnectionStatus(ConnectionEvent),
298
    /// Error events with details
299
    Error(ErrorEvent),
300
    /// Order book update
301
    OrderBook(OrderBookEvent),
302
    /// Level 2 order book snapshot
303
    OrderBookL2Snapshot(OrderBookSnapshot),
304
    /// Level 2 order book incremental update
305
    OrderBookL2Update(OrderBookUpdate),
306
}
307
308
/// Quote event structure - CANONICAL DEFINITION
309
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
310
pub struct QuoteEvent {
311
    /// Symbol
312
    pub symbol: String,
313
    /// Bid price
314
    pub bid: Option<Decimal>,
315
    /// Ask price
316
    pub ask: Option<Decimal>,
317
    /// Bid size
318
    pub bid_size: Option<Decimal>,
319
    /// Ask size
320
    pub ask_size: Option<Decimal>,
321
    /// Exchange
322
    pub exchange: Option<String>,
323
    /// Bid exchange
324
    pub bid_exchange: Option<String>,
325
    /// Ask exchange
326
    pub ask_exchange: Option<String>,
327
    /// Quote conditions
328
    pub conditions: Vec<String>,
329
    /// Timestamp
330
    pub timestamp: DateTime<Utc>,
331
    /// Sequence number
332
    pub sequence: u64,
333
}
334
335
impl QuoteEvent {
336
    /// Create a new quote event
337
    #[must_use]
338
6
    pub fn new(symbol: String, timestamp: DateTime<Utc>) -> Self {
339
6
        Self {
340
6
            symbol,
341
6
            bid: None,
342
6
            ask: None,
343
6
            bid_size: None,
344
6
            ask_size: None,
345
6
            exchange: None,
346
6
            bid_exchange: None,
347
6
            ask_exchange: None,
348
6
            conditions: Vec::new(),
349
6
            timestamp,
350
6
            sequence: 0,
351
6
        }
352
6
    }
353
354
    /// Set bid price and size
355
4
    pub fn with_bid(mut self, price: Decimal, size: Decimal) -> Self {
356
4
        self.bid = Some(price);
357
4
        self.bid_size = Some(size);
358
4
        self
359
4
    }
360
361
    /// Set ask price and size
362
4
    pub fn with_ask(mut self, price: Decimal, size: Decimal) -> Self {
363
4
        self.ask = Some(price);
364
4
        self.ask_size = Some(size);
365
4
        self
366
4
    }
367
368
    /// Set exchange
369
1
    pub fn with_exchange<S: Into<String>>(mut self, exchange: S) -> Self {
370
1
        self.exchange = Some(exchange.into());
371
1
        self
372
1
    }
373
374
    /// Set bid exchange
375
0
    pub fn with_bid_exchange<S: Into<String>>(mut self, exchange: S) -> Self {
376
0
        self.bid_exchange = Some(exchange.into());
377
0
        self
378
0
    }
379
380
    /// Set ask exchange
381
0
    pub fn with_ask_exchange<S: Into<String>>(mut self, exchange: S) -> Self {
382
0
        self.ask_exchange = Some(exchange.into());
383
0
        self
384
0
    }
385
386
    /// Add quote condition
387
0
    pub fn with_condition<S: Into<String>>(mut self, condition: S) -> Self {
388
0
        self.conditions.push(condition.into());
389
0
        self
390
0
    }
391
392
    /// Set sequence number
393
1
    pub fn with_sequence(mut self, sequence: u64) -> Self {
394
1
        self.sequence = sequence;
395
1
        self
396
1
    }
397
398
    /// Get mid price
399
1
    pub fn mid_price(&self) -> Option<Decimal> {
400
1
        match (self.bid, self.ask) {
401
1
            (Some(bid), Some(ask)) => Some((bid + ask) / Decimal::from(2)),
402
0
            _ => None,
403
        }
404
1
    }
405
406
    /// Get spread
407
1
    pub fn spread(&self) -> Option<Decimal> {
408
1
        match (self.bid, self.ask) {
409
1
            (Some(bid), Some(ask)) => Some(ask - bid),
410
0
            _ => None,
411
        }
412
1
    }
413
}
414
415
/// Trade event structure - CANONICAL DEFINITION
416
#[derive(Debug, Clone, Serialize, Deserialize)]
417
pub struct TradeEvent {
418
    /// Symbol
419
    pub symbol: String,
420
    /// Trade price
421
    pub price: Decimal,
422
    /// Trade size
423
    pub size: Decimal,
424
    /// Trade ID
425
    pub trade_id: Option<String>,
426
    /// Exchange
427
    pub exchange: Option<String>,
428
    /// Trade conditions
429
    pub conditions: Vec<String>,
430
    /// Timestamp
431
    pub timestamp: DateTime<Utc>,
432
    /// Sequence number
433
    pub sequence: u64,
434
}
435
436
impl TradeEvent {
437
    /// Create a new trade event
438
    #[must_use]
439
4
    pub fn new(symbol: String, price: Decimal, size: Decimal, timestamp: DateTime<Utc>) -> Self {
440
4
        Self {
441
4
            symbol,
442
4
            price,
443
4
            size,
444
4
            trade_id: None,
445
4
            exchange: None,
446
4
            conditions: Vec::new(),
447
4
            timestamp,
448
4
            sequence: 0,
449
4
        }
450
4
    }
451
452
    /// Set trade ID
453
0
    pub fn with_trade_id<S: Into<String>>(mut self, trade_id: S) -> Self {
454
0
        self.trade_id = Some(trade_id.into());
455
0
        self
456
0
    }
457
458
    /// Set exchange
459
0
    pub fn with_exchange<S: Into<String>>(mut self, exchange: S) -> Self {
460
0
        self.exchange = Some(exchange.into());
461
0
        self
462
0
    }
463
464
    /// Add trade condition
465
0
    pub fn with_condition<S: Into<String>>(mut self, condition: S) -> Self {
466
0
        self.conditions.push(condition.into());
467
0
        self
468
0
    }
469
470
    /// Set sequence number
471
0
    pub fn with_sequence(mut self, sequence: u64) -> Self {
472
0
        self.sequence = sequence;
473
0
        self
474
0
    }
475
476
    /// Get notional value
477
1
    pub fn notional_value(&self) -> Decimal {
478
1
        self.price * self.size
479
1
    }
480
}
481
482
/// Aggregate trade data
483
#[derive(Debug, Clone, Serialize, Deserialize)]
484
pub struct Aggregate {
485
    /// Symbol
486
    pub symbol: String,
487
    /// Open price
488
    pub open: Decimal,
489
    /// High price
490
    pub high: Decimal,
491
    /// Low price
492
    pub low: Decimal,
493
    /// Close price
494
    pub close: Decimal,
495
    /// Volume
496
    pub volume: Decimal,
497
    /// Volume weighted average price
498
    pub vwap: Option<Decimal>,
499
    /// Start timestamp
500
    pub start_timestamp: DateTime<Utc>,
501
    /// End timestamp
502
    pub end_timestamp: DateTime<Utc>,
503
}
504
505
/// Bar/candle event structure
506
#[derive(Debug, Clone, Serialize, Deserialize)]
507
pub struct BarEvent {
508
    /// Symbol
509
    pub symbol: String,
510
    /// Open price
511
    pub open: Decimal,
512
    /// High price
513
    pub high: Decimal,
514
    /// Low price
515
    pub low: Decimal,
516
    /// Close price
517
    pub close: Decimal,
518
    /// Volume
519
    pub volume: Decimal,
520
    /// Volume weighted average price
521
    pub vwap: Option<Decimal>,
522
    /// Start timestamp
523
    pub start_timestamp: DateTime<Utc>,
524
    /// End timestamp
525
    pub end_timestamp: DateTime<Utc>,
526
    /// Timeframe (e.g., "1m", "5m", "1h")
527
    pub timeframe: String,
528
}
529
530
/// Level 2 market data update
531
#[derive(Debug, Clone, Serialize, Deserialize)]
532
pub struct Level2Update {
533
    /// Symbol
534
    pub symbol: String,
535
    /// Bid levels
536
    pub bids: Vec<PriceLevel>,
537
    /// Ask levels
538
    pub asks: Vec<PriceLevel>,
539
    /// Timestamp
540
    pub timestamp: DateTime<Utc>,
541
}
542
543
/// Price level for order book
544
#[derive(Debug, Clone, Serialize, Deserialize)]
545
pub struct PriceLevel {
546
    /// Price
547
    pub price: Decimal,
548
    /// Size at this price level
549
    pub size: Decimal,
550
}
551
552
/// Order book snapshot from providers
553
#[derive(Debug, Clone, Serialize, Deserialize)]
554
pub struct OrderBookSnapshot {
555
    /// Symbol
556
    pub symbol: String,
557
    /// Bid levels (price, size) sorted by price descending
558
    pub bids: Vec<PriceLevel>,
559
    /// Ask levels (price, size) sorted by price ascending
560
    pub asks: Vec<PriceLevel>,
561
    /// Exchange
562
    pub exchange: String,
563
    /// Timestamp of snapshot
564
    pub timestamp: DateTime<Utc>,
565
    /// Sequence number
566
    pub sequence: u64,
567
}
568
569
/// Incremental order book update from providers
570
#[derive(Debug, Clone, Serialize, Deserialize)]
571
pub struct OrderBookUpdate {
572
    /// Symbol
573
    pub symbol: String,
574
    /// Changes to bid levels
575
    pub bid_changes: Vec<PriceLevelChange>,
576
    /// Changes to ask levels
577
    pub ask_changes: Vec<PriceLevelChange>,
578
    /// Exchange
579
    pub exchange: String,
580
    /// Timestamp of update
581
    pub timestamp: DateTime<Utc>,
582
    /// Sequence number
583
    pub sequence: u64,
584
}
585
586
/// Change to a price level
587
#[derive(Debug, Clone, Serialize, Deserialize)]
588
pub struct PriceLevelChange {
589
    /// Price level being modified
590
    pub price: Decimal,
591
    /// New size (0 = remove level)
592
    pub size: Decimal,
593
    /// Type of change
594
    pub change_type: PriceLevelChangeType,
595
    /// Side (bid or ask)
596
    pub side: OrderBookSide,
597
}
598
599
/// Type of price level change
600
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
601
pub enum PriceLevelChangeType {
602
    /// Add new price level
603
    Add,
604
    /// Update existing price level
605
    Update,
606
    /// Remove price level
607
    Delete,
608
}
609
610
/// Order book side
611
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
612
pub enum OrderBookSide {
613
    /// Bid side
614
    Bid,
615
    /// Ask side
616
    Ask,
617
}
618
619
/// Market status information
620
#[derive(Debug, Clone, Serialize, Deserialize)]
621
pub struct MarketStatus {
622
    /// Market
623
    pub market: String,
624
    /// Status (open, closed, early_hours, etc.)
625
    pub status: String,
626
    /// Timestamp
627
    pub timestamp: DateTime<Utc>,
628
}
629
630
/// Connection event for status updates
631
#[derive(Debug, Clone, Serialize, Deserialize)]
632
pub struct ConnectionEvent {
633
    /// Provider name
634
    pub provider: String,
635
    /// Connection status
636
    pub status: ConnectionStatus,
637
    /// Optional message
638
    pub message: Option<String>,
639
    /// Timestamp
640
    pub timestamp: DateTime<Utc>,
641
}
642
643
/// Connection status enumeration
644
/// Connection status for data providers and brokers
645
#[derive(Debug, Clone, Serialize, Deserialize)]
646
#[cfg_attr(feature = "database", derive(sqlx::Type))]
647
#[cfg_attr(
648
    feature = "database",
649
    sqlx(type_name = "connection_status", rename_all = "snake_case")
650
)]
651
pub enum ConnectionStatus {
652
    /// Successfully connected and operational
653
    Connected,
654
    /// Disconnected from the service
655
    Disconnected,
656
    /// Currently attempting to reconnect
657
    Reconnecting,
658
}
659
660
/// Error event structure
661
#[derive(Debug, Clone, Serialize, Deserialize)]
662
pub struct ErrorEvent {
663
    /// Provider name
664
    pub provider: String,
665
    /// Error message
666
    pub message: String,
667
    /// Error category
668
    pub category: ErrorCategory,
669
    /// Timestamp
670
    pub timestamp: DateTime<Utc>,
671
}
672
673
// ErrorCategory is imported from crate::error as CommonErrorCategory
674
675
/// Order book event
676
#[derive(Debug, Clone, Serialize, Deserialize)]
677
pub struct OrderBookEvent {
678
    /// Symbol
679
    pub symbol: String,
680
    /// Timestamp
681
    pub timestamp: DateTime<Utc>,
682
    /// Bid levels
683
    pub bids: Vec<(Price, Quantity)>,
684
    /// Ask levels
685
    pub asks: Vec<(Price, Quantity)>,
686
}
687
688
/// Data types for subscription
689
#[derive(Debug, Clone, Serialize, Deserialize)]
690
pub enum DataType {
691
    /// Real-time quotes
692
    Quotes,
693
    /// Real-time trades
694
    Trades,
695
    /// Aggregate/minute bars
696
    Aggregates,
697
    /// Level 2 order book
698
    Level2,
699
    /// Market status
700
    Status,
701
    /// Historical bars/aggregates
702
    Bars,
703
    /// Order book data
704
    OrderBook,
705
    /// Volume data
706
    Volume,
707
}
708
709
/// Market data subscription request
710
#[derive(Debug, Clone, Serialize, Deserialize)]
711
pub struct Subscription {
712
    /// Symbols to subscribe to
713
    pub symbols: Vec<String>,
714
    /// Data types to subscribe to
715
    pub data_types: Vec<DataType>,
716
    /// Exchange filter (optional)
717
    pub exchanges: Vec<String>,
718
}
719
720
impl MarketDataEvent {
721
    /// Get the symbol for any market data event
722
1
    pub fn symbol(&self) -> &str {
723
1
        match self {
724
1
            MarketDataEvent::Quote(q) => &q.symbol,
725
0
            MarketDataEvent::Trade(t) => &t.symbol,
726
0
            MarketDataEvent::Aggregate(a) => &a.symbol,
727
0
            MarketDataEvent::Bar(b) => &b.symbol,
728
0
            MarketDataEvent::Level2(l) => &l.symbol,
729
0
            MarketDataEvent::Status(s) => &s.market,
730
0
            MarketDataEvent::ConnectionStatus(_) => "",
731
0
            MarketDataEvent::Error(_) => "",
732
0
            MarketDataEvent::OrderBook(o) => &o.symbol,
733
0
            MarketDataEvent::OrderBookL2Snapshot(s) => &s.symbol,
734
0
            MarketDataEvent::OrderBookL2Update(u) => &u.symbol,
735
        }
736
1
    }
737
738
    /// Get the timestamp for any market data event
739
1
    pub fn timestamp(&self) -> Option<DateTime<Utc>> {
740
1
        match self {
741
0
            MarketDataEvent::Quote(q) => Some(q.timestamp),
742
1
            MarketDataEvent::Trade(t) => Some(t.timestamp),
743
0
            MarketDataEvent::Aggregate(a) => Some(a.end_timestamp),
744
0
            MarketDataEvent::Bar(b) => Some(b.end_timestamp),
745
0
            MarketDataEvent::Level2(l) => Some(l.timestamp),
746
0
            MarketDataEvent::Status(s) => Some(s.timestamp),
747
0
            MarketDataEvent::ConnectionStatus(c) => Some(c.timestamp),
748
0
            MarketDataEvent::Error(e) => Some(e.timestamp),
749
0
            MarketDataEvent::OrderBook(o) => Some(o.timestamp),
750
0
            MarketDataEvent::OrderBookL2Snapshot(s) => Some(s.timestamp),
751
0
            MarketDataEvent::OrderBookL2Update(u) => Some(u.timestamp),
752
        }
753
1
    }
754
}
755
impl fmt::Display for RequestId {
756
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
757
0
        write!(f, "{}", self.0)
758
0
    }
759
}
760
761
/// Connection information for services
762
#[derive(Debug, Clone, Serialize, Deserialize)]
763
pub struct ConnectionInfo {
764
    /// Host address
765
    pub host: String,
766
    /// Port number
767
    pub port: u16,
768
    /// Whether TLS is enabled
769
    pub tls: bool,
770
    /// Connection timeout in milliseconds
771
    pub timeout_ms: u64,
772
}
773
774
impl ConnectionInfo {
775
    /// Create new connection info
776
1
    pub fn new<S: Into<String>>(host: S, port: u16) -> Self {
777
1
        Self {
778
1
            host: host.into(),
779
1
            port,
780
1
            tls: false,
781
1
            timeout_ms: 5000,
782
1
        }
783
1
    }
784
785
    /// Enable TLS
786
1
    pub fn with_tls(mut self) -> Self {
787
1
        self.tls = true;
788
1
        self
789
1
    }
790
791
    /// Set timeout
792
0
    pub fn with_timeout(mut self, timeout_ms: u64) -> Self {
793
0
        self.timeout_ms = timeout_ms;
794
0
        self
795
0
    }
796
797
    /// Get connection URL
798
2
    pub fn url(&self) -> String {
799
2
        let scheme = if self.tls { 
"https"1
} else {
"http"1
};
800
2
        format!("{}://{}:{}", scheme, self.host, self.port)
801
2
    }
802
}
803
804
/// Resource limits for services
805
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
806
pub struct ResourceLimits {
807
    /// Maximum memory usage in bytes
808
    pub max_memory_bytes: Option<u64>,
809
    /// Maximum CPU usage as percentage (0-100)
810
    pub max_cpu_percent: Option<f64>,
811
    /// Maximum number of open file descriptors
812
    pub max_file_descriptors: Option<u32>,
813
    /// Maximum number of network connections
814
    pub max_connections: Option<u32>,
815
}
816
817
// =============================================================================
818
// TRADING TYPES (Migrated from foxhunt-common-types)
819
// =============================================================================
820
821
/// Common error types for trading operations
822
///
823
/// This error type implements Send + Sync for use in async contexts
824
#[derive(thiserror::Error, Debug)]
825
pub enum CommonTypeError {
826
    /// Invalid price value
827
    #[error("Invalid price: {value} - {reason}")]
828
    InvalidPrice {
829
        /// The invalid price value as string
830
        value: String,
831
        /// Reason why the price is invalid
832
        reason: String,
833
    },
834
835
    /// Invalid quantity value
836
    #[error("Invalid quantity: {value} - {reason}")]
837
    InvalidQuantity {
838
        /// The invalid quantity value as string
839
        value: String,
840
        /// Reason why the quantity is invalid
841
        reason: String,
842
    },
843
844
    /// Invalid identifier
845
    #[error("Invalid {field}: {reason}")]
846
    InvalidIdentifier {
847
        /// The field name that contains the invalid identifier
848
        field: String,
849
        /// Reason why the identifier is invalid
850
        reason: String,
851
    },
852
853
    /// Validation error
854
    #[error("Validation error for {field}: {reason}")]
855
    ValidationError {
856
        /// The field name that failed validation
857
        field: String,
858
        /// Reason why the validation failed
859
        reason: String,
860
    },
861
862
    /// Conversion error
863
    #[error("Conversion error: {message}")]
864
    ConversionError {
865
        /// Detailed error message describing the conversion failure
866
        message: String,
867
    },
868
869
    /// I/O error
870
    #[error("I/O error: {0}")]
871
    IoError(#[from] std::io::Error),
872
873
    /// JSON serialization/deserialization error
874
    #[error("JSON error: {0}")]
875
    JsonError(#[from] serde_json::Error),
876
877
    /// Float parsing error
878
    #[error("Float parsing error: {0}")]
879
    ParseFloatError(#[from] std::num::ParseFloatError),
880
881
    /// Integer parsing error
882
    #[error("Integer parsing error: {0}")]
883
    ParseIntError(#[from] std::num::ParseIntError),
884
}
885
886
// Manual trait implementations for CommonTypeError
887
// (Cannot derive Clone, PartialEq, Eq, Serialize due to std::io::Error and serde_json::Error)
888
889
impl Clone for CommonTypeError {
890
    /// Clone the error, converting IO and JSON errors to conversion errors
891
2
    fn clone(&self) -> Self {
892
2
        match self {
893
1
            Self::InvalidPrice { value, reason } => Self::InvalidPrice {
894
1
                value: value.clone(),
895
1
                reason: reason.clone(),
896
1
            },
897
0
            Self::InvalidQuantity { value, reason } => Self::InvalidQuantity {
898
0
                value: value.clone(),
899
0
                reason: reason.clone(),
900
0
            },
901
0
            Self::InvalidIdentifier { field, reason } => Self::InvalidIdentifier {
902
0
                field: field.clone(),
903
0
                reason: reason.clone(),
904
0
            },
905
0
            Self::ValidationError { field, reason } => Self::ValidationError {
906
0
                field: field.clone(),
907
0
                reason: reason.clone(),
908
0
            },
909
0
            Self::ConversionError { message } => Self::ConversionError {
910
0
                message: message.clone(),
911
0
            },
912
            // Cannot clone std::io::Error or serde_json::Error, so create new instances
913
1
            Self::IoError(e) => Self::ConversionError {
914
1
                message: format!("I/O error: {}", e),
915
1
            },
916
0
            Self::JsonError(e) => Self::ConversionError {
917
0
                message: format!("JSON error: {}", e),
918
0
            },
919
0
            Self::ParseFloatError(e) => Self::ParseFloatError(e.clone()),
920
0
            Self::ParseIntError(e) => Self::ParseIntError(e.clone()),
921
        }
922
2
    }
923
}
924
impl PartialEq for CommonTypeError {
925
    /// Compare two errors for equality
926
3
    fn eq(&self, other: &Self) -> bool {
927
3
        match (self, other) {
928
            (
929
                Self::InvalidPrice {
930
3
                    value: v1,
931
3
                    reason: r1,
932
                },
933
                Self::InvalidPrice {
934
3
                    value: v2,
935
3
                    reason: r2,
936
                },
937
3
            ) => v1 == v2 && 
r1 == r22
,
938
            (
939
                Self::InvalidQuantity {
940
0
                    value: v1,
941
0
                    reason: r1,
942
                },
943
                Self::InvalidQuantity {
944
0
                    value: v2,
945
0
                    reason: r2,
946
                },
947
0
            ) => v1 == v2 && r1 == r2,
948
            (
949
                Self::InvalidIdentifier {
950
0
                    field: f1,
951
0
                    reason: r1,
952
                },
953
                Self::InvalidIdentifier {
954
0
                    field: f2,
955
0
                    reason: r2,
956
                },
957
0
            ) => f1 == f2 && r1 == r2,
958
            (
959
                Self::ValidationError {
960
0
                    field: f1,
961
0
                    reason: r1,
962
                },
963
                Self::ValidationError {
964
0
                    field: f2,
965
0
                    reason: r2,
966
                },
967
0
            ) => f1 == f2 && r1 == r2,
968
0
            (Self::ConversionError { message: m1 }, Self::ConversionError { message: m2 }) => {
969
0
                m1 == m2
970
            },
971
0
            (Self::ParseFloatError(e1), Self::ParseFloatError(e2)) => e1 == e2,
972
0
            (Self::ParseIntError(e1), Self::ParseIntError(e2)) => e1 == e2,
973
            // std::io::Error and serde_json::Error don't implement PartialEq, so they're never equal
974
0
            (Self::IoError(_), Self::IoError(_)) => false,
975
0
            (Self::JsonError(_), Self::JsonError(_)) => false,
976
0
            _ => false,
977
        }
978
3
    }
979
}
980
981
impl Eq for CommonTypeError {}
982
983
// Note: Display is automatically implemented by thiserror::Error derive
984
// based on the #[error("...")] attributes on each variant
985
impl Serialize for CommonTypeError {
986
1
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
987
1
    where
988
1
        S: serde::Serializer,
989
    {
990
        use serde::ser::SerializeStruct;
991
1
        match self {
992
0
            Self::InvalidPrice { value, reason } => {
993
0
                let mut state = serializer.serialize_struct("InvalidPrice", 2)?;
994
0
                state.serialize_field("value", value)?;
995
0
                state.serialize_field("reason", reason)?;
996
0
                state.end()
997
            },
998
0
            Self::InvalidQuantity { value, reason } => {
999
0
                let mut state = serializer.serialize_struct("InvalidQuantity", 2)?;
1000
0
                state.serialize_field("value", value)?;
1001
0
                state.serialize_field("reason", reason)?;
1002
0
                state.end()
1003
            },
1004
0
            Self::InvalidIdentifier { field, reason } => {
1005
0
                let mut state = serializer.serialize_struct("InvalidIdentifier", 2)?;
1006
0
                state.serialize_field("field", field)?;
1007
0
                state.serialize_field("reason", reason)?;
1008
0
                state.end()
1009
            },
1010
1
            Self::ValidationError { field, reason } => {
1011
1
                let mut state = serializer.serialize_struct("ValidationError", 2)
?0
;
1012
1
                state.serialize_field("field", field)
?0
;
1013
1
                state.serialize_field("reason", reason)
?0
;
1014
1
                state.end()
1015
            },
1016
0
            Self::ConversionError { message } => {
1017
0
                let mut state = serializer.serialize_struct("ConversionError", 1)?;
1018
0
                state.serialize_field("message", message)?;
1019
0
                state.end()
1020
            },
1021
0
            Self::IoError(e) => {
1022
0
                let mut state = serializer.serialize_struct("IoError", 1)?;
1023
0
                state.serialize_field("message", &format!("I/O error: {}", e))?;
1024
0
                state.end()
1025
            },
1026
0
            Self::JsonError(e) => {
1027
0
                let mut state = serializer.serialize_struct("JsonError", 1)?;
1028
0
                state.serialize_field("message", &format!("JSON error: {}", e))?;
1029
0
                state.end()
1030
            },
1031
0
            Self::ParseFloatError(e) => {
1032
0
                let mut state = serializer.serialize_struct("ParseFloatError", 1)?;
1033
0
                state.serialize_field("message", &format!("Float parsing error: {}", e))?;
1034
0
                state.end()
1035
            },
1036
0
            Self::ParseIntError(e) => {
1037
0
                let mut state = serializer.serialize_struct("ParseIntError", 1)?;
1038
0
                state.serialize_field("message", &format!("Integer parsing error: {}", e))?;
1039
0
                state.end()
1040
            },
1041
        }
1042
1
    }
1043
}
1044
1045
impl<'de> Deserialize<'de> for CommonTypeError {
1046
1
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1047
1
    where
1048
1
        D: serde::Deserializer<'de>,
1049
    {
1050
        // For deserialization, we'll convert everything to ConversionError since
1051
        // we can't reconstruct std::io::Error or serde_json::Error from serialized form
1052
        use serde::de::{MapAccess, Visitor};
1053
        use std::fmt;
1054
1055
        struct CommonTypeErrorVisitor;
1056
1057
        impl<'de> Visitor<'de> for CommonTypeErrorVisitor {
1058
            type Value = CommonTypeError;
1059
1060
0
            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1061
0
                formatter.write_str("a CommonTypeError")
1062
0
            }
1063
1064
1
            fn visit_map<V>(self, mut map: V) -> Result<CommonTypeError, V::Error>
1065
1
            where
1066
1
                V: MapAccess<'de>,
1067
            {
1068
                // For simplicity, deserialize everything as ConversionError
1069
1
                let mut message = String::new();
1070
3
                while let Some(
key2
) = map.next_key::<String>()
?0
{
1071
2
                    let value: serde_json::Value = map.next_value()
?0
;
1072
2
                    if key == "message" {
1073
0
                        if let Some(msg) = value.as_str() {
1074
0
                            message = msg.to_string();
1075
0
                        }
1076
2
                    } else {
1077
2
                        message = format!("Deserialized error: {}: {}", key, value);
1078
2
                    }
1079
                }
1080
1
                if message.is_empty() {
1081
0
                    message = "Unknown deserialized error".to_string();
1082
1
                }
1083
1
                Ok(CommonTypeError::ConversionError { message })
1084
1
            }
1085
        }
1086
1087
1
        deserializer.deserialize_struct(
1088
            "CommonTypeError",
1089
1
            &["value", "reason", "field", "message"],
1090
1
            CommonTypeErrorVisitor,
1091
        )
1092
1
    }
1093
}
1094
1095
// =============================================================================
1096
// ORDER TYPES (Moved from trading_engine)
1097
// =============================================================================
1098
1099
/// Order type specifying execution behavior - CANONICAL DEFINITION
1100
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
1101
#[non_exhaustive]
1102
pub enum OrderType {
1103
    /// Market order - executes immediately at current market price
1104
    Market,
1105
    /// Limit order - executes only at specified price or better
1106
    Limit,
1107
    /// Stop order - becomes market order when stop price is reached
1108
    Stop,
1109
    /// Stop-limit order - becomes limit order when stop price is reached
1110
    StopLimit,
1111
    /// Iceberg order - large order split into smaller visible portions
1112
    Iceberg,
1113
    /// Trailing stop order - stop price adjusts with favorable price movement
1114
    TrailingStop,
1115
    /// Hidden order - not displayed in order book
1116
    Hidden,
1117
}
1118
1119
impl fmt::Display for OrderType {
1120
11
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1121
11
        match self {
1122
2
            Self::Market => write!(f, "MARKET"),
1123
2
            Self::Limit => write!(f, "LIMIT"),
1124
2
            Self::Stop => write!(f, "STOP"),
1125
2
            Self::StopLimit => write!(f, "STOP_LIMIT"),
1126
1
            Self::Iceberg => write!(f, "ICEBERG"),
1127
1
            Self::TrailingStop => write!(f, "TRAILING_STOP"),
1128
1
            Self::Hidden => write!(f, "HIDDEN"),
1129
        }
1130
11
    }
1131
}
1132
1133
impl Default for OrderType {
1134
    /// Returns the default order type (Market)
1135
2
    fn default() -> Self {
1136
2
        Self::Market
1137
2
    }
1138
}
1139
1140
impl TryFrom<i32> for OrderType {
1141
    type Error = String;
1142
1143
9
    fn try_from(value: i32) -> Result<Self, Self::Error> {
1144
9
        match value {
1145
2
            0 => Ok(OrderType::Market),
1146
2
            1 => Ok(OrderType::Limit),
1147
2
            2 => Ok(OrderType::Stop),
1148
1
            3 => Ok(OrderType::StopLimit),
1149
0
            4 => Ok(OrderType::Iceberg),
1150
0
            5 => Ok(OrderType::TrailingStop),
1151
0
            6 => Ok(OrderType::Hidden),
1152
2
            _ => Err(format!("Invalid OrderType: {}", value)),
1153
        }
1154
9
    }
1155
}
1156
1157
/// Supported broker types - CANONICAL DEFINITION
1158
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
1159
pub enum BrokerType {
1160
    /// Interactive Brokers TWS/API
1161
    InteractiveBrokers,
1162
    /// IC Markets FIX API
1163
    ICMarkets,
1164
    /// Paper trading simulation
1165
    PaperTrading,
1166
    /// Demo/Test broker
1167
    Demo,
1168
}
1169
1170
impl Default for BrokerType {
1171
    /// Returns the default broker type (InteractiveBrokers)
1172
1
    fn default() -> Self {
1173
1
        Self::InteractiveBrokers
1174
1
    }
1175
}
1176
1177
/// Order status throughout its lifecycle - CANONICAL DEFINITION
1178
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
1179
#[non_exhaustive]
1180
pub enum OrderStatus {
1181
    /// Order has been created but not yet submitted to broker
1182
    Created,
1183
    /// Order has been submitted to broker for execution
1184
    Submitted,
1185
    /// Order has been partially executed with remaining quantity
1186
    PartiallyFilled,
1187
    /// Order has been completely executed
1188
    Filled,
1189
    /// Order was rejected by broker or exchange
1190
    Rejected,
1191
    /// Order was cancelled by user or system
1192
    Cancelled,
1193
    /// New order accepted by broker
1194
    New,
1195
    /// Order expired due to time restrictions
1196
    Expired,
1197
    /// Order is pending broker acceptance
1198
    Pending,
1199
    /// Order is actively working in the market
1200
    Working,
1201
    /// Order status is unknown or not yet determined
1202
    Unknown,
1203
    /// Order is temporarily suspended
1204
    Suspended,
1205
    /// Order cancellation is pending
1206
    PendingCancel,
1207
    /// Order modification is pending
1208
    PendingReplace,
1209
}
1210
impl fmt::Display for OrderStatus {
1211
9
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1212
9
        match self {
1213
2
            Self::Created => write!(f, "CREATED"),
1214
1
            Self::Submitted => write!(f, "SUBMITTED"),
1215
1
            Self::PartiallyFilled => write!(f, "PARTIALLY_FILLED"),
1216
2
            Self::Filled => write!(f, "FILLED"),
1217
1
            Self::Rejected => write!(f, "REJECTED"),
1218
2
            Self::Cancelled => write!(f, "CANCELLED"),
1219
0
            Self::New => write!(f, "NEW"),
1220
0
            Self::Expired => write!(f, "EXPIRED"),
1221
0
            Self::Pending => write!(f, "PENDING"),
1222
0
            Self::Working => write!(f, "WORKING"),
1223
0
            Self::Unknown => write!(f, "UNKNOWN"),
1224
0
            Self::Suspended => write!(f, "SUSPENDED"),
1225
0
            Self::PendingCancel => write!(f, "PENDING_CANCEL"),
1226
0
            Self::PendingReplace => write!(f, "PENDING_REPLACE"),
1227
        }
1228
9
    }
1229
}
1230
1231
impl Default for OrderStatus {
1232
    /// Returns the default order status (Created)
1233
0
    fn default() -> Self {
1234
0
        Self::Created
1235
0
    }
1236
}
1237
1238
impl TryFrom<i32> for OrderStatus {
1239
    type Error = String;
1240
1241
8
    fn try_from(value: i32) -> Result<Self, Self::Error> {
1242
8
        match value {
1243
2
            0 => Ok(OrderStatus::Created),
1244
0
            1 => Ok(OrderStatus::Submitted),
1245
0
            2 => Ok(OrderStatus::PartiallyFilled),
1246
2
            3 => Ok(OrderStatus::Filled),
1247
0
            4 => Ok(OrderStatus::Rejected),
1248
2
            5 => Ok(OrderStatus::Cancelled),
1249
0
            6 => Ok(OrderStatus::New),
1250
0
            7 => Ok(OrderStatus::Expired),
1251
0
            8 => Ok(OrderStatus::Pending),
1252
0
            9 => Ok(OrderStatus::Working),
1253
0
            10 => Ok(OrderStatus::Unknown),
1254
0
            11 => Ok(OrderStatus::Suspended),
1255
0
            12 => Ok(OrderStatus::PendingCancel),
1256
0
            13 => Ok(OrderStatus::PendingReplace),
1257
2
            _ => Err(format!("Invalid OrderStatus: {}", value)),
1258
        }
1259
8
    }
1260
}
1261
1262
/// Order side - whether the order is a buy or sell - CANONICAL DEFINITION
1263
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
1264
pub enum OrderSide {
1265
    /// Buy order - purchasing securities
1266
    Buy,
1267
    /// Sell order - selling securities
1268
    Sell,
1269
}
1270
1271
impl fmt::Display for OrderSide {
1272
4
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1273
4
        match self {
1274
2
            Self::Buy => write!(f, "BUY"),
1275
2
            Self::Sell => write!(f, "SELL"),
1276
        }
1277
4
    }
1278
}
1279
1280
impl Default for OrderSide {
1281
    /// Returns the default order side (Buy)
1282
1
    fn default() -> Self {
1283
1
        Self::Buy
1284
1
    }
1285
}
1286
1287
impl TryFrom<i32> for OrderSide {
1288
    type Error = String;
1289
1290
6
    fn try_from(value: i32) -> Result<Self, Self::Error> {
1291
6
        match value {
1292
2
            0 => Ok(OrderSide::Buy),
1293
2
            1 => Ok(OrderSide::Sell),
1294
2
            _ => Err(format!("Invalid OrderSide: {}", value)),
1295
        }
1296
6
    }
1297
}
1298
1299
// REMOVED: Side alias - use OrderSide directly
1300
1301
/// Currency enumeration - CANONICAL DEFINITION
1302
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
1303
#[cfg_attr(feature = "database", derive(sqlx::Type))]
1304
pub enum Currency {
1305
    /// US Dollar
1306
    USD,
1307
    /// Euro
1308
    EUR,
1309
    /// British Pound Sterling
1310
    GBP,
1311
    /// Japanese Yen
1312
    JPY,
1313
    /// Swiss Franc
1314
    CHF,
1315
    /// Canadian Dollar
1316
    CAD,
1317
    /// Australian Dollar
1318
    AUD,
1319
    /// New Zealand Dollar
1320
    NZD,
1321
    /// Bitcoin
1322
    BTC,
1323
    /// Ethereum
1324
    ETH,
1325
}
1326
1327
impl fmt::Display for Currency {
1328
11
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1329
11
        match self {
1330
4
            Self::USD => write!(f, "USD"),
1331
2
            Self::EUR => write!(f, "EUR"),
1332
1
            Self::GBP => write!(f, "GBP"),
1333
1
            Self::JPY => write!(f, "JPY"),
1334
0
            Self::CHF => write!(f, "CHF"),
1335
0
            Self::CAD => write!(f, "CAD"),
1336
0
            Self::AUD => write!(f, "AUD"),
1337
0
            Self::NZD => write!(f, "NZD"),
1338
2
            Self::BTC => write!(f, "BTC"),
1339
1
            Self::ETH => write!(f, "ETH"),
1340
        }
1341
11
    }
1342
}
1343
1344
impl Default for Currency {
1345
    /// Returns the default currency (USD)
1346
2
    fn default() -> Self {
1347
2
        Self::USD
1348
2
    }
1349
}
1350
1351
/// Time in force enumeration - CANONICAL DEFINITION
1352
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
1353
pub enum TimeInForce {
1354
    /// Order is valid for the current trading day only
1355
    Day,
1356
    /// Order remains active until explicitly cancelled
1357
    GoodTillCancel,
1358
    /// Order must be executed immediately or cancelled
1359
    ImmediateOrCancel,
1360
    /// Order must be executed completely or cancelled
1361
    FillOrKill,
1362
}
1363
1364
impl fmt::Display for TimeInForce {
1365
8
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1366
8
        match self {
1367
2
            Self::Day => write!(f, "DAY"),
1368
2
            Self::GoodTillCancel => write!(f, "GTC"),
1369
2
            Self::ImmediateOrCancel => write!(f, "IOC"),
1370
2
            Self::FillOrKill => write!(f, "FOK"),
1371
        }
1372
8
    }
1373
}
1374
1375
impl Default for TimeInForce {
1376
    /// Returns the default time in force (Day)
1377
15
    fn default() -> Self {
1378
15
        Self::Day
1379
15
    }
1380
}
1381
1382
// =============================================================================
1383
// CORE ID TYPES (MIGRATED FROM TRADING_ENGINE)
1384
// =============================================================================
1385
1386
// Duplicate TradeId removed - using definition from line 1008
1387
1388
/// Event identifier for tracking system events
1389
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
1390
pub struct EventId(String);
1391
1392
impl EventId {
1393
    /// Create a new random event ID
1394
1
    pub fn new() -> Self {
1395
        use uuid::Uuid;
1396
1
        Self(Uuid::new_v4().to_string())
1397
1
    }
1398
1399
    /// Create an event ID from a string, generating new if empty
1400
1
    pub fn from_string<S: Into<String>>(id: S) -> Self {
1401
1
        let id = id.into();
1402
1
        if id.is_empty() {
1403
1
            Self::new() // Generate new ID if empty
1404
        } else {
1405
0
            Self(id)
1406
        }
1407
1
    }
1408
1409
    /// Get the string value of the event ID
1410
1
    pub fn value(&self) -> &str {
1411
1
        &self.0
1412
1
    }
1413
}
1414
1415
impl fmt::Display for EventId {
1416
    /// Format the event ID for display
1417
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1418
0
        write!(f, "{}", self.0)
1419
0
    }
1420
}
1421
1422
impl From<String> for EventId {
1423
    /// Create an EventId from a String
1424
0
    fn from(s: String) -> Self {
1425
0
        Self(s)
1426
0
    }
1427
}
1428
1429
impl Default for EventId {
1430
    /// Create a default EventId with a new UUID
1431
0
    fn default() -> Self {
1432
0
        Self::new()
1433
0
    }
1434
}
1435
1436
/// Fill identifier with validation
1437
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
1438
pub struct FillId(String);
1439
1440
impl FillId {
1441
    /// Create a new fill ID with validation
1442
0
    pub fn new<S: Into<String>>(id: S) -> Result<Self, CommonTypeError> {
1443
0
        let id = id.into();
1444
0
        if id.is_empty() {
1445
0
            return Err(CommonTypeError::ValidationError {
1446
0
                field: "fill_id".to_owned(),
1447
0
                reason: "Fill ID cannot be empty".to_owned(),
1448
0
            });
1449
0
        }
1450
0
        Ok(Self(id))
1451
0
    }
1452
1453
    /// Get the fill ID as a string slice
1454
0
    pub fn as_str(&self) -> &str {
1455
0
        &self.0
1456
0
    }
1457
    /// Convert the fill ID into an owned string
1458
    /// Convert the execution ID into an owned string
1459
    /// Convert execution ID into owned string
1460
0
    pub fn into_string(self) -> String {
1461
0
        self.0
1462
0
    }
1463
}
1464
1465
impl fmt::Display for FillId {
1466
    /// Format the fill ID for display
1467
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1468
0
        write!(f, "{}", self.0)
1469
0
    }
1470
}
1471
1472
/// Aggregate identifier with validation
1473
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
1474
pub struct AggregateId(String);
1475
1476
impl AggregateId {
1477
    /// Create a new aggregate ID with validation
1478
0
    pub fn new<S: Into<String>>(id: S) -> Result<Self, CommonTypeError> {
1479
0
        let id = id.into();
1480
0
        if id.is_empty() {
1481
0
            return Err(CommonTypeError::ValidationError {
1482
0
                field: "aggregate_id".to_owned(),
1483
0
                reason: "Aggregate ID cannot be empty".to_owned(),
1484
0
            });
1485
0
        }
1486
0
        Ok(Self(id))
1487
0
    }
1488
1489
    /// Get the aggregate ID as a string slice
1490
0
    pub fn as_str(&self) -> &str {
1491
0
        &self.0
1492
0
    }
1493
    /// Convert the aggregate ID into an owned string
1494
0
    pub fn into_string(self) -> String {
1495
0
        self.0
1496
0
    }
1497
}
1498
1499
impl fmt::Display for AggregateId {
1500
    /// Format the aggregate ID for display
1501
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1502
0
        write!(f, "{}", self.0)
1503
0
    }
1504
}
1505
1506
/// Asset identifier with validation
1507
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
1508
pub struct AssetId(String);
1509
1510
impl AssetId {
1511
    /// Create a new asset ID with validation
1512
0
    pub fn new<S: Into<String>>(id: S) -> Result<Self, CommonTypeError> {
1513
0
        let id = id.into();
1514
0
        if id.is_empty() {
1515
0
            return Err(CommonTypeError::ValidationError {
1516
0
                field: "asset_id".to_owned(),
1517
0
                reason: "Asset ID cannot be empty".to_owned(),
1518
0
            });
1519
0
        }
1520
0
        Ok(Self(id))
1521
0
    }
1522
1523
    /// Get the asset ID as a string slice
1524
0
    pub fn as_str(&self) -> &str {
1525
0
        &self.0
1526
0
    }
1527
    /// Convert the asset ID into an owned string
1528
0
    pub fn into_string(self) -> String {
1529
0
        self.0
1530
0
    }
1531
}
1532
1533
impl fmt::Display for AssetId {
1534
    /// Format the asset ID for display
1535
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1536
0
        write!(f, "{}", self.0)
1537
0
    }
1538
}
1539
1540
/// Client identifier with validation
1541
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
1542
pub struct ClientId(String);
1543
1544
impl ClientId {
1545
    /// Create a new client ID with validation
1546
0
    pub fn new<S: Into<String>>(id: S) -> Result<Self, CommonTypeError> {
1547
0
        let id = id.into();
1548
0
        if id.is_empty() {
1549
0
            return Err(CommonTypeError::ValidationError {
1550
0
                field: "client_id".to_owned(),
1551
0
                reason: "Client ID cannot be empty".to_owned(),
1552
0
            });
1553
0
        }
1554
0
        Ok(Self(id))
1555
0
    }
1556
1557
    /// Get the client ID as a string slice
1558
0
    pub fn as_str(&self) -> &str {
1559
0
        &self.0
1560
0
    }
1561
    /// Convert the client ID into an owned string
1562
0
    pub fn into_string(self) -> String {
1563
0
        self.0
1564
0
    }
1565
}
1566
1567
impl fmt::Display for ClientId {
1568
    /// Format the client ID for display
1569
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1570
0
        write!(f, "{}", self.0)
1571
0
    }
1572
}
1573
1574
// =============================================================================
1575
// CORE TRADING TYPES - MIGRATED FROM TRADING_ENGINE
1576
// =============================================================================
1577
1578
/// Canonical Order struct - UNIFIED DEFINITION based on Agent 1's comprehensive analysis
1579
/// This represents the single source of truth for Order across all services
1580
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1581
#[cfg_attr(feature = "database", derive(sqlx::FromRow))]
1582
pub struct Order {
1583
    // Core Identity
1584
    /// Unique order identifier
1585
    pub id: OrderId,
1586
    /// Client-provided order identifier
1587
    pub client_order_id: Option<String>,
1588
    /// Broker-assigned order identifier
1589
    pub broker_order_id: Option<String>,
1590
    /// Account identifier for the order
1591
    pub account_id: Option<String>,
1592
1593
    // Trading Details
1594
    /// Trading symbol for the order
1595
    pub symbol: Symbol,
1596
    /// Order side (buy or sell)
1597
    pub side: OrderSide,
1598
    /// Type of order (market, limit, etc.)
1599
    pub order_type: OrderType,
1600
    /// Current status of the order
1601
    pub status: OrderStatus,
1602
    /// Time in force policy
1603
    pub time_in_force: TimeInForce,
1604
1605
    // Quantities & Pricing
1606
    /// Total order quantity
1607
    pub quantity: Quantity,
1608
    /// Limit price for the order
1609
    pub price: Option<Price>,
1610
    /// Stop price for stop orders
1611
    pub stop_price: Option<Price>,
1612
    /// Quantity that has been filled
1613
    pub filled_quantity: Quantity,
1614
    /// Remaining quantity to be filled
1615
    pub remaining_quantity: Quantity,
1616
    /// Average execution price
1617
    pub average_price: Option<Price>,
1618
    /// Alias for average_price for database compatibility
1619
    pub avg_fill_price: Option<Price>,
1620
1621
    // Strategy Fields (from Agent 1)
1622
    /// Parent order ID for iceberg/algo orders
1623
    pub parent_id: Option<String>,
1624
    /// Execution algorithm name
1625
    pub execution_algorithm: Option<String>,
1626
    /// Execution algorithm parameters stored as JSON
1627
    pub execution_params: Value,
1628
1629
    // Risk Management (from Agent 1)
1630
    /// Stop loss price for risk management
1631
    pub stop_loss: Option<Price>,
1632
    /// Take profit price for profit taking
1633
    pub take_profit: Option<Price>,
1634
1635
    // Timestamps
1636
    /// Order creation timestamp
1637
    pub created_at: HftTimestamp,
1638
    /// Last update timestamp
1639
    pub updated_at: Option<HftTimestamp>,
1640
    /// Order expiration timestamp
1641
    pub expires_at: Option<HftTimestamp>,
1642
1643
    // Extensibility
1644
    /// Additional order metadata stored as JSON
1645
    pub metadata: Value,
1646
}
1647
1648
impl Order {
1649
    /// Create a new order with canonical fields
1650
14
    pub fn new(
1651
14
        symbol: Symbol,
1652
14
        side: OrderSide,
1653
14
        quantity: Quantity,
1654
14
        price: Option<Price>,
1655
14
        order_type: OrderType,
1656
14
    ) -> Self {
1657
14
        let now = HftTimestamp::now_or_zero();
1658
14
        Self {
1659
14
            // Core Identity
1660
14
            id: OrderId::new(),
1661
14
            client_order_id: None,
1662
14
            broker_order_id: None,
1663
14
            account_id: None,
1664
14
1665
14
            // Trading Details
1666
14
            symbol,
1667
14
            side,
1668
14
            order_type,
1669
14
            status: OrderStatus::Created,
1670
14
            time_in_force: TimeInForce::default(),
1671
14
1672
14
            // Quantities & Pricing
1673
14
            quantity,
1674
14
            price,
1675
14
            stop_price: None,
1676
14
            filled_quantity: Quantity::ZERO,
1677
14
            remaining_quantity: quantity,
1678
14
            average_price: None,
1679
14
            avg_fill_price: None, // Database compatibility alias
1680
14
1681
14
            // Strategy Fields
1682
14
            parent_id: None,
1683
14
            execution_algorithm: None,
1684
14
            execution_params: serde_json::json!({}),
1685
14
1686
14
            // Risk Management
1687
14
            stop_loss: None,
1688
14
            take_profit: None,
1689
14
1690
14
            // Timestamps
1691
14
            created_at: now,
1692
14
            updated_at: None,
1693
14
            expires_at: None,
1694
14
1695
14
            // Extensibility
1696
14
            metadata: serde_json::json!({}),
1697
14
        }
1698
14
    }
1699
1700
    /// Check if the order is fully filled
1701
12
    pub fn is_filled(&self) -> bool {
1702
12
        self.filled_quantity == self.quantity
1703
12
    }
1704
1705
    /// Check if the order is partially filled
1706
3
    pub fn is_partially_filled(&self) -> bool {
1707
3
        self.filled_quantity > Quantity::ZERO && 
self.filled_quantity < self.quantity2
1708
3
    }
1709
1710
    /// Calculate fill percentage
1711
5
    pub fn fill_percentage(&self) -> f64 {
1712
5
        if self.quantity.is_zero() {
1713
1
            0.0
1714
        } else {
1715
4
            (self.filled_quantity.to_f64() / self.quantity.to_f64()) * 100.0
1716
        }
1717
5
    }
1718
1719
    /// Set client order ID for tracking
1720
1
    pub fn with_client_order_id(mut self, client_order_id: String) -> Self {
1721
1
        self.client_order_id = Some(client_order_id);
1722
1
        self
1723
1
    }
1724
1725
    /// Set account ID
1726
1
    pub fn with_account_id(mut self, account_id: String) -> Self {
1727
1
        self.account_id = Some(account_id);
1728
1
        self
1729
1
    }
1730
1731
    /// Set time in force
1732
1
    pub fn with_time_in_force(mut self, time_in_force: TimeInForce) -> Self {
1733
1
        self.time_in_force = time_in_force;
1734
1
        self
1735
1
    }
1736
1737
    /// Set stop price
1738
0
    pub fn with_stop_price(mut self, stop_price: Price) -> Self {
1739
0
        self.stop_price = Some(stop_price);
1740
0
        self
1741
0
    }
1742
1743
    /// Set execution algorithm
1744
0
    pub fn with_execution_algorithm(mut self, algorithm: String) -> Self {
1745
0
        self.execution_algorithm = Some(algorithm);
1746
0
        self
1747
0
    }
1748
1749
    /// Add execution parameter
1750
0
    pub fn with_execution_param(mut self, key: String, value: f64) -> Self {
1751
0
        if let Some(obj) = self.execution_params.as_object_mut() {
1752
0
            obj.insert(key, serde_json::to_value(value).unwrap_or(Value::Null));
1753
0
        } else {
1754
0
            let mut map = serde_json::Map::new();
1755
0
            map.insert(key, serde_json::to_value(value).unwrap_or(Value::Null));
1756
0
            self.execution_params = Value::Object(map);
1757
0
        }
1758
0
        self
1759
0
    }
1760
1761
    /// Set stop loss
1762
0
    pub fn with_stop_loss(mut self, stop_loss: Price) -> Self {
1763
0
        self.stop_loss = Some(stop_loss);
1764
0
        self
1765
0
    }
1766
1767
    /// Set take profit
1768
0
    pub fn with_take_profit(mut self, take_profit: Price) -> Self {
1769
0
        self.take_profit = Some(take_profit);
1770
0
        self
1771
0
    }
1772
1773
    /// Add metadata
1774
0
    pub fn with_metadata(mut self, key: String, value: String) -> Self {
1775
0
        if let Some(obj) = self.metadata.as_object_mut() {
1776
0
            obj.insert(key, Value::String(value));
1777
0
        } else {
1778
0
            let mut map = serde_json::Map::new();
1779
0
            map.insert(key, Value::String(value));
1780
0
            self.metadata = Value::Object(map);
1781
0
        }
1782
0
        self
1783
0
    }
1784
1785
    /// Update order status and timestamp
1786
10
    pub fn update_status(&mut self, status: OrderStatus) {
1787
10
        self.status = status;
1788
10
        self.updated_at = Some(HftTimestamp::now_or_zero());
1789
10
    }
1790
1791
    /// Fill order with given quantity and price
1792
11
    pub fn fill(
1793
11
        &mut self,
1794
11
        fill_quantity: Quantity,
1795
11
        fill_price: Price,
1796
11
    ) -> Result<(), CommonTypeError> {
1797
11
        if self.filled_quantity + fill_quantity > self.quantity {
1798
1
            return Err(CommonTypeError::ValidationError {
1799
1
                field: "fill_quantity".to_string(),
1800
1
                reason: "Fill quantity exceeds remaining quantity".to_string(),
1801
1
            });
1802
10
        }
1803
1804
        // Update filled quantity
1805
10
        let previous_filled = self.filled_quantity;
1806
10
        self.filled_quantity = self.filled_quantity + fill_quantity;
1807
10
        self.remaining_quantity = self.quantity - self.filled_quantity;
1808
1809
        // Update average price
1810
10
        if let Some(
avg_price5
) = self.average_price {
1811
5
            let total_value = avg_price.to_f64() * previous_filled.to_f64()
1812
5
                + fill_price.to_f64() * fill_quantity.to_f64();
1813
5
            let new_avg = Some(
1814
5
                Price::from_f64(total_value / self.filled_quantity.to_f64()).unwrap_or(fill_price),
1815
5
            );
1816
5
            self.average_price = new_avg;
1817
5
            self.avg_fill_price = new_avg; // Keep in sync
1818
5
        } else {
1819
5
            self.average_price = Some(fill_price);
1820
5
            self.avg_fill_price = Some(fill_price); // Keep in sync
1821
5
        }
1822
1823
        // Update status
1824
10
        if self.is_filled() {
1825
4
            self.update_status(OrderStatus::Filled);
1826
6
        } else {
1827
6
            self.update_status(OrderStatus::PartiallyFilled);
1828
6
        }
1829
1830
10
        Ok(())
1831
11
    }
1832
1833
    /// Create a limit order - convenience constructor
1834
12
    pub fn limit(symbol: Symbol, side: OrderSide, quantity: Quantity, price: Price) -> Self {
1835
12
        Self::new(symbol, side, quantity, Some(price), OrderType::Limit)
1836
12
    }
1837
1838
    /// Create a market order - convenience constructor
1839
1
    pub fn market(symbol: Symbol, side: OrderSide, quantity: Quantity) -> Self {
1840
1
        Self::new(symbol, side, quantity, None, OrderType::Market)
1841
1
    }
1842
1843
    /// Get symbol hash for performance-critical operations
1844
1
    pub fn symbol_hash(&self) -> i64 {
1845
        use std::collections::hash_map::DefaultHasher;
1846
        use std::hash::{Hash, Hasher};
1847
1848
1
        let mut hasher = DefaultHasher::new();
1849
1
        self.symbol.as_str().hash(&mut hasher);
1850
1
        hasher.finish() as i64
1851
1
    }
1852
1853
    /// Get order timestamp
1854
0
    pub fn timestamp(&self) -> HftTimestamp {
1855
0
        self.created_at
1856
0
    }
1857
}
1858
1859
impl Default for Order {
1860
0
    fn default() -> Self {
1861
0
        Self {
1862
0
            id: OrderId::new(),
1863
0
            client_order_id: None,
1864
0
            broker_order_id: None,
1865
0
            account_id: None,
1866
0
1867
0
            symbol: Symbol::from("DEFAULT"),
1868
0
            side: OrderSide::Buy,
1869
0
            order_type: OrderType::Market,
1870
0
            status: OrderStatus::Created,
1871
0
            time_in_force: TimeInForce::Day,
1872
0
1873
0
            quantity: Quantity::ONE,
1874
0
            price: None,
1875
0
            stop_price: None,
1876
0
            filled_quantity: Quantity::ZERO,
1877
0
            remaining_quantity: Quantity::ONE,
1878
0
            average_price: None,
1879
0
            avg_fill_price: None,
1880
0
1881
0
            parent_id: None,
1882
0
            execution_algorithm: None,
1883
0
            execution_params: serde_json::json!({}),
1884
0
1885
0
            stop_loss: None,
1886
0
            take_profit: None,
1887
0
1888
0
            created_at: HftTimestamp::now().unwrap_or(HftTimestamp { nanos: 0 }),
1889
0
            updated_at: None,
1890
0
            expires_at: None,
1891
0
1892
0
            metadata: serde_json::json!({}),
1893
0
        }
1894
0
    }
1895
}
1896
1897
/// Represents a trading position - CANONICAL DEFINITION
1898
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1899
#[cfg_attr(feature = "database", derive(sqlx::FromRow))]
1900
pub struct Position {
1901
    /// Unique position identifier
1902
    pub id: Uuid,
1903
1904
    /// Trading symbol
1905
    pub symbol: String,
1906
1907
    /// Position quantity (positive for long, negative for short)
1908
    pub quantity: Decimal,
1909
1910
    /// Average entry price
1911
    pub avg_price: Decimal,
1912
1913
    /// Average cost per share
1914
    pub avg_cost: Decimal,
1915
1916
    /// Cost basis for tax calculations
1917
    pub basis: Decimal,
1918
1919
    /// Average entry price
1920
    pub average_price: Decimal,
1921
1922
    /// Market value of position
1923
    pub market_value: Decimal,
1924
1925
    /// Unrealized P&L
1926
    pub unrealized_pnl: Decimal,
1927
1928
    /// Realized P&L
1929
    pub realized_pnl: Decimal,
1930
1931
    /// Position creation timestamp
1932
    pub created_at: DateTime<Utc>,
1933
1934
    /// Last update timestamp
1935
    pub updated_at: DateTime<Utc>,
1936
1937
    /// Last updated timestamp
1938
    pub last_updated: DateTime<Utc>,
1939
1940
    /// Current market price (for P&L calculation)
1941
    pub current_price: Option<Decimal>,
1942
1943
    /// Position size in base currency
1944
    pub notional_value: Decimal,
1945
1946
    /// Margin requirement
1947
    pub margin_requirement: Decimal,
1948
}
1949
1950
impl Position {
1951
    /// Create a new position
1952
7
    pub fn new(symbol: String, quantity: Decimal, avg_price: Decimal) -> Self {
1953
7
        let now = Utc::now();
1954
7
        let notional_value = quantity.abs() * avg_price;
1955
1956
7
        Self {
1957
7
            id: Uuid::new_v4(),
1958
7
            symbol,
1959
7
            quantity,
1960
7
            avg_price,
1961
7
            avg_cost: avg_price, // Keep avg_cost synchronized with avg_price
1962
7
            basis: quantity * avg_price, // Cost basis calculation
1963
7
            average_price: avg_price, // Same as avg_price for compatibility
1964
7
            market_value: notional_value, // Initialize market value to notional value
1965
7
            unrealized_pnl: Decimal::ZERO,
1966
7
            realized_pnl: Decimal::ZERO,
1967
7
            created_at: now,
1968
7
            updated_at: now,
1969
7
            last_updated: now, // Same as updated_at for compatibility
1970
7
            current_price: None,
1971
7
            notional_value,
1972
7
            margin_requirement: notional_value
1973
7
                * Decimal::from_str_exact("0.02").unwrap_or(Decimal::ZERO), // 2% margin
1974
7
        }
1975
7
    }
1976
1977
    /// Check if position is long
1978
2
    pub fn is_long(&self) -> bool {
1979
2
        self.quantity > Decimal::ZERO
1980
2
    }
1981
1982
    /// Check if position is short
1983
2
    pub fn is_short(&self) -> bool {
1984
2
        self.quantity < Decimal::ZERO
1985
2
    }
1986
1987
    /// Calculate unrealized P&L based on current price
1988
3
    pub fn calculate_unrealized_pnl(&mut self, current_price: Decimal) {
1989
3
        self.current_price = Some(current_price);
1990
3
        self.market_value = self.quantity.abs() * current_price;
1991
        // For both long and short: quantity * (current_price - avg_price)
1992
3
        self.unrealized_pnl = self.quantity * (current_price - self.avg_price);
1993
3
        let now = Utc::now();
1994
3
        self.updated_at = now;
1995
3
        self.last_updated = now; // Keep alias synchronized
1996
3
    }
1997
1998
    /// Get total P&L (realized + unrealized)
1999
1
    pub fn total_pnl(&self) -> Decimal {
2000
1
        self.realized_pnl + self.unrealized_pnl
2001
1
    }
2002
2003
    /// Calculate return on investment percentage
2004
2
    pub fn roi_percentage(&self) -> Decimal {
2005
2
        if self.notional_value.is_zero() {
2006
1
            Decimal::ZERO
2007
        } else {
2008
1
            self.total_pnl() / self.notional_value * Decimal::from(100)
2009
        }
2010
2
    }
2011
}
2012
2013
/// Represents a trade execution - CANONICAL DEFINITION
2014
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
2015
#[cfg_attr(feature = "database", derive(sqlx::FromRow))]
2016
pub struct Execution {
2017
    /// Unique execution identifier
2018
    pub id: Uuid,
2019
2020
    /// Related order ID
2021
    pub order_id: Uuid,
2022
2023
    /// Trading symbol
2024
    pub symbol: String,
2025
2026
    /// Executed quantity
2027
    pub quantity: Decimal,
2028
2029
    /// Execution price
2030
    pub price: Decimal,
2031
2032
    /// Execution side
2033
    pub side: OrderSide,
2034
2035
    /// Trading fees
2036
    pub fees: Decimal,
2037
2038
    /// Fee currency
2039
    pub fee_currency: String,
2040
2041
    /// Execution timestamp
2042
    pub executed_at: DateTime<Utc>,
2043
2044
    /// Execution timestamp
2045
    pub timestamp: DateTime<Utc>,
2046
2047
    /// Symbol hash for performance
2048
    pub symbol_hash: i64,
2049
2050
    /// Broker execution ID
2051
    pub broker_execution_id: Option<String>,
2052
2053
    /// Counterparty information
2054
    pub counterparty: Option<String>,
2055
2056
    /// Trade venue
2057
    pub venue: Option<String>,
2058
2059
    /// Gross trade value
2060
    pub gross_value: Decimal,
2061
2062
    /// Net trade value (after fees)
2063
    pub net_value: Decimal,
2064
}
2065
2066
impl Execution {
2067
    /// Create a new execution
2068
5
    pub fn new(
2069
5
        order_id: Uuid,
2070
5
        symbol: String,
2071
5
        quantity: Decimal,
2072
5
        price: Decimal,
2073
5
        side: OrderSide,
2074
5
        fees: Decimal,
2075
5
    ) -> Self {
2076
5
        let gross_value = quantity * price;
2077
5
        let net_value = if side == OrderSide::Buy {
2078
4
            gross_value + fees
2079
        } else {
2080
1
            gross_value - fees
2081
        };
2082
5
        let now = Utc::now();
2083
5
        let symbol_hash = Self::hash_symbol(&symbol);
2084
2085
5
        Self {
2086
5
            id: Uuid::new_v4(),
2087
5
            order_id,
2088
5
            symbol,
2089
5
            quantity,
2090
5
            price,
2091
5
            side,
2092
5
            fees,
2093
5
            fee_currency: "USD".to_string(), // Default to USD
2094
5
            executed_at: now,
2095
5
            timestamp: now, // Same as executed_at for compatibility
2096
5
            symbol_hash,
2097
5
            broker_execution_id: None,
2098
5
            counterparty: None,
2099
5
            venue: None,
2100
5
            gross_value,
2101
5
            net_value,
2102
5
        }
2103
5
    }
2104
2105
    /// Calculate effective price including fees
2106
2
    pub fn effective_price(&self) -> Decimal {
2107
2
        if self.quantity.is_zero() {
2108
1
            self.price
2109
        } else {
2110
1
            self.net_value / self.quantity
2111
        }
2112
2
    }
2113
2114
    /// Hash symbol for performance
2115
5
    fn hash_symbol(symbol: &str) -> i64 {
2116
        use std::collections::hash_map::DefaultHasher;
2117
        use std::hash::{Hash, Hasher};
2118
2119
5
        let mut hasher = DefaultHasher::new();
2120
5
        symbol.hash(&mut hasher);
2121
5
        hasher.finish() as i64
2122
5
    }
2123
}
2124
2125
/// Core Price type using fixed-point arithmetic for precision
2126
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
2127
pub struct Price {
2128
    value: u64,
2129
}
2130
2131
impl Price {
2132
    /// Zero price constant
2133
    pub const ZERO: Self = Self { value: 0 };
2134
    /// One unit price constant (1.0)
2135
    pub const ONE: Self = Self { value: 100_000_000 };
2136
    /// One cent constant (0.01)
2137
    pub const CENT: Self = Self { value: 1_000_000 };
2138
    /// Maximum price value
2139
    pub const MAX: Self = Self { value: u64::MAX };
2140
2141
    /// Create a Price from a floating-point value
2142
70
    pub fn from_f64(value: f64) -> Result<Self, CommonTypeError> {
2143
70
        if value < 0.0 || 
!value.is_finite()66
{
2144
8
            return Err(CommonTypeError::InvalidPrice {
2145
8
                value: value.to_string(),
2146
8
                reason: "Price validation failed".to_owned(),
2147
8
            });
2148
62
        }
2149
62
        Ok(Self {
2150
62
            value: (value * 100_000_000.0).round() as u64,
2151
62
        })
2152
70
    }
2153
2154
    /// Convert to floating-point representation
2155
    #[must_use]
2156
    /// Convert the quantity to a floating point value
2157
51
    pub fn to_f64(&self) -> f64 {
2158
51
        self.value as f64 / 100_000_000.0
2159
51
    }
2160
2161
    /// Get floating-point representation (alias for to_f64)
2162
    /// Convert quantity to f64 representation
2163
    /// Convert quantity to f64 representation
2164
    /// Convert quantity to f64 representation
2165
    #[must_use]
2166
0
    pub fn as_f64(&self) -> f64 {
2167
0
        self.to_f64()
2168
0
    }
2169
2170
    /// Create a zero price
2171
    /// Create a zero quantity
2172
    /// Create zero quantity
2173
    #[must_use]
2174
0
    pub const fn zero() -> Self {
2175
0
        Self::ZERO
2176
0
    }
2177
2178
    /// Convert to Decimal type for precise calculations
2179
1
    pub fn to_decimal(&self) -> Result<Decimal, CommonTypeError> {
2180
1
        Decimal::from_f64(self.to_f64()).ok_or_else(|| CommonTypeError::InvalidPrice {
2181
0
            value: "0.0".to_owned(),
2182
0
            reason: "Price to Decimal conversion failed".to_owned(),
2183
0
        })
2184
1
    }
2185
2186
    /// Create a Price from a Decimal value
2187
    #[must_use]
2188
1
    pub fn from_decimal(decimal: Decimal) -> Self {
2189
1
        Self::from(decimal)
2190
1
    }
2191
2192
    /// Create a new Price (alias for from_f64)
2193
    /// Create a new quantity from a floating point value
2194
    /// Create new quantity from f64 value
2195
0
    pub fn new(value: f64) -> Result<Self, CommonTypeError> {
2196
0
        Self::from_f64(value)
2197
0
    }
2198
2199
    /// Get the raw internal value representation
2200
    /// Get the raw internal value
2201
    /// Get the raw internal value representation
2202
    #[must_use]
2203
1
    pub const fn raw_value(&self) -> u64 {
2204
1
        self.value
2205
1
    }
2206
2207
    /// Get the price as a u64 value (same as raw_value)
2208
    /// Convert to u64 representation
2209
    /// Convert quantity to u64 representation
2210
    #[must_use]
2211
0
    pub const fn as_u64(&self) -> u64 {
2212
0
        self.value
2213
0
    }
2214
2215
    /// Create a Price from a raw u64 value
2216
    /// Create a quantity from raw internal value
2217
    /// Create quantity from raw u64 value
2218
    #[must_use]
2219
0
    pub const fn from_raw(value: u64) -> Self {
2220
0
        Self { value }
2221
0
    }
2222
2223
    /// Convert price to cents (divides by 1M for 8 decimal places)
2224
    #[must_use]
2225
2
    pub const fn to_cents(&self) -> u64 {
2226
2
        self.value / 1_000_000
2227
2
    }
2228
2229
    /// Create a Price from cents value
2230
    #[must_use]
2231
2
    pub const fn from_cents(cents: u64) -> Self {
2232
2
        Self {
2233
2
            value: cents * 1_000_000,
2234
2
        }
2235
2
    }
2236
2237
    /// Check if the price is zero
2238
    /// Check if the quantity is zero
2239
    /// Check if quantity is zero
2240
    #[must_use]
2241
2
    pub const fn is_zero(&self) -> bool {
2242
2
        self.value == 0
2243
2
    }
2244
2245
    /// Check if the price is non-zero (has some value)
2246
    /// Check if the quantity is non-zero (has some value)
2247
    /// Check if quantity has a non-zero value
2248
    #[must_use]
2249
0
    pub const fn is_some(&self) -> bool {
2250
0
        !self.is_zero()
2251
0
    }
2252
2253
    /// Check if the price is zero (has no value)
2254
    /// Check if the quantity is zero (has no value)
2255
    /// Check if quantity is zero (none)
2256
    #[must_use]
2257
0
    pub const fn is_none(&self) -> bool {
2258
0
        self.is_zero()
2259
0
    }
2260
2261
    /// Get a reference to this price
2262
    /// Get a reference to self
2263
    /// Get a reference to self
2264
    #[must_use]
2265
0
    pub const fn as_ref(&self) -> &Self {
2266
0
        self
2267
0
    }
2268
2269
    /// Get the absolute value of the price (prices are always positive)
2270
    /// Get the absolute value (quantities are always positive)
2271
    /// Get absolute value (always positive for Quantity)
2272
    #[must_use]
2273
0
    pub const fn abs(&self) -> Self {
2274
0
        *self
2275
0
    }
2276
2277
    /// Multiply this price by another price
2278
1
    pub fn multiply(&self, other: Self) -> Result<Self, CommonTypeError> {
2279
1
        *self * other
2280
1
    }
2281
2282
    /// Subtract another price from this price
2283
    /// Subtract another quantity from this quantity
2284
    /// Subtract another quantity from this quantity
2285
    /// Subtract another quantity from this quantity
2286
    /// Subtract another quantity from this quantity
2287
    #[must_use]
2288
0
    pub fn subtract(&self, other: Self) -> Self {
2289
0
        *self - other
2290
0
    }
2291
2292
    /// Divide this price by a floating point divisor
2293
0
    pub fn divide(&self, divisor: f64) -> Result<Self, CommonTypeError> {
2294
0
        *self / divisor
2295
0
    }
2296
}
2297
2298
impl fmt::Display for Price {
2299
    /// Format the price for display with 8 decimal places
2300
2
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2301
2
        write!(f, "{:.8}", self.to_f64())
2302
2
    }
2303
}
2304
2305
impl Default for Price {
2306
    /// Returns the default price (zero)
2307
0
    fn default() -> Self {
2308
0
        Self::ZERO
2309
0
    }
2310
}
2311
2312
impl FromStr for Price {
2313
    type Err = CommonTypeError;
2314
2315
5
    fn from_str(s: &str) -> Result<Self, Self::Err> {
2316
5
        let 
parsed_value3
= s
2317
5
            .parse::<f64>()
2318
5
            .map_err(|_| CommonTypeError::InvalidPrice {
2319
2
                value: s.to_owned(),
2320
2
                reason: format!("Cannot parse '{}' as price", s),
2321
2
            })?;
2322
3
        Self::from_f64(parsed_value)
2323
5
    }
2324
}
2325
2326
impl Add for Price {
2327
    type Output = Self;
2328
4
    fn add(self, rhs: Self) -> Self::Output {
2329
4
        Self {
2330
4
            value: self.value.saturating_add(rhs.value),
2331
4
        }
2332
4
    }
2333
}
2334
2335
impl Sub for Price {
2336
    type Output = Self;
2337
3
    fn sub(self, rhs: Self) -> Self::Output {
2338
3
        Self {
2339
3
            value: self.value.saturating_sub(rhs.value),
2340
3
        }
2341
3
    }
2342
}
2343
2344
impl Mul<f64> for Price {
2345
    type Output = Result<Self, CommonTypeError>;
2346
2
    fn mul(self, rhs: f64) -> Self::Output {
2347
2
        Self::from_f64(self.to_f64() * rhs)
2348
2
    }
2349
}
2350
2351
impl Div<f64> for Price {
2352
    type Output = Result<Self, CommonTypeError>;
2353
4
    fn div(self, rhs: f64) -> Self::Output {
2354
4
        if rhs == 0.0 {
2355
2
            return Err(CommonTypeError::ConversionError {
2356
2
                message: "Cannot divide price by zero".to_owned(),
2357
2
            });
2358
2
        }
2359
2
        Self::from_f64(self.to_f64() / rhs)
2360
4
    }
2361
}
2362
2363
impl From<Decimal> for Price {
2364
1
    fn from(decimal: Decimal) -> Self {
2365
1
        let f64_val: f64 = TryInto::<f64>::try_into(decimal).unwrap_or_else(|_| 
{0
2366
0
            tracing::warn!("Failed to convert Decimal to f64, using 0.0 as fallback");
2367
0
            0.0_f64
2368
0
        });
2369
1
        Self::from_f64(f64_val).unwrap_or_else(|_| 
{0
2370
0
            tracing::warn!(
2371
0
                "Failed to create Price from f64 value {}, using ZERO",
2372
                f64_val
2373
            );
2374
0
            Self::ZERO
2375
0
        })
2376
1
    }
2377
}
2378
2379
impl From<Price> for Decimal {
2380
0
    fn from(price: Price) -> Self {
2381
0
        price.to_decimal().unwrap_or(Decimal::ZERO)
2382
0
    }
2383
}
2384
2385
// TryFrom<Quantity> for Decimal removed due to conflicting blanket implementation
2386
// Use qty.to_decimal() directly instead
2387
impl From<Quantity> for Decimal {
2388
0
    fn from(qty: Quantity) -> Self {
2389
0
        qty.to_decimal().unwrap_or(Decimal::ZERO)
2390
0
    }
2391
}
2392
2393
// TryFrom<Quantity> for Decimal removed due to conflict with From implementation
2394
// Use the From implementation instead which handles errors by returning ZERO
2395
2396
impl Mul<Self> for Price {
2397
    type Output = Result<Self, CommonTypeError>;
2398
1
    fn mul(self, rhs: Self) -> Self::Output {
2399
1
        Self::from_f64(self.to_f64() * rhs.to_f64())
2400
1
    }
2401
}
2402
2403
impl TryFrom<String> for Price {
2404
    type Error = CommonTypeError;
2405
0
    fn try_from(s: String) -> Result<Self, Self::Error> {
2406
0
        Self::from_str(&s)
2407
0
    }
2408
}
2409
2410
impl TryFrom<&str> for Price {
2411
    type Error = CommonTypeError;
2412
0
    fn try_from(s: &str) -> Result<Self, Self::Error> {
2413
0
        Self::from_str(s)
2414
0
    }
2415
}
2416
2417
impl PartialEq<f64> for Price {
2418
4
    fn eq(&self, other: &f64) -> bool {
2419
4
        (self.to_f64() - other).abs() < f64::EPSILON
2420
4
    }
2421
}
2422
2423
impl PartialEq<Price> for f64 {
2424
1
    fn eq(&self, other: &Price) -> bool {
2425
1
        (self - other.to_f64()).abs() < f64::EPSILON
2426
1
    }
2427
}
2428
2429
impl AddAssign for Price {
2430
1
    fn add_assign(&mut self, rhs: Self) {
2431
1
        self.value = self.value.saturating_add(rhs.value);
2432
1
    }
2433
}
2434
2435
impl SubAssign for Price {
2436
0
    fn sub_assign(&mut self, rhs: Self) {
2437
0
        self.value = self.value.saturating_sub(rhs.value);
2438
0
    }
2439
}
2440
2441
impl MulAssign<f64> for Price {
2442
0
    fn mul_assign(&mut self, rhs: f64) {
2443
0
        if let Ok(result) = self.mul(rhs) {
2444
0
            *self = result;
2445
0
        }
2446
        // If multiplication fails, self remains unchanged
2447
0
    }
2448
}
2449
2450
impl DivAssign<f64> for Price {
2451
0
    fn div_assign(&mut self, rhs: f64) {
2452
0
        if let Ok(result) = self.div(rhs) {
2453
0
            *self = result;
2454
0
        }
2455
        // If division fails, self remains unchanged
2456
0
    }
2457
}
2458
2459
impl PartialOrd<f64> for Price {
2460
2
    fn partial_cmp(&self, other: &f64) -> Option<std::cmp::Ordering> {
2461
2
        self.to_f64().partial_cmp(other)
2462
2
    }
2463
}
2464
2465
impl PartialOrd<Price> for f64 {
2466
0
    fn partial_cmp(&self, other: &Price) -> Option<std::cmp::Ordering> {
2467
0
        self.partial_cmp(&other.to_f64())
2468
0
    }
2469
}
2470
2471
/// Core Quantity type using fixed-point arithmetic
2472
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
2473
pub struct Quantity {
2474
    value: u64,
2475
}
2476
2477
impl Quantity {
2478
    /// Zero quantity constant
2479
    pub const ZERO: Self = Self { value: 0 };
2480
    /// One unit quantity constant
2481
    pub const ONE: Self = Self { value: 100_000_000 };
2482
    /// Maximum possible quantity
2483
    pub const MAX: Self = Self { value: u64::MAX };
2484
2485
    /// Create a Quantity from a floating point value
2486
61
    pub fn from_f64(value: f64) -> Result<Self, CommonTypeError> {
2487
61
        if value < 0.0 || 
!value.is_finite()59
{
2488
4
            return Err(CommonTypeError::InvalidQuantity {
2489
4
                value: value.to_string(),
2490
4
                reason: "Quantity validation failed".to_owned(),
2491
4
            });
2492
57
        }
2493
57
        Ok(Self {
2494
57
            value: (value * 100_000_000.0).round() as u64,
2495
57
        })
2496
61
    }
2497
2498
    /// Convert quantity to floating point representation
2499
    #[must_use]
2500
46
    pub fn to_f64(&self) -> f64 {
2501
46
        self.value as f64 / 100_000_000.0
2502
46
    }
2503
2504
    /// Convert the quantity to a Decimal value
2505
0
    pub fn to_decimal(&self) -> Result<Decimal, CommonTypeError> {
2506
0
        Decimal::from_f64(self.to_f64()).ok_or_else(|| CommonTypeError::InvalidQuantity {
2507
0
            value: "0.0".to_owned(),
2508
0
            reason: "Quantity to Decimal conversion failed".to_owned(),
2509
0
        })
2510
0
    }
2511
2512
    /// Get the internal value representation
2513
    #[must_use]
2514
0
    pub const fn value(&self) -> u64 {
2515
0
        self.value
2516
0
    }
2517
2518
    /// Get the raw internal value representation
2519
    #[must_use]
2520
1
    pub const fn raw_value(&self) -> u64 {
2521
1
        self.value
2522
1
    }
2523
2524
    /// Convert quantity to u64 representation
2525
    #[must_use]
2526
0
    pub const fn as_u64(&self) -> u64 {
2527
0
        self.value
2528
0
    }
2529
2530
    /// Create quantity from raw u64 value
2531
    #[must_use]
2532
0
    pub const fn from_raw(value: u64) -> Self {
2533
0
        Self { value }
2534
0
    }
2535
2536
    /// Create new quantity from f64 value
2537
1
    pub fn new(value: f64) -> Result<Self, CommonTypeError> {
2538
1
        Self::from_f64(value)
2539
1
    }
2540
2541
    /// Create zero quantity
2542
    #[must_use]
2543
0
    pub const fn zero() -> Self {
2544
0
        Self::ZERO
2545
0
    }
2546
2547
    /// Create a quantity from an i64 value
2548
0
    pub fn from_i64(value: i64) -> Result<Self, CommonTypeError> {
2549
0
        Self::from_f64(value as f64)
2550
0
    }
2551
2552
    /// Create a quantity from a u64 value
2553
0
    pub fn from_u64(value: u64) -> Result<Self, CommonTypeError> {
2554
0
        Self::from_f64(value as f64)
2555
0
    }
2556
2557
    /// Create a quantity from a Decimal value
2558
0
    pub fn from_decimal(decimal: Decimal) -> Result<Self, CommonTypeError> {
2559
        use std::convert::TryFrom;
2560
0
        Self::try_from(decimal).map_err(|_| CommonTypeError::InvalidQuantity {
2561
0
            value: decimal.to_string(),
2562
0
            reason: "Failed to convert Decimal to Quantity".to_owned(),
2563
0
        })
2564
0
    }
2565
2566
    /// Check if quantity is zero
2567
    #[must_use]
2568
10
    pub const fn is_zero(&self) -> bool {
2569
10
        self.value == 0
2570
10
    }
2571
2572
    /// Check if quantity has a non-zero value
2573
    #[must_use]
2574
0
    pub const fn is_some(&self) -> bool {
2575
0
        !self.is_zero()
2576
0
    }
2577
2578
    /// Check if quantity is zero (none)
2579
    #[must_use]
2580
0
    pub const fn is_none(&self) -> bool {
2581
0
        self.is_zero()
2582
0
    }
2583
2584
    /// Get a reference to self
2585
    #[must_use]
2586
0
    pub const fn as_ref(&self) -> &Self {
2587
0
        self
2588
0
    }
2589
2590
    /// Get absolute value (always positive for Quantity)
2591
    #[must_use]
2592
0
    pub const fn abs(&self) -> Self {
2593
0
        *self
2594
0
    }
2595
2596
    /// Get the sign of the quantity (1.0 for positive, 0.0 for zero)
2597
    #[must_use]
2598
0
    pub const fn signum(&self) -> f64 {
2599
0
        if self.value > 0 {
2600
0
            1.0
2601
        } else {
2602
0
            0.0
2603
        }
2604
0
    }
2605
2606
    /// Check if quantity is positive
2607
    #[must_use]
2608
5
    pub const fn is_positive(&self) -> bool {
2609
5
        self.value > 0
2610
5
    }
2611
2612
    /// Check if quantity is negative (always false for Quantity)
2613
    #[must_use]
2614
2
    pub const fn is_negative(&self) -> bool {
2615
2
        false
2616
2
    }
2617
2618
    /// Convert quantity to f64 representation
2619
    #[must_use]
2620
0
    pub fn as_f64(&self) -> f64 {
2621
0
        self.to_f64()
2622
0
    }
2623
2624
    /// Create quantity from number of shares
2625
    #[must_use]
2626
2
    pub const fn from_shares(shares: u64) -> Self {
2627
2
        Self {
2628
2
            value: shares * 100_000_000,
2629
2
        }
2630
2
    }
2631
2632
    /// Convert quantity to number of shares
2633
    #[must_use]
2634
2
    pub const fn to_shares(&self) -> u64 {
2635
2
        self.value / 100_000_000
2636
2
    }
2637
2638
    /// Multiply this quantity by another quantity
2639
0
    pub fn multiply(&self, other: Self) -> Result<Self, CommonTypeError> {
2640
0
        Self::from_f64(self.to_f64() * other.to_f64())
2641
0
    }
2642
2643
    /// Subtract another quantity from this quantity
2644
    #[must_use]
2645
0
    pub fn subtract(&self, other: Self) -> Self {
2646
0
        *self - other
2647
0
    }
2648
}
2649
2650
impl Default for Quantity {
2651
0
    fn default() -> Self {
2652
0
        Self::ZERO
2653
0
    }
2654
}
2655
2656
impl FromStr for Quantity {
2657
    type Err = CommonTypeError;
2658
2659
1
    fn from_str(s: &str) -> Result<Self, Self::Err> {
2660
1
        let parsed_value = s
2661
1
            .parse::<f64>()
2662
1
            .map_err(|_| CommonTypeError::InvalidQuantity {
2663
0
                value: s.to_owned(),
2664
0
                reason: format!("Cannot parse '{}' as quantity", s),
2665
0
            })?;
2666
1
        Self::from_f64(parsed_value)
2667
1
    }
2668
}
2669
2670
impl fmt::Display for Quantity {
2671
    /// Format the quantity for display with 8 decimal places
2672
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2673
0
        write!(f, "{:.8}", self.to_f64())
2674
0
    }
2675
}
2676
2677
impl TryFrom<i32> for Quantity {
2678
    type Error = CommonTypeError;
2679
1
    fn try_from(value: i32) -> Result<Self, Self::Error> {
2680
1
        Self::new(f64::from(value))
2681
1
    }
2682
}
2683
2684
impl TryFrom<u64> for Quantity {
2685
    type Error = CommonTypeError;
2686
0
    fn try_from(value: u64) -> Result<Self, Self::Error> {
2687
0
        Self::new(value as f64)
2688
0
    }
2689
}
2690
2691
impl TryFrom<f64> for Quantity {
2692
    type Error = CommonTypeError;
2693
0
    fn try_from(value: f64) -> Result<Self, Self::Error> {
2694
0
        Self::new(value)
2695
0
    }
2696
}
2697
2698
impl TryFrom<Decimal> for Quantity {
2699
    type Error = CommonTypeError;
2700
1
    fn try_from(decimal: Decimal) -> Result<Self, Self::Error> {
2701
1
        let f64_val: f64 =
2702
1
            TryInto::<f64>::try_into(decimal).map_err(|_| CommonTypeError::ConversionError {
2703
0
                message: "Failed to convert Decimal to f64".to_owned(),
2704
0
            })?;
2705
1
        Self::from_f64(f64_val)
2706
1
    }
2707
}
2708
2709
impl TryFrom<String> for Quantity {
2710
    type Error = CommonTypeError;
2711
0
    fn try_from(s: String) -> Result<Self, Self::Error> {
2712
0
        Self::from_str(&s)
2713
0
    }
2714
}
2715
2716
impl TryFrom<&str> for Quantity {
2717
    type Error = CommonTypeError;
2718
1
    fn try_from(s: &str) -> Result<Self, Self::Error> {
2719
1
        Self::from_str(s)
2720
1
    }
2721
}
2722
2723
impl PartialEq<f64> for Quantity {
2724
0
    fn eq(&self, other: &f64) -> bool {
2725
0
        (self.to_f64() - other).abs() < f64::EPSILON
2726
0
    }
2727
}
2728
2729
impl PartialEq<Quantity> for f64 {
2730
0
    fn eq(&self, other: &Quantity) -> bool {
2731
0
        (self - other.to_f64()).abs() < f64::EPSILON
2732
0
    }
2733
}
2734
2735
impl PartialOrd<f64> for Quantity {
2736
0
    fn partial_cmp(&self, other: &f64) -> Option<std::cmp::Ordering> {
2737
0
        self.to_f64().partial_cmp(other)
2738
0
    }
2739
}
2740
2741
impl PartialOrd<Quantity> for f64 {
2742
0
    fn partial_cmp(&self, other: &Quantity) -> Option<std::cmp::Ordering> {
2743
0
        self.partial_cmp(&other.to_f64())
2744
0
    }
2745
}
2746
2747
impl Add for Quantity {
2748
    type Output = Self;
2749
29
    fn add(self, rhs: Self) -> Self::Output {
2750
29
        Self {
2751
29
            value: self.value.saturating_add(rhs.value),
2752
29
        }
2753
29
    }
2754
}
2755
2756
impl Sub for Quantity {
2757
    type Output = Self;
2758
14
    fn sub(self, rhs: Self) -> Self::Output {
2759
14
        Self {
2760
14
            value: self.value.saturating_sub(rhs.value),
2761
14
        }
2762
14
    }
2763
}
2764
2765
impl Mul<f64> for Quantity {
2766
    type Output = Result<Self, CommonTypeError>;
2767
1
    fn mul(self, rhs: f64) -> Self::Output {
2768
1
        Self::from_f64(self.to_f64() * rhs)
2769
1
    }
2770
}
2771
2772
impl Div<f64> for Quantity {
2773
    type Output = Result<Self, CommonTypeError>;
2774
2
    fn div(self, rhs: f64) -> Self::Output {
2775
2
        if rhs == 0.0 {
2776
1
            return Err(CommonTypeError::ConversionError {
2777
1
                message: "Cannot divide quantity by zero".to_owned(),
2778
1
            });
2779
1
        }
2780
1
        Self::from_f64(self.to_f64() / rhs)
2781
2
    }
2782
}
2783
2784
impl Sum for Quantity {
2785
2
    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
2786
6
        
iter2
.
fold2
(Self::ZERO, |acc, x| acc + x)
2787
2
    }
2788
}
2789
2790
impl<'quantity> Sum<&'quantity Self> for Quantity {
2791
0
    fn sum<I: Iterator<Item = &'quantity Self>>(iter: I) -> Self {
2792
0
        iter.fold(Self::ZERO, |acc, x| acc + *x)
2793
0
    }
2794
}
2795
2796
// =============================================================================
2797
// SQLX IMPLEMENTATIONS FOR FINANCIAL TYPES
2798
// =============================================================================
2799
2800
#[cfg(feature = "database")]
2801
mod sqlx_impls {
2802
    use super::{HftTimestamp, MarketRegime, OrderSide, OrderStatus, OrderType, Price, Quantity};
2803
    use rust_decimal::Decimal as RustDecimal;
2804
    use sqlx::{
2805
        decode::Decode,
2806
        encode::{Encode, IsNull},
2807
        error::BoxDynError,
2808
        postgres::{PgArgumentBuffer, PgTypeInfo, PgValueRef, Postgres},
2809
        Type,
2810
    };
2811
2812
    // SQLx implementations for Price
2813
    impl Type<Postgres> for Price {
2814
0
        fn type_info() -> PgTypeInfo {
2815
0
            PgTypeInfo::with_name("NUMERIC")
2816
0
        }
2817
    }
2818
2819
    impl<'q> Encode<'q, Postgres> for Price {
2820
0
        fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
2821
            // Convert our fixed-point u64 to rust_decimal::Decimal with 8 decimal places
2822
0
            let decimal_value = RustDecimal::new(self.raw_value() as i64, 8);
2823
0
            decimal_value.encode_by_ref(buf)
2824
0
        }
2825
    }
2826
2827
    impl<'r> Decode<'r, Postgres> for Price {
2828
0
        fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
2829
            // Decode from NUMERIC to rust_decimal::Decimal
2830
0
            let decimal_value = <RustDecimal as Decode<Postgres>>::decode(value)?;
2831
2832
            // Validate scale matches our fixed-point precision (8 decimal places)
2833
0
            if decimal_value.scale() != 8 {
2834
0
                return Err(format!(
2835
0
                    "Invalid scale for Price: expected 8, got {}",
2836
0
                    decimal_value.scale()
2837
0
                )
2838
0
                .into());
2839
0
            }
2840
2841
            // Extract mantissa and convert to our u64 representation
2842
0
            let mantissa = decimal_value.mantissa();
2843
0
            let inner_val = u64::try_from(mantissa)
2844
0
                .map_err(|_| "Failed to convert negative or overflowing NUMERIC to Price")?;
2845
2846
0
            Ok(Price::from_raw(inner_val))
2847
0
        }
2848
    }
2849
    // SQLx implementations for Quantity
2850
    impl Type<Postgres> for Quantity {
2851
0
        fn type_info() -> PgTypeInfo {
2852
0
            PgTypeInfo::with_name("NUMERIC")
2853
0
        }
2854
    }
2855
2856
    impl<'q> Encode<'q, Postgres> for Quantity {
2857
0
        fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
2858
            // Convert our fixed-point u64 to rust_decimal::Decimal with 8 decimal places
2859
0
            let decimal_value = RustDecimal::new(self.raw_value() as i64, 8);
2860
0
            decimal_value.encode_by_ref(buf)
2861
0
        }
2862
    }
2863
2864
    impl<'r> Decode<'r, Postgres> for Quantity {
2865
0
        fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
2866
            // Decode from NUMERIC to rust_decimal::Decimal
2867
0
            let decimal_value = <RustDecimal as Decode<Postgres>>::decode(value)?;
2868
2869
            // Validate scale matches our fixed-point precision (8 decimal places)
2870
0
            if decimal_value.scale() != 8 {
2871
0
                return Err(format!(
2872
0
                    "Invalid scale for Quantity: expected 8, got {}",
2873
0
                    decimal_value.scale()
2874
0
                )
2875
0
                .into());
2876
0
            }
2877
2878
            // Extract mantissa and convert to our u64 representation
2879
0
            let mantissa = decimal_value.mantissa();
2880
0
            let inner_val = u64::try_from(mantissa)
2881
0
                .map_err(|_| "Failed to convert negative or overflowing NUMERIC to Quantity")?;
2882
2883
0
            Ok(Quantity::from_raw(inner_val))
2884
0
        }
2885
    }
2886
2887
    // SQLx implementations for TimeInForce
2888
    impl Type<Postgres> for super::TimeInForce {
2889
0
        fn type_info() -> PgTypeInfo {
2890
0
            PgTypeInfo::with_name("TEXT")
2891
0
        }
2892
    }
2893
2894
    impl<'q> Encode<'q, Postgres> for super::TimeInForce {
2895
0
        fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
2896
            // Use the Display trait to convert enum to string representation
2897
0
            <&str as Encode<Postgres>>::encode(self.to_string().as_str(), buf)
2898
0
        }
2899
    }
2900
2901
    impl<'r> Decode<'r, Postgres> for super::TimeInForce {
2902
0
        fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
2903
            // Decode from TEXT to string, then parse to enum
2904
0
            let s = <&str as Decode<Postgres>>::decode(value)?;
2905
0
            match s {
2906
0
                "DAY" => Ok(super::TimeInForce::Day),
2907
0
                "GTC" => Ok(super::TimeInForce::GoodTillCancel),
2908
0
                "IOC" => Ok(super::TimeInForce::ImmediateOrCancel),
2909
0
                "FOK" => Ok(super::TimeInForce::FillOrKill),
2910
0
                _ => Err(format!("Invalid TimeInForce value: {}", s).into()),
2911
            }
2912
0
        }
2913
    }
2914
2915
    // SQLx implementations for OrderStatus
2916
    impl Type<Postgres> for OrderStatus {
2917
0
        fn type_info() -> PgTypeInfo {
2918
0
            PgTypeInfo::with_name("TEXT")
2919
0
        }
2920
    }
2921
2922
    impl<'q> Encode<'q, Postgres> for OrderStatus {
2923
0
        fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
2924
0
            let value = match self {
2925
0
                OrderStatus::Created => "CREATED",
2926
0
                OrderStatus::Submitted => "SUBMITTED",
2927
0
                OrderStatus::PartiallyFilled => "PARTIALLY_FILLED",
2928
0
                OrderStatus::Filled => "FILLED",
2929
0
                OrderStatus::Rejected => "REJECTED",
2930
0
                OrderStatus::Cancelled => "CANCELLED",
2931
0
                OrderStatus::New => "NEW",
2932
0
                OrderStatus::Expired => "EXPIRED",
2933
0
                OrderStatus::Pending => "PENDING",
2934
0
                OrderStatus::Working => "WORKING",
2935
0
                OrderStatus::Unknown => "UNKNOWN",
2936
0
                OrderStatus::Suspended => "SUSPENDED",
2937
0
                OrderStatus::PendingCancel => "PENDING_CANCEL",
2938
0
                OrderStatus::PendingReplace => "PENDING_REPLACE",
2939
            };
2940
0
            <&str as Encode<Postgres>>::encode_by_ref(&value, buf)
2941
0
        }
2942
    }
2943
2944
    impl<'r> Decode<'r, Postgres> for OrderStatus {
2945
0
        fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
2946
0
            let s = <String as Decode<Postgres>>::decode(value)?;
2947
0
            match s.as_str() {
2948
0
                "CREATED" => Ok(OrderStatus::Created),
2949
0
                "SUBMITTED" => Ok(OrderStatus::Submitted),
2950
0
                "PARTIALLY_FILLED" => Ok(OrderStatus::PartiallyFilled),
2951
0
                "FILLED" => Ok(OrderStatus::Filled),
2952
0
                "REJECTED" => Ok(OrderStatus::Rejected),
2953
0
                "CANCELLED" => Ok(OrderStatus::Cancelled),
2954
0
                "NEW" => Ok(OrderStatus::New),
2955
0
                "EXPIRED" => Ok(OrderStatus::Expired),
2956
0
                "PENDING" => Ok(OrderStatus::Pending),
2957
0
                "WORKING" => Ok(OrderStatus::Working),
2958
0
                "UNKNOWN" => Ok(OrderStatus::Unknown),
2959
0
                "SUSPENDED" => Ok(OrderStatus::Suspended),
2960
0
                "PENDING_CANCEL" => Ok(OrderStatus::PendingCancel),
2961
0
                "PENDING_REPLACE" => Ok(OrderStatus::PendingReplace),
2962
0
                _ => Err(format!("Invalid OrderStatus value: {}", s).into()),
2963
            }
2964
0
        }
2965
    }
2966
2967
    // SQLx implementations for OrderSide
2968
    impl Type<Postgres> for OrderSide {
2969
0
        fn type_info() -> PgTypeInfo {
2970
0
            PgTypeInfo::with_name("TEXT")
2971
0
        }
2972
    }
2973
2974
    impl<'q> Encode<'q, Postgres> for OrderSide {
2975
0
        fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
2976
0
            let value = match self {
2977
0
                OrderSide::Buy => "BUY",
2978
0
                OrderSide::Sell => "SELL",
2979
            };
2980
0
            <&str as Encode<Postgres>>::encode_by_ref(&value, buf)
2981
0
        }
2982
    }
2983
2984
    impl<'r> Decode<'r, Postgres> for OrderSide {
2985
0
        fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
2986
0
            let s = <String as Decode<Postgres>>::decode(value)?;
2987
0
            match s.as_str() {
2988
0
                "BUY" => Ok(OrderSide::Buy),
2989
0
                "SELL" => Ok(OrderSide::Sell),
2990
0
                _ => Err(format!("Invalid OrderSide value: {}", s).into()),
2991
            }
2992
0
        }
2993
    }
2994
2995
    // SQLx implementations for OrderType
2996
    impl Type<Postgres> for OrderType {
2997
0
        fn type_info() -> PgTypeInfo {
2998
0
            PgTypeInfo::with_name("TEXT")
2999
0
        }
3000
    }
3001
3002
    impl<'q> Encode<'q, Postgres> for OrderType {
3003
0
        fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
3004
0
            let value = match self {
3005
0
                OrderType::Market => "MARKET",
3006
0
                OrderType::Limit => "LIMIT",
3007
0
                OrderType::Stop => "STOP",
3008
0
                OrderType::StopLimit => "STOP_LIMIT",
3009
0
                OrderType::Iceberg => "ICEBERG",
3010
0
                OrderType::TrailingStop => "TRAILING_STOP",
3011
0
                OrderType::Hidden => "HIDDEN",
3012
            };
3013
0
            <&str as Encode<Postgres>>::encode_by_ref(&value, buf)
3014
0
        }
3015
    }
3016
3017
    impl<'r> Decode<'r, Postgres> for OrderType {
3018
0
        fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
3019
0
            let s = <String as Decode<Postgres>>::decode(value)?;
3020
0
            match s.as_str() {
3021
0
                "MARKET" => Ok(OrderType::Market),
3022
0
                "LIMIT" => Ok(OrderType::Limit),
3023
0
                "STOP" => Ok(OrderType::Stop),
3024
0
                "STOP_LIMIT" => Ok(OrderType::StopLimit),
3025
0
                "ICEBERG" => Ok(OrderType::Iceberg),
3026
0
                "TRAILING_STOP" => Ok(OrderType::TrailingStop),
3027
0
                "HIDDEN" => Ok(OrderType::Hidden),
3028
0
                _ => Err(format!("Invalid OrderType value: {}", s).into()),
3029
            }
3030
0
        }
3031
    }
3032
3033
    // SQLx implementations for MarketRegime
3034
    impl Type<Postgres> for MarketRegime {
3035
0
        fn type_info() -> PgTypeInfo {
3036
0
            PgTypeInfo::with_name("TEXT")
3037
0
        }
3038
    }
3039
3040
    impl<'q> Encode<'q, Postgres> for MarketRegime {
3041
0
        fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
3042
0
            let value = match self {
3043
0
                MarketRegime::Normal => "NORMAL",
3044
0
                MarketRegime::Crisis => "CRISIS",
3045
0
                MarketRegime::Trending => "TRENDING",
3046
0
                MarketRegime::Sideways => "SIDEWAYS",
3047
0
                MarketRegime::Bull => "BULL",
3048
0
                MarketRegime::Bear => "BEAR",
3049
0
                MarketRegime::HighVolatility => "HIGH_VOLATILITY",
3050
0
                MarketRegime::LowVolatility => "LOW_VOLATILITY",
3051
0
                MarketRegime::Volatile => "VOLATILE",
3052
0
                MarketRegime::Calm => "CALM",
3053
0
                MarketRegime::Unknown => "UNKNOWN",
3054
0
                MarketRegime::Recovery => "RECOVERY",
3055
0
                MarketRegime::Bubble => "BUBBLE",
3056
0
                MarketRegime::Correction => "CORRECTION",
3057
0
                MarketRegime::Custom(id) => {
3058
0
                    return <String as Encode<Postgres>>::encode_by_ref(
3059
0
                        &format!("CUSTOM_{}", id),
3060
0
                        buf,
3061
                    )
3062
                },
3063
            };
3064
0
            <&str as Encode<Postgres>>::encode_by_ref(&value, buf)
3065
0
        }
3066
    }
3067
3068
    impl<'r> Decode<'r, Postgres> for MarketRegime {
3069
0
        fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
3070
0
            let s = <String as Decode<Postgres>>::decode(value)?;
3071
0
            match s.as_str() {
3072
0
                "NORMAL" => Ok(MarketRegime::Normal),
3073
0
                "CRISIS" => Ok(MarketRegime::Crisis),
3074
0
                "TRENDING" => Ok(MarketRegime::Trending),
3075
0
                "SIDEWAYS" => Ok(MarketRegime::Sideways),
3076
0
                "BULL" => Ok(MarketRegime::Bull),
3077
0
                "BEAR" => Ok(MarketRegime::Bear),
3078
0
                "HIGH_VOLATILITY" => Ok(MarketRegime::HighVolatility),
3079
0
                "LOW_VOLATILITY" => Ok(MarketRegime::LowVolatility),
3080
0
                "VOLATILE" => Ok(MarketRegime::Volatile),
3081
0
                "CALM" => Ok(MarketRegime::Calm),
3082
0
                "UNKNOWN" => Ok(MarketRegime::Unknown),
3083
0
                "RECOVERY" => Ok(MarketRegime::Recovery),
3084
0
                "BUBBLE" => Ok(MarketRegime::Bubble),
3085
0
                "CORRECTION" => Ok(MarketRegime::Correction),
3086
                _ => {
3087
                    // Handle Custom(id) format
3088
0
                    if let Some(id_str) = s.strip_prefix("CUSTOM_") {
3089
0
                        if let Ok(id) = id_str.parse::<usize>() {
3090
0
                            Ok(MarketRegime::Custom(id))
3091
                        } else {
3092
0
                            Err(format!("Invalid MarketRegime Custom ID: {}", id_str).into())
3093
                        }
3094
                    } else {
3095
0
                        Err(format!("Invalid MarketRegime value: {}", s).into())
3096
                    }
3097
                },
3098
            }
3099
0
        }
3100
    }
3101
3102
    // SQLx implementations for HftTimestamp
3103
    // Maps to PostgreSQL BIGINT (stores nanoseconds since Unix epoch)
3104
    // Note: Limited to i64::MAX nanoseconds (year 2262) due to PostgreSQL BIGINT constraints
3105
    impl<'q> Encode<'q, Postgres> for HftTimestamp {
3106
0
        fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
3107
            // Cast u64 to i64 for PostgreSQL BIGINT compatibility
3108
0
            <i64 as Encode<Postgres>>::encode(self.nanos() as i64, buf)
3109
0
        }
3110
    }
3111
3112
    impl<'r> Decode<'r, Postgres> for HftTimestamp {
3113
0
        fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
3114
0
            let val = <i64 as Decode<Postgres>>::decode(value)?;
3115
            // Cast i64 back to u64 for internal representation
3116
0
            Ok(HftTimestamp::from_nanos(val as u64))
3117
0
        }
3118
    }
3119
3120
    impl Type<Postgres> for HftTimestamp {
3121
0
        fn type_info() -> <Postgres as sqlx::Database>::TypeInfo {
3122
0
            <i64 as Type<Postgres>>::type_info()
3123
0
        }
3124
3125
0
        fn compatible(ty: &<Postgres as sqlx::Database>::TypeInfo) -> bool {
3126
0
            <i64 as Type<Postgres>>::compatible(ty)
3127
0
        }
3128
    }
3129
3130
    // SQLx implementations for OrderId (uses BIGINT for u64)
3131
    impl Type<Postgres> for super::OrderId {
3132
0
        fn type_info() -> PgTypeInfo {
3133
0
            PgTypeInfo::with_name("BIGINT")
3134
0
        }
3135
    }
3136
3137
    impl<'q> Encode<'q, Postgres> for super::OrderId {
3138
0
        fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
3139
0
            <i64 as Encode<Postgres>>::encode_by_ref(&(self.value() as i64), buf)
3140
0
        }
3141
    }
3142
3143
    impl<'r> Decode<'r, Postgres> for super::OrderId {
3144
0
        fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
3145
0
            let id = <i64 as Decode<Postgres>>::decode(value)?;
3146
0
            Ok(super::OrderId::from_u64(id as u64))
3147
0
        }
3148
    }
3149
}
3150
3151
/// Volume type - alias for Quantity with the same fixed-point arithmetic
3152
/// SQLx traits are automatically inherited from Quantity
3153
pub type Volume = Quantity;
3154
3155
// ORDER TYPES ALREADY DEFINED ABOVE - No need to re-export from trading_engine
3156
// =============================================================================
3157
// CORE ID TYPES (MOVED FROM TRADING_ENGINE)
3158
// =============================================================================
3159
3160
/// Order identifier with ultra-fast atomic generation
3161
/// Replaces slow UUID generation (1ms+) with atomic increment (~5ns)
3162
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
3163
pub struct OrderId(u64);
3164
3165
impl Default for OrderId {
3166
0
    fn default() -> Self {
3167
0
        Self::new()
3168
0
    }
3169
}
3170
3171
impl OrderId {
3172
    /// Generate next `OrderId` using atomic counter - <50ns performance
3173
1.01k
    pub fn new() -> Self {
3174
        use std::sync::atomic::{AtomicU64, Ordering};
3175
        static COUNTER: AtomicU64 = AtomicU64::new(1);
3176
1.01k
        Self(COUNTER.fetch_add(1, Ordering::Relaxed))
3177
1.01k
    }
3178
3179
    /// Create `OrderId` from u64 value
3180
    #[must_use]
3181
2
    pub const fn from_u64(value: u64) -> Self {
3182
2
        Self(value)
3183
2
    }
3184
3185
    /// Get u64 value
3186
    #[must_use]
3187
8
    pub const fn value(&self) -> u64 {
3188
8
        self.0
3189
8
    }
3190
3191
    /// Get u64 value for performance-critical code (alias for value)
3192
    #[must_use]
3193
1
    pub const fn as_u64(&self) -> u64 {
3194
1
        self.0
3195
1
    }
3196
3197
    /// Get as string for compatibility
3198
    #[must_use]
3199
0
    pub fn as_str(&self) -> String {
3200
0
        self.0.to_string()
3201
0
    }
3202
}
3203
3204
impl fmt::Display for OrderId {
3205
    /// Format the order ID for display
3206
1
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3207
1
        write!(f, "{}", self.0)
3208
1
    }
3209
}
3210
3211
impl From<u64> for OrderId {
3212
    /// Create an OrderId from a u64 value
3213
0
    fn from(value: u64) -> Self {
3214
0
        Self(value)
3215
0
    }
3216
}
3217
3218
impl From<OrderId> for u64 {
3219
    /// Convert an OrderId to u64
3220
0
    fn from(order_id: OrderId) -> Self {
3221
0
        order_id.0
3222
0
    }
3223
}
3224
3225
impl FromStr for OrderId {
3226
    type Err = ParseIntError;
3227
3228
2
    fn from_str(s: &str) -> Result<Self, Self::Err> {
3229
2
        s.parse::<u64>().map(OrderId)
3230
2
    }
3231
}
3232
3233
impl From<String> for OrderId {
3234
    /// Create an OrderId from a String, generating new ID if parsing fails
3235
2
    fn from(s: String) -> Self {
3236
2
        s.parse().unwrap_or_else(|_| 
Self::new1
())
3237
2
    }
3238
}
3239
3240
impl From<&str> for OrderId {
3241
    /// Create an OrderId from a &str, generating new ID if parsing fails
3242
0
    fn from(s: &str) -> Self {
3243
0
        s.parse().unwrap_or_else(|_| Self::new())
3244
0
    }
3245
}
3246
3247
/// Execution identifier with validation
3248
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
3249
#[cfg_attr(feature = "database", derive(sqlx::Type))]
3250
pub struct ExecutionId(String);
3251
3252
impl ExecutionId {
3253
    /// Create a new execution ID with validation
3254
3
    pub fn new<S: Into<String>>(id: S) -> Result<Self, CommonTypeError> {
3255
3
        let id = id.into();
3256
3
        if id.trim().is_empty() {
3257
2
            return Err(CommonTypeError::ValidationError {
3258
2
                field: "execution_id".to_owned(),
3259
2
                reason: "Execution ID cannot be empty".to_owned(),
3260
2
            });
3261
1
        }
3262
1
        Ok(Self(id))
3263
3
    }
3264
3265
    /// Generate a new random execution ID
3266
1
    pub fn generate() -> Self {
3267
1
        Self(uuid::Uuid::new_v4().to_string())
3268
1
    }
3269
3270
    /// Get execution ID as string slice
3271
3
    pub fn as_str(&self) -> &str {
3272
3
        &self.0
3273
3
    }
3274
3275
    /// Convert execution ID into owned string
3276
0
    pub fn into_string(self) -> String {
3277
0
        self.0
3278
0
    }
3279
}
3280
3281
impl fmt::Display for ExecutionId {
3282
    /// Format the execution ID for display
3283
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3284
0
        write!(f, "{}", self.0)
3285
0
    }
3286
}
3287
3288
impl FromStr for ExecutionId {
3289
    type Err = CommonTypeError;
3290
3291
0
    fn from_str(s: &str) -> Result<Self, Self::Err> {
3292
0
        Self::new(s)
3293
0
    }
3294
}
3295
3296
/// Trade identifier with validation
3297
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
3298
pub struct TradeId(String);
3299
3300
impl TradeId {
3301
    /// Create a new trade ID with validation
3302
2
    pub fn new<S: Into<String>>(id: S) -> Result<Self, CommonTypeError> {
3303
2
        let id = id.into();
3304
2
        if id.is_empty() {
3305
1
            return Err(CommonTypeError::ValidationError {
3306
1
                field: "trade_id".to_owned(),
3307
1
                reason: "Trade ID cannot be empty".to_owned(),
3308
1
            });
3309
1
        }
3310
1
        Ok(Self(id))
3311
2
    }
3312
3313
    /// Get the trade ID as a string slice
3314
1
    pub fn as_str(&self) -> &str {
3315
1
        &self.0
3316
1
    }
3317
    /// Convert the trade ID into an owned string
3318
0
    pub fn into_string(self) -> String {
3319
0
        self.0
3320
0
    }
3321
}
3322
3323
impl fmt::Display for TradeId {
3324
    /// Format the trade ID for display
3325
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3326
0
        write!(f, "{}", self.0)
3327
0
    }
3328
}
3329
3330
/// Trading symbol with validation
3331
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
3332
#[cfg_attr(feature = "database", derive(sqlx::Type))]
3333
pub struct Symbol {
3334
    value: String,
3335
}
3336
3337
impl Symbol {
3338
    /// Create a new symbol from a string
3339
    #[must_use]
3340
20
    pub const fn new(s: String) -> Self {
3341
20
        Self { value: s }
3342
20
    }
3343
3344
    /// Create a new Symbol with validation
3345
6
    pub fn new_validated(s: String) -> Result<Self, CommonTypeError> {
3346
6
        if s.trim().is_empty() {
3347
4
            return Err(CommonTypeError::ValidationError {
3348
4
                field: "symbol".to_string(),
3349
4
                reason: "Symbol cannot be empty".to_string(),
3350
4
            });
3351
2
        }
3352
2
        Ok(Self { value: s })
3353
6
    }
3354
3355
    /// Create a Symbol from &str with validation
3356
0
    pub fn from_str_validated(s: &str) -> Result<Self, CommonTypeError> {
3357
0
        Self::new_validated(s.to_owned())
3358
0
    }
3359
3360
    /// Get the symbol as a string slice
3361
    #[must_use]
3362
7
    pub fn as_str(&self) -> &str {
3363
7
        &self.value
3364
7
    }
3365
    /// Get the symbol value as a string slice
3366
    #[must_use]
3367
0
    pub fn value(&self) -> &str {
3368
0
        &self.value
3369
0
    }
3370
    /// Get the symbol as bytes
3371
    #[must_use]
3372
0
    pub fn as_bytes(&self) -> &[u8] {
3373
0
        self.value.as_bytes()
3374
0
    }
3375
    /// Check if the symbol is empty
3376
    #[must_use]
3377
2
    pub fn is_empty(&self) -> bool {
3378
2
        self.value.is_empty()
3379
2
    }
3380
    /// Convert the symbol to uppercase
3381
    #[must_use]
3382
2
    pub fn to_uppercase(&self) -> String {
3383
2
        self.value.to_uppercase()
3384
2
    }
3385
    /// Replace occurrences in the symbol
3386
    #[must_use]
3387
2
    pub fn replace(&self, from: &str, to: &str) -> String {
3388
2
        self.value.replace(from, to)
3389
2
    }
3390
3391
    /// Helper for risk management - creates a 'NONE' symbol
3392
    #[must_use]
3393
1
    pub fn none() -> Self {
3394
1
        "NONE".parse().unwrap()
3395
1
    }
3396
3397
    /// Check if the symbol contains a pattern
3398
    #[must_use]
3399
4
    pub fn contains(&self, pattern: &str) -> bool {
3400
4
        self.value.contains(pattern)
3401
4
    }
3402
}
3403
3404
impl FromStr for Symbol {
3405
    type Err = std::convert::Infallible;
3406
3407
6
    fn from_str(s: &str) -> Result<Self, Self::Err> {
3408
6
        Ok(Self {
3409
6
            value: s.to_owned(),
3410
6
        })
3411
6
    }
3412
}
3413
3414
// Additional implementation to support conversion from &Symbol to &str
3415
impl AsRef<str> for Symbol {
3416
    /// Convert symbol to string reference
3417
0
    fn as_ref(&self) -> &str {
3418
0
        &self.value
3419
0
    }
3420
}
3421
3422
impl fmt::Display for Symbol {
3423
    /// Format the symbol for display
3424
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3425
0
        write!(f, "{}", self.value)
3426
0
    }
3427
}
3428
3429
impl From<String> for Symbol {
3430
    /// Create a Symbol from a String
3431
0
    fn from(s: String) -> Self {
3432
0
        Self::new(s)
3433
0
    }
3434
}
3435
impl From<&str> for Symbol {
3436
    /// Create a Symbol from a &str
3437
19
    fn from(s: &str) -> Self {
3438
19
        Self::new(s.to_owned())
3439
19
    }
3440
}
3441
3442
// TryFrom implementations removed due to conflicting blanket implementations
3443
// Use Symbol::new_validated() or Symbol::from_validated() directly instead
3444
3445
impl Default for Symbol {
3446
    /// Returns the default symbol (empty string)
3447
0
    fn default() -> Self {
3448
0
        Self::new(String::new())
3449
0
    }
3450
}
3451
3452
impl PartialEq<str> for Symbol {
3453
0
    fn eq(&self, other: &str) -> bool {
3454
0
        self.value == other
3455
0
    }
3456
}
3457
3458
impl PartialEq<&str> for Symbol {
3459
2
    fn eq(&self, other: &&str) -> bool {
3460
2
        self.value == *other
3461
2
    }
3462
}
3463
3464
impl PartialEq<String> for Symbol {
3465
1
    fn eq(&self, other: &String) -> bool {
3466
1
        &self.value == other
3467
1
    }
3468
}
3469
3470
impl PartialEq<Symbol> for &str {
3471
2
    fn eq(&self, other: &Symbol) -> bool {
3472
2
        *self == other.value
3473
2
    }
3474
}
3475
3476
impl PartialEq<Symbol> for String {
3477
1
    fn eq(&self, other: &Symbol) -> bool {
3478
1
        self == &other.value
3479
1
    }
3480
}
3481
3482
// TimeInForce moved to canonical source: common::types::TimeInForce
3483
3484
// Currency moved to canonical source: common::types::Currency
3485
3486
// Price moved to canonical source: common::types::Price
3487
3488
// Quantity moved to canonical source: common::types::Quantity
3489
// Volume moved to canonical source: common::types::Quantity (as Volume alias)
3490
3491
/// Money amount with currency
3492
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
3493
pub struct Money {
3494
    /// The monetary amount
3495
    pub amount: Decimal,
3496
    /// The currency of the amount
3497
    pub currency: Currency,
3498
}
3499
3500
impl Money {
3501
    /// Create new money amount
3502
3
    pub const fn new(amount: Decimal, currency: Currency) -> Self {
3503
3
        Self { amount, currency }
3504
3
    }
3505
}
3506
3507
impl fmt::Display for Money {
3508
2
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3509
2
        write!(f, "{} {}", self.amount, self.currency)
3510
2
    }
3511
}
3512
3513
// OrderId moved to canonical source: common::types::OrderId
3514
3515
// TradeId moved to canonical source: common::types::TradeId
3516
3517
// Symbol moved to canonical source: common::types::Symbol
3518
3519
/// Type-safe account identifier
3520
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
3521
pub struct AccountId(String);
3522
3523
impl AccountId {
3524
    /// Create a new account ID with validation
3525
3
    pub fn new<S: Into<String>>(id: S) -> Result<Self, CommonTypeError> {
3526
3
        let id = id.into();
3527
3
        if id.trim().is_empty() {
3528
2
            return Err(CommonTypeError::InvalidIdentifier {
3529
2
                field: "account_id".to_string(),
3530
2
                reason: "Account ID cannot be empty".to_string(),
3531
2
            });
3532
1
        }
3533
1
        Ok(Self(id))
3534
3
    }
3535
3536
    /// Get the ID as a string slice
3537
0
    pub fn as_str(&self) -> &str {
3538
0
        &self.0
3539
0
    }
3540
3541
    /// Convert to owned String
3542
0
    pub fn into_string(self) -> String {
3543
0
        self.0
3544
0
    }
3545
}
3546
3547
impl fmt::Display for AccountId {
3548
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3549
0
        write!(f, "{}", self.0)
3550
0
    }
3551
}
3552
3553
/// High-precision timestamp for HFT applications - CANONICAL DEFINITION
3554
/// Robust implementation with error handling for financial safety
3555
#[derive(
3556
    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Default,
3557
)]
3558
pub struct HftTimestamp {
3559
    nanos: u64,
3560
}
3561
3562
impl HftTimestamp {
3563
    /// Get current timestamp with error handling for financial safety
3564
26
    pub fn now() -> Result<Self, CommonError> {
3565
        use std::time::{SystemTime, UNIX_EPOCH};
3566
26
        let nanos = SystemTime::now()
3567
26
            .duration_since(UNIX_EPOCH)
3568
26
            .map_err(|e| CommonError::Service {
3569
0
                category: CommonErrorCategory::System,
3570
0
                message: format!("System time before UNIX epoch: {e}"),
3571
0
            })?
3572
26
            .as_nanos() as u64;
3573
26
        Ok(Self { nanos })
3574
26
    }
3575
3576
    /// Get current timestamp with error handling for financial safety (CommonTypeError version)
3577
1
    pub fn now_common() -> Result<Self, CommonTypeError> {
3578
        use std::time::{SystemTime, UNIX_EPOCH};
3579
1
        let nanos = SystemTime::now()
3580
1
            .duration_since(UNIX_EPOCH)
3581
1
            .map_err(|e| CommonTypeError::ConversionError {
3582
0
                message: format!("System time before UNIX epoch: {e}"),
3583
0
            })?
3584
1
            .as_nanos() as u64;
3585
1
        Ok(Self { nanos })
3586
1
    }
3587
3588
    /// Get current timestamp or zero if system time is invalid
3589
    #[must_use]
3590
25
    pub fn now_or_zero() -> Self {
3591
25
        Self::now().unwrap_or(Self { nanos: 0 })
3592
25
    }
3593
3594
    /// Get nanoseconds since epoch
3595
    #[must_use]
3596
4
    pub const fn nanos(self) -> u64 {
3597
4
        self.nanos
3598
4
    }
3599
3600
    /// Create from nanoseconds since epoch
3601
    #[must_use]
3602
2
    pub const fn from_nanos(nanos: u64) -> Self {
3603
2
        Self { nanos }
3604
2
    }
3605
3606
    /// Create from signed nanoseconds (cast to unsigned)
3607
    #[must_use]
3608
0
    pub const fn from_nanos_i64(nanos: i64) -> Self {
3609
0
        Self {
3610
0
            nanos: nanos as u64,
3611
0
        }
3612
0
    }
3613
3614
    /// Get nanoseconds since epoch
3615
0
    pub const fn as_nanos(&self) -> u64 {
3616
0
        self.nanos
3617
0
    }
3618
3619
    /// Convert to DateTime<Utc>
3620
1
    pub fn to_datetime(&self) -> DateTime<Utc> {
3621
1
        let secs = self.nanos / 1_000_000_000;
3622
1
        let nsecs = (self.nanos % 1_000_000_000) as u32;
3623
1
        DateTime::from_timestamp(secs as i64, nsecs).unwrap_or_default()
3624
1
    }
3625
}
3626
3627
impl fmt::Display for HftTimestamp {
3628
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3629
0
        write!(f, "{}", self.to_datetime())
3630
0
    }
3631
}
3632
3633
/// Generic timestamp for general use cases
3634
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
3635
pub struct GenericTimestamp {
3636
    nanos: u64,
3637
}
3638
3639
impl GenericTimestamp {
3640
    /// Create from nanoseconds since epoch
3641
    #[must_use]
3642
0
    pub const fn from_nanos(nanos: u64) -> Self {
3643
0
        Self { nanos }
3644
0
    }
3645
3646
    /// Get nanoseconds since epoch
3647
    #[must_use]
3648
0
    pub const fn nanos(&self) -> u64 {
3649
0
        self.nanos
3650
0
    }
3651
}
3652
3653
// =============================================================================
3654
// MARKET TYPES (MIGRATED FROM TRADING_ENGINE)
3655
// =============================================================================
3656
3657
/// Market regime enumeration for position sizing scaling and risk management
3658
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
3659
pub enum MarketRegime {
3660
    /// Normal market conditions
3661
    Normal,
3662
    /// Crisis/stress market conditions
3663
    Crisis,
3664
    /// Trending market (strong directional movement)
3665
    Trending,
3666
    /// Sideways/ranging market (low volatility)
3667
    Sideways,
3668
    /// Bull market (sustained upward trend)
3669
    Bull,
3670
    /// Bear market (sustained downward trend)
3671
    Bear,
3672
    /// High volatility market conditions
3673
    HighVolatility,
3674
    /// Low volatility market conditions
3675
    LowVolatility,
3676
    /// Volatile market conditions (alias for `HighVolatility`)
3677
    Volatile,
3678
    /// Calm market conditions (alias for `LowVolatility`)
3679
    Calm,
3680
    /// Unknown/unclassified regime
3681
    Unknown,
3682
    /// Recovery regime - transitioning from crisis
3683
    Recovery,
3684
    /// Bubble regime - unsustainable upward movement
3685
    Bubble,
3686
    /// Correction regime - temporary downward adjustment
3687
    Correction,
3688
    /// Custom regime with numeric identifier
3689
    Custom(usize),
3690
}
3691
3692
impl Default for MarketRegime {
3693
0
    fn default() -> Self {
3694
0
        Self::Normal
3695
0
    }
3696
}
3697
3698
impl fmt::Display for MarketRegime {
3699
6
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3700
6
        match self {
3701
1
            Self::Normal => write!(f, "Normal"),
3702
1
            Self::Crisis => write!(f, "Crisis"),
3703
0
            Self::Trending => write!(f, "Trending"),
3704
0
            Self::Sideways => write!(f, "Sideways"),
3705
1
            Self::Bull => write!(f, "Bull"),
3706
1
            Self::Bear => write!(f, "Bear"),
3707
1
            Self::HighVolatility => write!(f, "HighVolatility"),
3708
0
            Self::LowVolatility => write!(f, "LowVolatility"),
3709
0
            Self::Volatile => write!(f, "Volatile"),
3710
0
            Self::Calm => write!(f, "Calm"),
3711
0
            Self::Unknown => write!(f, "Unknown"),
3712
0
            Self::Recovery => write!(f, "Recovery"),
3713
0
            Self::Bubble => write!(f, "Bubble"),
3714
0
            Self::Correction => write!(f, "Correction"),
3715
1
            Self::Custom(id) => write!(f, "Custom({id})"),
3716
        }
3717
6
    }
3718
}
3719
3720
/// Tick type enumeration for market data
3721
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
3722
#[cfg_attr(feature = "database", derive(sqlx::Type))]
3723
#[cfg_attr(
3724
    feature = "database",
3725
    sqlx(type_name = "tick_type", rename_all = "snake_case")
3726
)]
3727
pub enum TickType {
3728
    /// Trade execution tick
3729
    Trade,
3730
    /// Bid price update tick
3731
    Bid,
3732
    /// Ask price update tick
3733
    Ask,
3734
    /// Quote (bid/ask) update tick
3735
    Quote,
3736
}
3737
3738
/// Exchange enumeration for trading venues
3739
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
3740
pub enum Exchange {
3741
    /// New York Stock Exchange
3742
    NYSE,
3743
    /// NASDAQ
3744
    NASDAQ,
3745
    /// Chicago Mercantile Exchange
3746
    CME,
3747
    /// Intercontinental Exchange
3748
    ICE,
3749
    /// London Stock Exchange
3750
    LSE,
3751
    /// Tokyo Stock Exchange
3752
    TSE,
3753
    /// Hong Kong Stock Exchange
3754
    HKEX,
3755
    /// Shanghai Stock Exchange
3756
    SSE,
3757
    /// Shenzhen Stock Exchange
3758
    SZSE,
3759
    /// Euronext
3760
    EURONEXT,
3761
    /// Deutsche Börse
3762
    XETRA,
3763
    /// Chicago Board of Trade
3764
    CBOT,
3765
    /// Chicago Board Options Exchange
3766
    CBOE,
3767
    /// BATS Global Markets
3768
    BATS,
3769
    /// IEX Exchange
3770
    IEX,
3771
    /// Interactive Brokers
3772
    IBKR,
3773
    /// IC Markets
3774
    ICMARKETS,
3775
    /// Forex.com
3776
    FOREX,
3777
    /// Binance
3778
    BINANCE,
3779
    /// Coinbase
3780
    COINBASE,
3781
    /// Kraken
3782
    KRAKEN,
3783
    /// Unknown or unrecognized exchange
3784
    UNKNOWN,
3785
}
3786
3787
impl Default for Exchange {
3788
0
    fn default() -> Self {
3789
0
        Self::UNKNOWN
3790
0
    }
3791
}
3792
3793
impl fmt::Display for Exchange {
3794
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3795
0
        match self {
3796
0
            Self::NYSE => write!(f, "NYSE"),
3797
0
            Self::NASDAQ => write!(f, "NASDAQ"),
3798
0
            Self::CME => write!(f, "CME"),
3799
0
            Self::ICE => write!(f, "ICE"),
3800
0
            Self::LSE => write!(f, "LSE"),
3801
0
            Self::TSE => write!(f, "TSE"),
3802
0
            Self::HKEX => write!(f, "HKEX"),
3803
0
            Self::SSE => write!(f, "SSE"),
3804
0
            Self::SZSE => write!(f, "SZSE"),
3805
0
            Self::EURONEXT => write!(f, "EURONEXT"),
3806
0
            Self::XETRA => write!(f, "XETRA"),
3807
0
            Self::CBOT => write!(f, "CBOT"),
3808
0
            Self::CBOE => write!(f, "CBOE"),
3809
0
            Self::BATS => write!(f, "BATS"),
3810
0
            Self::IEX => write!(f, "IEX"),
3811
0
            Self::IBKR => write!(f, "IBKR"),
3812
0
            Self::ICMARKETS => write!(f, "ICMARKETS"),
3813
0
            Self::FOREX => write!(f, "FOREX"),
3814
0
            Self::BINANCE => write!(f, "BINANCE"),
3815
0
            Self::COINBASE => write!(f, "COINBASE"),
3816
0
            Self::KRAKEN => write!(f, "KRAKEN"),
3817
0
            Self::UNKNOWN => write!(f, "UNKNOWN"),
3818
        }
3819
0
    }
3820
}
3821
3822
impl FromStr for Exchange {
3823
    type Err = CommonTypeError;
3824
3825
4
    fn from_str(s: &str) -> Result<Self, Self::Err> {
3826
4
        match s.to_uppercase().as_str() {
3827
4
            "NYSE" => 
Ok(Self::NYSE)1
,
3828
3
            "NASDAQ" => 
Ok(Self::NASDAQ)2
,
3829
1
            "CME" => 
Ok(Self::CME)0
,
3830
1
            "ICE" => 
Ok(Self::ICE)0
,
3831
1
            "LSE" => 
Ok(Self::LSE)0
,
3832
1
            "TSE" => 
Ok(Self::TSE)0
,
3833
1
            "HKEX" => 
Ok(Self::HKEX)0
,
3834
1
            "SSE" => 
Ok(Self::SSE)0
,
3835
1
            "SZSE" => 
Ok(Self::SZSE)0
,
3836
1
            "EURONEXT" => 
Ok(Self::EURONEXT)0
,
3837
1
            "XETRA" => 
Ok(Self::XETRA)0
,
3838
1
            "CBOT" => 
Ok(Self::CBOT)0
,
3839
1
            "CBOE" => 
Ok(Self::CBOE)0
,
3840
1
            "BATS" => 
Ok(Self::BATS)0
,
3841
1
            "IEX" => 
Ok(Self::IEX)0
,
3842
1
            "IBKR" => 
Ok(Self::IBKR)0
,
3843
1
            "ICMARKETS" => 
Ok(Self::ICMARKETS)0
,
3844
1
            "FOREX" => 
Ok(Self::FOREX)0
,
3845
1
            "BINANCE" => 
Ok(Self::BINANCE)0
,
3846
1
            "COINBASE" => 
Ok(Self::COINBASE)0
,
3847
1
            "KRAKEN" => 
Ok(Self::KRAKEN)0
,
3848
1
            "UNKNOWN" => 
Ok(Self::UNKNOWN)0
,
3849
1
            _ => Ok(Self::UNKNOWN), // Default to UNKNOWN for unrecognized exchanges
3850
        }
3851
4
    }
3852
}
3853
3854
/// Market tick data structure - CANONICAL SINGLE SOURCE OF TRUTH
3855
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
3856
pub struct MarketTick {
3857
    /// Trading symbol
3858
    pub symbol: Symbol,
3859
    /// Tick price
3860
    pub price: Price,
3861
    /// Tick size/quantity
3862
    pub size: Quantity,
3863
    /// Tick timestamp
3864
    pub timestamp: HftTimestamp,
3865
    /// Type of tick (trade, bid, ask, quote)
3866
    pub tick_type: TickType,
3867
    /// Exchange where the tick occurred
3868
    pub exchange: Exchange,
3869
    /// Sequence number for ordering
3870
    pub sequence_number: u64,
3871
}
3872
3873
impl MarketTick {
3874
    /// Create a new market tick with current timestamp
3875
0
    pub fn new(
3876
0
        symbol: Symbol,
3877
0
        price: Price,
3878
0
        size: Quantity,
3879
0
        tick_type: TickType,
3880
0
        exchange: Exchange,
3881
0
        sequence_number: u64,
3882
0
    ) -> Result<Self, CommonError> {
3883
        Ok(Self {
3884
0
            symbol,
3885
0
            price,
3886
0
            size,
3887
0
            timestamp: HftTimestamp::now()?,
3888
0
            tick_type,
3889
0
            exchange,
3890
0
            sequence_number,
3891
        })
3892
0
    }
3893
3894
    /// Create a new market tick with specified timestamp (for backtesting)
3895
    #[must_use]
3896
0
    pub const fn with_timestamp(
3897
0
        symbol: Symbol,
3898
0
        price: Price,
3899
0
        size: Quantity,
3900
0
        timestamp: HftTimestamp,
3901
0
        tick_type: TickType,
3902
0
        exchange: Exchange,
3903
0
        sequence_number: u64,
3904
0
    ) -> Self {
3905
0
        Self {
3906
0
            symbol,
3907
0
            price,
3908
0
            size,
3909
0
            timestamp,
3910
0
            tick_type,
3911
0
            exchange,
3912
0
            sequence_number,
3913
0
        }
3914
0
    }
3915
}
3916
3917
/// Trading signal for algorithmic trading
3918
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3919
pub struct TradingSignal {
3920
    /// Signal ID
3921
    pub signal_id: Uuid,
3922
    /// Symbol this signal applies to
3923
    pub symbol: Symbol,
3924
    /// Signal strength (-1.0 to 1.0)
3925
    pub strength: f64,
3926
    /// Signal direction
3927
    pub direction: OrderSide,
3928
    /// Confidence level (0.0 to 1.0)
3929
    pub confidence: f64,
3930
    /// Signal generation timestamp
3931
    pub timestamp: HftTimestamp,
3932
    /// Signal source/strategy
3933
    pub source: String,
3934
    /// Additional metadata
3935
    pub metadata: std::collections::HashMap<String, String>,
3936
}
3937
3938
impl TradingSignal {
3939
    /// Create a new trading signal
3940
3
    pub fn new(
3941
3
        symbol: Symbol,
3942
3
        strength: f64,
3943
3
        direction: OrderSide,
3944
3
        confidence: f64,
3945
3
        source: String,
3946
3
    ) -> Result<Self, CommonTypeError> {
3947
3
        if !(0.0..=1.0).contains(&confidence) {
3948
1
            return Err(CommonTypeError::ValidationError {
3949
1
                field: "confidence".to_owned(),
3950
1
                reason: "Confidence must be between 0.0 and 1.0".to_owned(),
3951
1
            });
3952
2
        }
3953
2
        if !(-1.0..=1.0).contains(&strength) {
3954
1
            return Err(CommonTypeError::ValidationError {
3955
1
                field: "strength".to_owned(),
3956
1
                reason: "Strength must be between -1.0 and 1.0".to_owned(),
3957
1
            });
3958
1
        }
3959
3960
        Ok(Self {
3961
1
            signal_id: Uuid::new_v4(),
3962
1
            symbol,
3963
1
            strength,
3964
1
            direction,
3965
1
            confidence,
3966
1
            timestamp: HftTimestamp::now_common()
?0
,
3967
1
            source,
3968
1
            metadata: std::collections::HashMap::new(),
3969
        })
3970
3
    }
3971
3972
    /// Add metadata to the signal
3973
    #[must_use]
3974
0
    pub fn with_metadata(mut self, key: String, value: String) -> Self {
3975
0
        self.metadata.insert(key, value);
3976
0
        self
3977
0
    }
3978
}
3979
3980
// =============================================================================
3981
// HIGH-PERFORMANCE TYPES FOR COPY/CLONE OPTIMIZATION
3982
// =============================================================================
3983
3984
/// Lightweight Order reference for high-performance contexts requiring Copy trait
3985
///
3986
/// This struct contains only the essential order data needed for performance-critical
3987
/// operations like `SmallBatchRing` processing, while maintaining Copy semantics.
3988
/// For full order details, use the complete Order struct.
3989
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
3990
pub struct OrderRef {
3991
    /// Order ID (u64 for performance)
3992
    pub id: u64,
3993
    /// Symbol hash for fast lookups
3994
    pub symbol_hash: i64,
3995
    /// Order side (Buy/Sell)
3996
    pub side: OrderSide,
3997
    /// Order type
3998
    pub order_type: OrderType,
3999
    /// Quantity (fixed-point u64)
4000
    pub quantity: u64,
4001
    /// Price (fixed-point u64, 0 for market orders)
4002
    pub price: u64,
4003
    /// Timestamp (nanoseconds since epoch)
4004
    pub timestamp: u64,
4005
}
4006
4007
impl OrderRef {
4008
    /// Create `OrderRef` from a full Order struct
4009
    #[must_use]
4010
1
    pub fn from_order(order: &Order) -> Self {
4011
        Self {
4012
1
            id: order.id.value(),
4013
1
            symbol_hash: order.symbol_hash(),
4014
1
            side: order.side,
4015
1
            order_type: order.order_type,
4016
1
            quantity: order.quantity.raw_value(),
4017
1
            price: order.price.map_or(0, |p| p.raw_value()),
4018
1
            timestamp: order.created_at.nanos(),
4019
        }
4020
1
    }
4021
4022
    /// Create a limit order reference
4023
    #[must_use]
4024
0
    pub fn limit(symbol_hash: i64, side: OrderSide, quantity: u64, price: u64) -> Self {
4025
0
        Self {
4026
0
            id: OrderId::new().value(),
4027
0
            symbol_hash,
4028
0
            side,
4029
0
            order_type: OrderType::Limit,
4030
0
            quantity,
4031
0
            price,
4032
0
            timestamp: HftTimestamp::now_or_zero().nanos(),
4033
0
        }
4034
0
    }
4035
4036
    /// Create a market order reference  
4037
    #[must_use]
4038
0
    pub fn market(symbol_hash: i64, side: OrderSide, quantity: u64) -> Self {
4039
0
        Self {
4040
0
            id: OrderId::new().value(),
4041
0
            symbol_hash,
4042
0
            side,
4043
0
            order_type: OrderType::Market,
4044
0
            quantity,
4045
0
            price: 0,
4046
0
            timestamp: HftTimestamp::now_or_zero().nanos(),
4047
0
        }
4048
0
    }
4049
4050
    /// Get quantity as Quantity type
4051
    #[must_use]
4052
0
    pub const fn get_quantity(&self) -> Quantity {
4053
0
        Quantity::from_raw(self.quantity)
4054
0
    }
4055
4056
    /// Get price as Price type (None for market orders)
4057
    #[must_use]
4058
0
    pub const fn get_price(&self) -> Option<Price> {
4059
0
        if self.price == 0 {
4060
0
            None
4061
        } else {
4062
0
            Some(Price::from_raw(self.price))
4063
        }
4064
0
    }
4065
4066
    /// Check if this is a buy order
4067
    #[must_use]
4068
0
    pub fn is_buy(&self) -> bool {
4069
0
        self.side == OrderSide::Buy
4070
0
    }
4071
4072
    /// Check if this is a sell order
4073
    #[must_use]
4074
0
    pub fn is_sell(&self) -> bool {
4075
0
        self.side == OrderSide::Sell
4076
0
    }
4077
4078
    /// Check if this is a market order
4079
    #[must_use]
4080
0
    pub fn is_market_order(&self) -> bool {
4081
0
        self.order_type == OrderType::Market || self.price == 0
4082
0
    }
4083
4084
    /// Check if this is a limit order
4085
    #[must_use]
4086
0
    pub fn is_limit_order(&self) -> bool {
4087
0
        self.order_type == OrderType::Limit && self.price > 0
4088
0
    }
4089
}
4090
4091
impl Default for OrderRef {
4092
0
    fn default() -> Self {
4093
0
        Self {
4094
0
            id: 0,
4095
0
            symbol_hash: 0,
4096
0
            side: OrderSide::Buy,
4097
0
            order_type: OrderType::Market,
4098
0
            quantity: 0,
4099
0
            price: 0,
4100
0
            timestamp: 0,
4101
0
        }
4102
0
    }
4103
}
4104
4105
// =============================================================================
4106
// COMPREHENSIVE TESTS
4107
// =============================================================================
4108
4109
#[cfg(test)]
4110
mod tests {
4111
    use super::*;
4112
    use std::str::FromStr;
4113
4114
    // =============================================================================
4115
    // Price Tests
4116
    // =============================================================================
4117
4118
    #[test]
4119
1
    fn test_price_from_f64_valid() {
4120
1
        let price = Price::from_f64(100.50).unwrap();
4121
1
        assert_eq!(price.to_f64(), 100.50);
4122
1
    }
4123
4124
    #[test]
4125
1
    fn test_price_from_f64_negative() {
4126
1
        let result = Price::from_f64(-10.0);
4127
1
        assert!(result.is_err());
4128
1
    }
4129
4130
    #[test]
4131
1
    fn test_price_from_f64_nan() {
4132
1
        let result = Price::from_f64(f64::NAN);
4133
1
        assert!(result.is_err());
4134
1
    }
4135
4136
    #[test]
4137
1
    fn test_price_from_f64_infinity() {
4138
1
        let result = Price::from_f64(f64::INFINITY);
4139
1
        assert!(result.is_err());
4140
1
    }
4141
4142
    #[test]
4143
1
    fn test_price_constants() {
4144
1
        assert_eq!(Price::ZERO.to_f64(), 0.0);
4145
1
        assert_eq!(Price::ONE.to_f64(), 1.0);
4146
1
        assert_eq!(Price::CENT.to_f64(), 0.01);
4147
1
    }
4148
4149
    #[test]
4150
1
    fn test_price_addition() {
4151
1
        let p1 = Price::from_f64(10.0).unwrap();
4152
1
        let p2 = Price::from_f64(5.5).unwrap();
4153
1
        let result = p1 + p2;
4154
1
        assert!((result.to_f64() - 15.5).abs() < 0.00001);
4155
1
    }
4156
4157
    #[test]
4158
1
    fn test_price_subtraction() {
4159
1
        let p1 = Price::from_f64(10.0).unwrap();
4160
1
        let p2 = Price::from_f64(5.5).unwrap();
4161
1
        let result = p1 - p2;
4162
1
        assert!((result.to_f64() - 4.5).abs() < 0.00001);
4163
1
    }
4164
4165
    #[test]
4166
1
    fn test_price_multiplication() {
4167
1
        let price = Price::from_f64(10.0).unwrap();
4168
1
        let result = (price * 2.5).unwrap();
4169
1
        assert!((result.to_f64() - 25.0).abs() < 0.00001);
4170
1
    }
4171
4172
    #[test]
4173
1
    fn test_price_division() {
4174
1
        let price = Price::from_f64(10.0).unwrap();
4175
1
        let result = (price / 2.0).unwrap();
4176
1
        assert!((result.to_f64() - 5.0).abs() < 0.00001);
4177
1
    }
4178
4179
    #[test]
4180
1
    fn test_price_division_by_zero() {
4181
1
        let price = Price::from_f64(10.0).unwrap();
4182
1
        let result = price / 0.0;
4183
1
        assert!(result.is_err());
4184
1
    }
4185
4186
    #[test]
4187
1
    fn test_price_from_cents() {
4188
1
        let price = Price::from_cents(150);
4189
1
        assert!((price.to_f64() - 1.50).abs() < 0.00001);
4190
1
    }
4191
4192
    #[test]
4193
1
    fn test_price_to_cents() {
4194
1
        let price = Price::from_f64(1.50).unwrap();
4195
1
        assert_eq!(price.to_cents(), 150);
4196
1
    }
4197
4198
    #[test]
4199
1
    fn test_price_is_zero() {
4200
1
        assert!(Price::ZERO.is_zero());
4201
1
        assert!(!Price::from_f64(1.0).unwrap().is_zero());
4202
1
    }
4203
4204
    #[test]
4205
1
    fn test_price_from_str() {
4206
1
        let price = Price::from_str("123.45").unwrap();
4207
1
        assert!((price.to_f64() - 123.45).abs() < 0.00001);
4208
1
    }
4209
4210
    #[test]
4211
1
    fn test_price_from_str_invalid() {
4212
1
        let result = Price::from_str("invalid");
4213
1
        assert!(result.is_err());
4214
1
    }
4215
4216
    #[test]
4217
1
    fn test_price_display() {
4218
1
        let price = Price::from_f64(123.456789).unwrap();
4219
1
        let display = format!("{}", price);
4220
1
        assert!(display.starts_with("123.45678"));
4221
1
    }
4222
4223
    #[test]
4224
1
    fn test_price_partial_eq_f64() {
4225
1
        let price = Price::from_f64(10.0).unwrap();
4226
1
        assert_eq!(price, 10.0);
4227
1
        assert_eq!(10.0, price);
4228
1
    }
4229
4230
    #[test]
4231
1
    fn test_price_multiply_price() {
4232
1
        let p1 = Price::from_f64(10.0).unwrap();
4233
1
        let p2 = Price::from_f64(2.5).unwrap();
4234
1
        let result = p1.multiply(p2).unwrap();
4235
1
        assert!((result.to_f64() - 25.0).abs() < 0.00001);
4236
1
    }
4237
4238
    // =============================================================================
4239
    // Quantity Tests
4240
    // =============================================================================
4241
4242
    #[test]
4243
1
    fn test_quantity_from_f64_valid() {
4244
1
        let qty = Quantity::from_f64(100.5).unwrap();
4245
1
        assert_eq!(qty.to_f64(), 100.5);
4246
1
    }
4247
4248
    #[test]
4249
1
    fn test_quantity_from_f64_negative() {
4250
1
        let result = Quantity::from_f64(-10.0);
4251
1
        assert!(result.is_err());
4252
1
    }
4253
4254
    #[test]
4255
1
    fn test_quantity_from_f64_nan() {
4256
1
        let result = Quantity::from_f64(f64::NAN);
4257
1
        assert!(result.is_err());
4258
1
    }
4259
4260
    #[test]
4261
1
    fn test_quantity_constants() {
4262
1
        assert_eq!(Quantity::ZERO.to_f64(), 0.0);
4263
1
        assert_eq!(Quantity::ONE.to_f64(), 1.0);
4264
1
    }
4265
4266
    #[test]
4267
1
    fn test_quantity_addition() {
4268
1
        let q1 = Quantity::from_f64(10.0).unwrap();
4269
1
        let q2 = Quantity::from_f64(5.5).unwrap();
4270
1
        let result = q1 + q2;
4271
1
        assert!((result.to_f64() - 15.5).abs() < 0.00001);
4272
1
    }
4273
4274
    #[test]
4275
1
    fn test_quantity_subtraction() {
4276
1
        let q1 = Quantity::from_f64(10.0).unwrap();
4277
1
        let q2 = Quantity::from_f64(5.5).unwrap();
4278
1
        let result = q1 - q2;
4279
1
        assert!((result.to_f64() - 4.5).abs() < 0.00001);
4280
1
    }
4281
4282
    #[test]
4283
1
    fn test_quantity_multiplication() {
4284
1
        let qty = Quantity::from_f64(10.0).unwrap();
4285
1
        let result = (qty * 2.5).unwrap();
4286
1
        assert!((result.to_f64() - 25.0).abs() < 0.00001);
4287
1
    }
4288
4289
    #[test]
4290
1
    fn test_quantity_division() {
4291
1
        let qty = Quantity::from_f64(10.0).unwrap();
4292
1
        let result = (qty / 2.0).unwrap();
4293
1
        assert!((result.to_f64() - 5.0).abs() < 0.00001);
4294
1
    }
4295
4296
    #[test]
4297
1
    fn test_quantity_division_by_zero() {
4298
1
        let qty = Quantity::from_f64(10.0).unwrap();
4299
1
        let result = qty / 0.0;
4300
1
        assert!(result.is_err());
4301
1
    }
4302
4303
    #[test]
4304
1
    fn test_quantity_is_zero() {
4305
1
        assert!(Quantity::ZERO.is_zero());
4306
1
        assert!(!Quantity::from_f64(1.0).unwrap().is_zero());
4307
1
    }
4308
4309
    #[test]
4310
1
    fn test_quantity_is_positive() {
4311
1
        assert!(Quantity::from_f64(1.0).unwrap().is_positive());
4312
1
        assert!(!Quantity::ZERO.is_positive());
4313
1
    }
4314
4315
    #[test]
4316
1
    fn test_quantity_is_negative() {
4317
        // Quantity is always non-negative
4318
1
        assert!(!Quantity::from_f64(1.0).unwrap().is_negative());
4319
1
        assert!(!Quantity::ZERO.is_negative());
4320
1
    }
4321
4322
    #[test]
4323
1
    fn test_quantity_from_shares() {
4324
1
        let qty = Quantity::from_shares(100);
4325
1
        assert_eq!(qty.to_shares(), 100);
4326
1
    }
4327
4328
    #[test]
4329
1
    fn test_quantity_sum() {
4330
1
        let quantities = vec![
4331
1
            Quantity::from_f64(1.0).unwrap(),
4332
1
            Quantity::from_f64(2.0).unwrap(),
4333
1
            Quantity::from_f64(3.0).unwrap(),
4334
        ];
4335
1
        let sum: Quantity = quantities.into_iter().sum();
4336
1
        assert!((sum.to_f64() - 6.0).abs() < 0.00001);
4337
1
    }
4338
4339
    #[test]
4340
1
    fn test_quantity_try_from_i32() {
4341
1
        let qty = Quantity::try_from(100i32).unwrap();
4342
1
        assert_eq!(qty.to_f64(), 100.0);
4343
1
    }
4344
4345
    #[test]
4346
1
    fn test_quantity_try_from_string() {
4347
1
        let qty = Quantity::try_from("123.45").unwrap();
4348
1
        assert!((qty.to_f64() - 123.45).abs() < 0.00001);
4349
1
    }
4350
4351
    // =============================================================================
4352
    // Money Tests
4353
    // =============================================================================
4354
4355
    #[test]
4356
1
    fn test_money_new() {
4357
1
        let amount = Decimal::from_f64(100.50).unwrap();
4358
1
        let money = Money::new(amount, Currency::USD);
4359
1
        assert_eq!(money.currency, Currency::USD);
4360
1
        assert_eq!(money.amount, amount);
4361
1
    }
4362
4363
    #[test]
4364
1
    fn test_money_display() {
4365
1
        let amount = Decimal::from_f64(100.50).unwrap();
4366
1
        let money = Money::new(amount, Currency::USD);
4367
1
        let display = format!("{}", money);
4368
1
        assert!(display.contains("100.5"));
4369
1
        assert!(display.contains("USD"));
4370
1
    }
4371
4372
    // =============================================================================
4373
    // Symbol Tests
4374
    // =============================================================================
4375
4376
    #[test]
4377
1
    fn test_symbol_new() {
4378
1
        let symbol = Symbol::new("AAPL".to_string());
4379
1
        assert_eq!(symbol.as_str(), "AAPL");
4380
1
    }
4381
4382
    #[test]
4383
1
    fn test_symbol_new_validated_valid() {
4384
1
        let symbol = Symbol::new_validated("AAPL".to_string()).unwrap();
4385
1
        assert_eq!(symbol.as_str(), "AAPL");
4386
1
    }
4387
4388
    #[test]
4389
1
    fn test_symbol_new_validated_empty() {
4390
1
        let result = Symbol::new_validated("".to_string());
4391
1
        assert!(result.is_err());
4392
1
    }
4393
4394
    #[test]
4395
1
    fn test_symbol_new_validated_whitespace() {
4396
1
        let result = Symbol::new_validated("   ".to_string());
4397
1
        assert!(result.is_err());
4398
1
    }
4399
4400
    #[test]
4401
1
    fn test_symbol_from_str() {
4402
1
        let symbol = Symbol::from_str("AAPL").unwrap();
4403
1
        assert_eq!(symbol.as_str(), "AAPL");
4404
1
    }
4405
4406
    #[test]
4407
1
    fn test_symbol_to_uppercase() {
4408
1
        let symbol = Symbol::from_str("aapl").unwrap();
4409
1
        assert_eq!(symbol.to_uppercase(), "AAPL");
4410
1
    }
4411
4412
    #[test]
4413
1
    fn test_symbol_replace() {
4414
1
        let symbol = Symbol::from_str("AAPL.US").unwrap();
4415
1
        assert_eq!(symbol.replace(".US", ""), "AAPL");
4416
1
    }
4417
4418
    #[test]
4419
1
    fn test_symbol_contains() {
4420
1
        let symbol = Symbol::from_str("AAPL.US").unwrap();
4421
1
        assert!(symbol.contains("AAPL"));
4422
1
        assert!(!symbol.contains("MSFT"));
4423
1
    }
4424
4425
    #[test]
4426
1
    fn test_symbol_partial_eq_str() {
4427
1
        let symbol = Symbol::from_str("AAPL").unwrap();
4428
1
        assert_eq!("AAPL", symbol);
4429
1
        assert_eq!(symbol.as_str(), "AAPL");
4430
1
    }
4431
4432
    #[test]
4433
1
    fn test_symbol_none() {
4434
1
        let symbol = Symbol::none();
4435
1
        assert_eq!(symbol.as_str(), "NONE");
4436
1
    }
4437
4438
    // =============================================================================
4439
    // TimeInForce Tests
4440
    // =============================================================================
4441
4442
    #[test]
4443
1
    fn test_time_in_force_display() {
4444
1
        assert_eq!(format!("{}", TimeInForce::Day), "DAY");
4445
1
        assert_eq!(format!("{}", TimeInForce::GoodTillCancel), "GTC");
4446
1
        assert_eq!(format!("{}", TimeInForce::ImmediateOrCancel), "IOC");
4447
1
        assert_eq!(format!("{}", TimeInForce::FillOrKill), "FOK");
4448
1
    }
4449
4450
    #[test]
4451
1
    fn test_time_in_force_default() {
4452
1
        assert_eq!(TimeInForce::default(), TimeInForce::Day);
4453
1
    }
4454
4455
    // =============================================================================
4456
    // OrderType Tests
4457
    // =============================================================================
4458
4459
    #[test]
4460
1
    fn test_order_type_display() {
4461
1
        assert_eq!(format!("{}", OrderType::Market), "MARKET");
4462
1
        assert_eq!(format!("{}", OrderType::Limit), "LIMIT");
4463
1
        assert_eq!(format!("{}", OrderType::Stop), "STOP");
4464
1
        assert_eq!(format!("{}", OrderType::StopLimit), "STOP_LIMIT");
4465
1
    }
4466
4467
    #[test]
4468
1
    fn test_order_type_try_from_i32_valid() {
4469
1
        assert_eq!(OrderType::try_from(0).unwrap(), OrderType::Market);
4470
1
        assert_eq!(OrderType::try_from(1).unwrap(), OrderType::Limit);
4471
1
        assert_eq!(OrderType::try_from(2).unwrap(), OrderType::Stop);
4472
1
    }
4473
4474
    #[test]
4475
1
    fn test_order_type_try_from_i32_invalid() {
4476
1
        let result = OrderType::try_from(99);
4477
1
        assert!(result.is_err());
4478
1
    }
4479
4480
    #[test]
4481
1
    fn test_order_type_default() {
4482
1
        assert_eq!(OrderType::default(), OrderType::Market);
4483
1
    }
4484
4485
    // =============================================================================
4486
    // OrderStatus Tests
4487
    // =============================================================================
4488
4489
    #[test]
4490
1
    fn test_order_status_display() {
4491
1
        assert_eq!(format!("{}", OrderStatus::Created), "CREATED");
4492
1
        assert_eq!(format!("{}", OrderStatus::Filled), "FILLED");
4493
1
        assert_eq!(format!("{}", OrderStatus::Cancelled), "CANCELLED");
4494
1
    }
4495
4496
    #[test]
4497
1
    fn test_order_status_try_from_i32_valid() {
4498
1
        assert_eq!(OrderStatus::try_from(0).unwrap(), OrderStatus::Created);
4499
1
        assert_eq!(OrderStatus::try_from(3).unwrap(), OrderStatus::Filled);
4500
1
        assert_eq!(OrderStatus::try_from(5).unwrap(), OrderStatus::Cancelled);
4501
1
    }
4502
4503
    #[test]
4504
1
    fn test_order_status_try_from_i32_invalid() {
4505
1
        let result = OrderStatus::try_from(99);
4506
1
        assert!(result.is_err());
4507
1
    }
4508
4509
    // =============================================================================
4510
    // OrderSide Tests
4511
    // =============================================================================
4512
4513
    #[test]
4514
1
    fn test_order_side_display() {
4515
1
        assert_eq!(format!("{}", OrderSide::Buy), "BUY");
4516
1
        assert_eq!(format!("{}", OrderSide::Sell), "SELL");
4517
1
    }
4518
4519
    #[test]
4520
1
    fn test_order_side_try_from_i32_valid() {
4521
1
        assert_eq!(OrderSide::try_from(0).unwrap(), OrderSide::Buy);
4522
1
        assert_eq!(OrderSide::try_from(1).unwrap(), OrderSide::Sell);
4523
1
    }
4524
4525
    #[test]
4526
1
    fn test_order_side_try_from_i32_invalid() {
4527
1
        let result = OrderSide::try_from(99);
4528
1
        assert!(result.is_err());
4529
1
    }
4530
4531
    #[test]
4532
1
    fn test_order_side_default() {
4533
1
        assert_eq!(OrderSide::default(), OrderSide::Buy);
4534
1
    }
4535
4536
    // =============================================================================
4537
    // Currency Tests
4538
    // =============================================================================
4539
4540
    #[test]
4541
1
    fn test_currency_display() {
4542
1
        assert_eq!(format!("{}", Currency::USD), "USD");
4543
1
        assert_eq!(format!("{}", Currency::EUR), "EUR");
4544
1
        assert_eq!(format!("{}", Currency::BTC), "BTC");
4545
1
    }
4546
4547
    #[test]
4548
1
    fn test_currency_default() {
4549
1
        assert_eq!(Currency::default(), Currency::USD);
4550
1
    }
4551
4552
    // =============================================================================
4553
    // Error Type Tests
4554
    // =============================================================================
4555
4556
    #[test]
4557
1
    fn test_common_type_error_invalid_price() {
4558
1
        let error = CommonTypeError::InvalidPrice {
4559
1
            value: "abc".to_string(),
4560
1
            reason: "not a number".to_string(),
4561
1
        };
4562
1
        let display = format!("{}", error);
4563
1
        assert!(display.contains("abc"));
4564
1
    }
4565
4566
    #[test]
4567
1
    fn test_common_type_error_invalid_quantity() {
4568
1
        let error = CommonTypeError::InvalidQuantity {
4569
1
            value: "xyz".to_string(),
4570
1
            reason: "not a number".to_string(),
4571
1
        };
4572
1
        let display = format!("{}", error);
4573
1
        assert!(display.contains("xyz"));
4574
1
    }
4575
4576
    #[test]
4577
1
    fn test_common_type_error_validation() {
4578
1
        let error = CommonTypeError::ValidationError {
4579
1
            field: "symbol".to_string(),
4580
1
            reason: "cannot be empty".to_string(),
4581
1
        };
4582
1
        let display = format!("{}", error);
4583
1
        assert!(display.contains("symbol"));
4584
1
    }
4585
}