rusty_model/
trading_order.rs

1//! Order-related data structures
2//!
3//! Contains types for representing orders, trades, and positions
4
5use quanta::Clock;
6use rust_decimal::Decimal;
7use serde::{Deserialize, Serialize};
8use smartstring::alias::String;
9
10// Re-export common enums from rusty-common
11pub use crate::enums::{OrderSide, OrderStatus, OrderType, TimeInForce};
12use crate::types::{ClientId, OrderId};
13use crate::venues::Venue;
14
15// Import the Poolable trait from rusty-common
16use rusty_common::pools::Poolable;
17
18/// Represents an order in the system
19#[repr(align(64))] // Cache-line aligned for HFT performance
20#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct Order {
22    /// Unique order ID
23    pub id: OrderId,
24
25    /// Exchange-specific order ID (once assigned)
26    pub exchange_order_id: Option<String>,
27
28    /// Exchange identifier
29    pub venue: Venue,
30
31    /// Trading symbol (e.g. "BTCUSDT")
32    pub symbol: String,
33
34    /// Order side (buy or sell)
35    pub side: OrderSide,
36
37    /// Order type
38    pub order_type: OrderType,
39
40    /// Limit price (required for limit orders)
41    pub price: Option<Decimal>,
42
43    /// Stop price (required for stop orders)
44    pub stop_price: Option<Decimal>,
45
46    /// Order quantity
47    pub quantity: Decimal,
48
49    /// Filled quantity
50    pub filled_quantity: Decimal,
51
52    /// Average fill price
53    pub average_fill_price: Option<Decimal>,
54
55    /// Current order status
56    pub status: OrderStatus,
57
58    /// Order creation time in nanoseconds
59    pub creation_time_ns: u64,
60
61    /// Order update time in nanoseconds
62    pub update_time_ns: u64,
63
64    /// Strategy or client ID that created this order
65    pub client_id: ClientId,
66
67    /// Time in force for the order
68    pub time_in_force: TimeInForce,
69
70    /// Additional order metadata
71    pub metadata: rusty_common::json::Value,
72}
73
74// SAFETY: Default implementation removed to prevent accidental order creation in production.
75// Use Order::new() or Order::for_testing() instead.
76
77#[cfg(test)]
78impl Order {
79    /// Create a test order with obviously invalid values
80    ///
81    /// # Safety
82    /// This method creates an order with invalid/test values that should NEVER be used in production.
83    /// It's designed to be obviously invalid to prevent accidental execution:
84    /// - Uses a nil UUID (all zeros)
85    /// - Symbol is "TEST-INVALID"
86    /// - Client ID is "TEST-ONLY"
87    /// - All timestamps are zero
88    ///
89    /// # Examples
90    /// ```rust
91    /// # use rusty_model::trading_order::Order;
92    /// let test_order = Order::for_testing();
93    /// assert_eq!(test_order.symbol.as_str(), "TEST-INVALID");
94    /// ```
95    #[must_use]
96    pub fn for_testing() -> Self {
97        use crate::types::OrderId;
98        use uuid::Uuid;
99
100        Self {
101            id: OrderId::from_uuid(Uuid::nil()), // Nil UUID - obviously invalid
102            exchange_order_id: None,
103            venue: Venue::Test,
104            symbol: String::from("TEST-INVALID"), // Obviously invalid symbol
105            side: OrderSide::Buy,
106            order_type: OrderType::Market,
107            price: None,
108            stop_price: None,
109            quantity: Decimal::ZERO, // Zero quantity - invalid for real orders
110            filled_quantity: Decimal::ZERO,
111            average_fill_price: None,
112            status: OrderStatus::New,
113            creation_time_ns: 0, // Zero timestamp - obviously invalid
114            update_time_ns: 0,
115            client_id: ClientId::from("TEST-ONLY"), // Obviously test-only client
116            time_in_force: TimeInForce::GTC,
117            metadata: rusty_common::json::json!({"test_only": true}),
118        }
119    }
120}
121
122impl Order {
123    /// Create a new order
124    #[must_use]
125    pub fn new(
126        venue: Venue,
127        symbol: impl AsRef<str>,
128        side: OrderSide,
129        order_type: OrderType,
130        quantity: Decimal,
131        price: Option<Decimal>,
132        client_id: ClientId,
133    ) -> Self {
134        Self::with_time_in_force(
135            venue,
136            symbol,
137            side,
138            order_type,
139            quantity,
140            price,
141            client_id,
142            TimeInForce::GTC, // Default to Good Till Cancel
143        )
144    }
145
146    /// Create a new order with specific time in force
147    #[must_use]
148    #[allow(clippy::too_many_arguments)] // Constructor needs all parameters for complete order
149    pub fn with_time_in_force(
150        venue: Venue,
151        symbol: impl AsRef<str>,
152        side: OrderSide,
153        order_type: OrderType,
154        quantity: Decimal,
155        price: Option<Decimal>,
156        client_id: ClientId,
157        time_in_force: TimeInForce,
158    ) -> Self {
159        // Use quanta::Clock for high-precision nanosecond timestamps
160        let clock = Clock::new();
161        let now = clock.raw();
162
163        /*
164           don't need them:
165           - exchange_order_id
166           - average_fill_price
167           - metadata
168        */
169        Self {
170            id: OrderId::new(),
171            exchange_order_id: None,
172            venue,
173            symbol: String::from(symbol.as_ref()),
174            side,
175            order_type,
176            price,
177            stop_price: None,
178            quantity,
179            filled_quantity: Decimal::ZERO,
180            average_fill_price: None,
181            status: OrderStatus::New,
182            creation_time_ns: now,
183            update_time_ns: now,
184            client_id,
185            time_in_force,
186            metadata: rusty_common::json::json!(null),
187        }
188    }
189
190    /// Determine if order is completely filled
191    #[must_use]
192    pub fn is_filled(&self) -> bool {
193        self.status == OrderStatus::Filled
194    }
195
196    /// Calculate remaining quantity
197    #[must_use]
198    pub fn remaining_quantity(&self) -> Decimal {
199        self.quantity - self.filled_quantity
200    }
201
202    /// Update order status
203    pub fn update_status(&mut self, status: OrderStatus) {
204        self.status = status;
205        // Use quanta::Clock for high-precision nanosecond timestamps
206        let clock = Clock::new();
207        self.update_time_ns = clock.raw();
208    }
209}
210
211/// Poolable implementation for safe object pool usage
212///
213/// This implementation provides safe pool initialization without the risks
214/// of the Default trait. Objects created through this trait are obviously
215/// invalid and safe for pool pre-allocation.
216impl Poolable for Order {
217    fn new_for_pool() -> Self {
218        use uuid::Uuid;
219
220        Self {
221            id: OrderId::from_uuid(Uuid::nil()), // Nil UUID - obviously invalid
222            exchange_order_id: None,
223            venue: Venue::Test,
224            symbol: String::from("POOL-INVALID"), // Obviously invalid pool symbol
225            side: OrderSide::Buy,
226            order_type: OrderType::Market,
227            price: None,
228            stop_price: None,
229            quantity: Decimal::ZERO, // Zero quantity - invalid for real orders
230            filled_quantity: Decimal::ZERO,
231            average_fill_price: None,
232            status: OrderStatus::New,
233            creation_time_ns: 0, // Zero timestamp - obviously invalid
234            update_time_ns: 0,
235            client_id: ClientId::from("POOL-ONLY"), // Obviously pool-only client
236            time_in_force: TimeInForce::GTC,
237            metadata: rusty_common::json::json!({"pool_object": true}),
238        }
239    }
240
241    fn reset_for_pool(&mut self) {
242        use uuid::Uuid;
243
244        // Reset to invalid state for pool reuse
245        self.id = OrderId::from_uuid(Uuid::nil());
246        self.exchange_order_id = None;
247        self.venue = Venue::Test;
248        self.symbol = String::from("POOL-INVALID");
249        self.side = OrderSide::Buy;
250        self.order_type = OrderType::Market;
251        self.price = None;
252        self.stop_price = None;
253        self.quantity = Decimal::ZERO;
254        self.filled_quantity = Decimal::ZERO;
255        self.average_fill_price = None;
256        self.status = OrderStatus::New;
257        self.creation_time_ns = 0;
258        self.update_time_ns = 0;
259        self.client_id = ClientId::from("POOL-ONLY");
260        self.time_in_force = TimeInForce::GTC;
261        self.metadata = rusty_common::json::json!({"pool_object": true});
262    }
263}
264
265/// Default implementation using Poolable for object pool compatibility
266///
267/// This implementation uses the safe Poolable trait to provide Default behavior
268/// for object pools while maintaining the security benefits of removing the
269/// original Default implementation that could create accidentally valid orders.
270impl Default for Order {
271    fn default() -> Self {
272        Self::new_for_pool()
273    }
274}
275
276#[cfg(test)]
277mod tests {
278    use super::*;
279    use crate::enums::{OrderSide, OrderStatus, OrderType};
280    use crate::types::ClientId;
281    use rust_decimal_macros::dec;
282    use std::thread;
283
284    // Helper function to create a test venue
285    fn create_test_venue() -> Venue {
286        Venue::Test
287    }
288
289    #[test]
290    fn test_order_new() {
291        let venue = Venue::Test;
292        let symbol = "BTCUSDT";
293        let side = OrderSide::Buy;
294        let order_type = OrderType::Limit;
295        let quantity = dec!(1.0);
296        let price = Some(dec!(50000.0));
297        let client_id = ClientId::from("test_client");
298
299        let order = Order::new(venue, symbol, side, order_type, quantity, price, client_id);
300
301        assert_eq!(order.venue, venue);
302        assert_eq!(order.symbol.as_str(), symbol);
303        assert_eq!(order.side, side);
304        assert_eq!(order.order_type, order_type);
305        assert_eq!(order.quantity, quantity);
306        assert_eq!(order.price, price);
307        assert_eq!(order.stop_price, None);
308        assert_eq!(order.filled_quantity, dec!(0));
309        assert_eq!(order.average_fill_price, None);
310        assert_eq!(order.status, OrderStatus::New);
311        assert!(order.creation_time_ns > 0);
312        assert_eq!(order.update_time_ns, order.creation_time_ns);
313        assert_eq!(order.client_id.as_str(), "test_client");
314        assert_eq!(order.metadata, rusty_common::json::json!(null));
315    }
316
317    #[test]
318    fn test_order_is_filled() {
319        let mut order = Order::new(
320            create_test_venue(),
321            "BTCUSDT",
322            OrderSide::Buy,
323            OrderType::Limit,
324            dec!(1.0),
325            Some(dec!(50000.0)),
326            ClientId::from("test_client"),
327        );
328
329        // Initially, the order is not filled
330        assert!(!order.is_filled());
331
332        // Update the status to Filled
333        order.status = OrderStatus::Filled;
334        assert!(order.is_filled());
335
336        // Other statuses should return false
337        order.status = OrderStatus::PartiallyFilled;
338        assert!(!order.is_filled());
339
340        order.status = OrderStatus::Cancelled;
341        assert!(!order.is_filled());
342    }
343
344    #[test]
345    fn test_order_remaining_quantity() {
346        let mut order = Order::new(
347            create_test_venue(),
348            "BTCUSDT",
349            OrderSide::Buy,
350            OrderType::Limit,
351            dec!(2.0),
352            Some(dec!(50000.0)),
353            ClientId::from("test_client"),
354        );
355
356        // Initially, the remaining quantity is the full quantity
357        assert_eq!(order.remaining_quantity(), dec!(2.0));
358
359        // After partial fill
360        order.filled_quantity = dec!(0.5);
361        assert_eq!(order.remaining_quantity(), dec!(1.5));
362
363        // After complete fill
364        order.filled_quantity = dec!(2.0);
365        assert_eq!(order.remaining_quantity(), dec!(0));
366    }
367
368    #[test]
369    fn test_order_update_status() {
370        let mut order = Order::new(
371            create_test_venue(),
372            "BTCUSDT",
373            OrderSide::Buy,
374            OrderType::Limit,
375            dec!(1.0),
376            Some(dec!(50000.0)),
377            ClientId::from("test_client"),
378        );
379
380        let initial_update_time = order.update_time_ns;
381
382        // Wait a small amount of time to ensure the update time changes
383        thread::sleep(std::time::Duration::from_millis(1));
384
385        // Update the status
386        order.update_status(OrderStatus::Open);
387
388        assert_eq!(order.status, OrderStatus::Open);
389        assert!(order.update_time_ns > initial_update_time);
390    }
391
392    #[test]
393    fn test_order_side_conversion() {
394        // Test conversion from OrderSide to OrderSide
395        assert_eq!(OrderSide::Buy, OrderSide::Buy);
396        assert_eq!(OrderSide::Sell, OrderSide::Sell);
397
398        // Test conversion from OrderSide to OrderSide
399        assert_eq!(OrderSide::Buy, OrderSide::Buy);
400        assert_eq!(OrderSide::Sell, OrderSide::Sell);
401    }
402
403    #[test]
404    fn test_order_type_conversion() {
405        // Test conversion from OrderType to OrderType
406        assert_eq!(OrderType::Market, OrderType::Market);
407        assert_eq!(OrderType::Limit, OrderType::Limit);
408        assert_eq!(OrderType::Stop, OrderType::Stop);
409        assert_eq!(OrderType::StopLimit, OrderType::StopLimit);
410        assert_eq!(OrderType::FillOrKill, OrderType::FillOrKill);
411        assert_eq!(OrderType::ImmediateOrCancel, OrderType::ImmediateOrCancel);
412        assert_eq!(OrderType::PostOnly, OrderType::PostOnly);
413
414        // Test conversion from OrderType to OrderType
415        assert_eq!(OrderType::Market, OrderType::Market);
416        assert_eq!(OrderType::Limit, OrderType::Limit);
417        assert_eq!(OrderType::Stop, OrderType::Stop);
418        assert_eq!(OrderType::StopLimit, OrderType::StopLimit);
419        assert_eq!(OrderType::FillOrKill, OrderType::FillOrKill);
420        assert_eq!(OrderType::ImmediateOrCancel, OrderType::ImmediateOrCancel);
421        assert_eq!(OrderType::PostOnly, OrderType::PostOnly);
422    }
423
424    #[test]
425    fn test_order_status_conversion() {
426        // Test conversion from OrderStatus to OrderStatus
427        assert_eq!(OrderStatus::New, OrderStatus::New);
428        assert_eq!(OrderStatus::Open, OrderStatus::Open);
429        assert_eq!(OrderStatus::PartiallyFilled, OrderStatus::PartiallyFilled);
430        assert_eq!(OrderStatus::Filled, OrderStatus::Filled);
431        assert_eq!(OrderStatus::Cancelled, OrderStatus::Cancelled);
432        assert_eq!(OrderStatus::Rejected, OrderStatus::Rejected);
433        assert_eq!(OrderStatus::Pending, OrderStatus::Pending);
434        assert_eq!(OrderStatus::Unknown, OrderStatus::Unknown);
435
436        // Test conversion from OrderStatus to OrderStatus
437        assert_eq!(OrderStatus::New, OrderStatus::New);
438        assert_eq!(OrderStatus::Open, OrderStatus::Open);
439        assert_eq!(OrderStatus::PartiallyFilled, OrderStatus::PartiallyFilled);
440        assert_eq!(OrderStatus::Filled, OrderStatus::Filled);
441        assert_eq!(OrderStatus::Cancelled, OrderStatus::Cancelled);
442        assert_eq!(OrderStatus::Rejected, OrderStatus::Rejected);
443        assert_eq!(OrderStatus::Pending, OrderStatus::Pending);
444        assert_eq!(OrderStatus::Unknown, OrderStatus::Unknown);
445    }
446
447    #[test]
448    fn test_order_for_testing() {
449        let test_order = Order::for_testing();
450
451        // Verify obviously invalid values
452        assert_eq!(
453            test_order.id.to_string(),
454            "00000000-0000-0000-0000-000000000000"
455        );
456        assert_eq!(test_order.symbol.as_str(), "TEST-INVALID");
457        assert_eq!(test_order.client_id.as_str(), "TEST-ONLY");
458        assert_eq!(test_order.quantity, dec!(0)); // Zero quantity is invalid
459        assert_eq!(test_order.creation_time_ns, 0); // Zero timestamp is invalid
460        assert_eq!(test_order.update_time_ns, 0);
461        assert_eq!(test_order.venue, Venue::Test);
462        assert_eq!(test_order.status, OrderStatus::New);
463        assert_eq!(test_order.metadata["test_only"], true);
464
465        // Verify it's clearly a test order
466        assert!(test_order.symbol.contains("TEST"));
467        assert!(test_order.client_id.as_str().contains("TEST"));
468    }
469
470    #[test]
471    fn test_production_order_vs_test_order() {
472        let production_order = Order::new(
473            Venue::Binance,
474            "BTCUSDT",
475            OrderSide::Buy,
476            OrderType::Limit,
477            dec!(1.0),
478            Some(dec!(50000.0)),
479            ClientId::from("real_client"),
480        );
481
482        let test_order = Order::for_testing();
483
484        // Verify production order has valid values
485        assert_ne!(
486            production_order.id.to_string(),
487            "00000000-0000-0000-0000-000000000000"
488        );
489        assert_ne!(production_order.symbol.as_str(), "TEST-INVALID");
490        assert_ne!(production_order.client_id.as_str(), "TEST-ONLY");
491        assert_ne!(production_order.quantity, dec!(0));
492        assert_ne!(production_order.creation_time_ns, 0);
493
494        // Verify test order has invalid values
495        assert_eq!(
496            test_order.id.to_string(),
497            "00000000-0000-0000-0000-000000000000"
498        );
499        assert_eq!(test_order.symbol.as_str(), "TEST-INVALID");
500        assert_eq!(test_order.client_id.as_str(), "TEST-ONLY");
501        assert_eq!(test_order.quantity, dec!(0));
502        assert_eq!(test_order.creation_time_ns, 0);
503    }
504
505    #[test]
506    fn test_poolable_trait_safety() {
507        // Test that Poolable creates obviously invalid orders
508        let pool_order = Order::new_for_pool();
509
510        assert_eq!(
511            pool_order.id.to_string(),
512            "00000000-0000-0000-0000-000000000000"
513        );
514        assert_eq!(pool_order.symbol.as_str(), "POOL-INVALID");
515        assert_eq!(pool_order.client_id.as_str(), "POOL-ONLY");
516        assert_eq!(pool_order.quantity, dec!(0));
517        assert_eq!(pool_order.creation_time_ns, 0);
518        assert_eq!(pool_order.update_time_ns, 0);
519        assert_eq!(pool_order.venue, Venue::Test);
520        assert_eq!(pool_order.metadata["pool_object"], true);
521    }
522
523    #[test]
524    fn test_poolable_reset_functionality() {
525        // Create a production order and then reset it for pool reuse
526        let mut order = Order::new(
527            Venue::Binance,
528            "BTCUSDT",
529            OrderSide::Buy,
530            OrderType::Limit,
531            dec!(1.0),
532            Some(dec!(50000.0)),
533            ClientId::from("real_client"),
534        );
535
536        // Verify it's a valid order initially
537        assert_ne!(order.id.to_string(), "00000000-0000-0000-0000-000000000000");
538        assert_eq!(order.symbol.as_str(), "BTCUSDT");
539        assert_eq!(order.client_id.as_str(), "real_client");
540        assert_eq!(order.quantity, dec!(1.0));
541        assert_ne!(order.creation_time_ns, 0);
542
543        // Reset for pool reuse
544        order.reset_for_pool();
545
546        // Verify it's now in invalid pool state
547        assert_eq!(order.id.to_string(), "00000000-0000-0000-0000-000000000000");
548        assert_eq!(order.symbol.as_str(), "POOL-INVALID");
549        assert_eq!(order.client_id.as_str(), "POOL-ONLY");
550        assert_eq!(order.quantity, dec!(0));
551        assert_eq!(order.creation_time_ns, 0);
552        assert_eq!(order.update_time_ns, 0);
553        assert_eq!(order.venue, Venue::Test);
554        assert_eq!(order.metadata["pool_object"], true);
555    }
556
557    #[test]
558    fn test_default_uses_poolable() {
559        // Verify that Default implementation uses Poolable for safety
560        let default_order = Order::default();
561        let pool_order = Order::new_for_pool();
562
563        // They should be identical
564        assert_eq!(default_order.id.to_string(), pool_order.id.to_string());
565        assert_eq!(default_order.symbol, pool_order.symbol);
566        assert_eq!(default_order.client_id, pool_order.client_id);
567        assert_eq!(default_order.quantity, pool_order.quantity);
568        assert_eq!(default_order.creation_time_ns, pool_order.creation_time_ns);
569        assert_eq!(default_order.metadata, pool_order.metadata);
570    }
571
572    #[test]
573    fn test_pool_vs_test_order_differences() {
574        let test_order = Order::for_testing();
575        let pool_order = Order::new_for_pool();
576
577        // Both should have nil UUIDs and zero quantities (invalid)
578        assert_eq!(test_order.id.to_string(), pool_order.id.to_string());
579        assert_eq!(test_order.quantity, pool_order.quantity);
580        assert_eq!(test_order.creation_time_ns, pool_order.creation_time_ns);
581        assert_eq!(test_order.venue, pool_order.venue);
582
583        // But they should have different symbols and client IDs to indicate purpose
584        assert_ne!(test_order.symbol, pool_order.symbol);
585        assert_ne!(test_order.client_id, pool_order.client_id);
586        assert_ne!(test_order.metadata, pool_order.metadata);
587
588        // Verify their specific purposes
589        assert!(test_order.symbol.contains("TEST"));
590        assert!(test_order.client_id.as_str().contains("TEST"));
591        assert!(pool_order.symbol.contains("POOL"));
592        assert!(pool_order.client_id.as_str().contains("POOL"));
593    }
594
595    #[test]
596    fn test_order_default_has_nil_uuid() {
597        let order = Order::default();
598        // Nil UUID is all zeros: 00000000-0000-0000-0000-000000000000
599        assert_eq!(order.id.to_string(), "00000000-0000-0000-0000-000000000000");
600    }
601
602    #[test]
603    fn test_order_default_has_pool_invalid_symbol() {
604        let order = Order::default();
605        assert_eq!(order.symbol.as_str(), "POOL-INVALID");
606    }
607
608    #[test]
609    fn test_order_default_has_pool_only_client_id() {
610        let order = Order::default();
611        assert_eq!(order.client_id.as_str(), "POOL-ONLY");
612    }
613
614    #[test]
615    fn test_order_default_has_zero_quantity() {
616        let order = Order::default();
617        assert_eq!(order.quantity, Decimal::ZERO);
618        assert_eq!(order.filled_quantity, Decimal::ZERO);
619    }
620
621    #[test]
622    fn test_order_default_has_zero_timestamps() {
623        let order = Order::default();
624        assert_eq!(order.creation_time_ns, 0);
625        assert_eq!(order.update_time_ns, 0);
626    }
627
628    #[test]
629    fn test_order_default_has_test_venue() {
630        let order = Order::default();
631        assert_eq!(order.venue, Venue::Test);
632    }
633
634    #[test]
635    fn test_order_default_has_pool_object_metadata() {
636        let order = Order::default();
637        assert_eq!(order.metadata["pool_object"], true);
638    }
639
640    #[test]
641    fn test_order_default_comprehensive() {
642        // Comprehensive test to verify all fields of Default implementation
643        let order = Order::default();
644
645        // 1. Nil UUID (all zeros)
646        assert_eq!(order.id.to_string(), "00000000-0000-0000-0000-000000000000");
647
648        // 2. Symbol is "POOL-INVALID"
649        assert_eq!(order.symbol.as_str(), "POOL-INVALID");
650
651        // 3. ClientId is "POOL-ONLY"
652        assert_eq!(order.client_id.as_str(), "POOL-ONLY");
653
654        // 4. Quantity is zero (also check filled_quantity)
655        assert_eq!(order.quantity, Decimal::ZERO);
656        assert_eq!(order.filled_quantity, Decimal::ZERO);
657
658        // 5. Timestamps are zero
659        assert_eq!(order.creation_time_ns, 0);
660        assert_eq!(order.update_time_ns, 0);
661
662        // 6. Venue is Test
663        assert_eq!(order.venue, Venue::Test);
664
665        // 7. Metadata contains pool_object: true
666        assert_eq!(order.metadata["pool_object"], true);
667
668        // Additional safety checks for other fields
669        assert_eq!(order.exchange_order_id, None);
670        assert_eq!(order.side, OrderSide::Buy);
671        assert_eq!(order.order_type, OrderType::Market);
672        assert_eq!(order.price, None);
673        assert_eq!(order.stop_price, None);
674        assert_eq!(order.average_fill_price, None);
675        assert_eq!(order.status, OrderStatus::New);
676        assert_eq!(order.time_in_force, TimeInForce::GTC);
677    }
678
679    #[test]
680    fn test_order_default_is_obviously_invalid() {
681        // Test that a default order is obviously invalid and safe for pool usage
682        let order = Order::default();
683
684        // Check invalid characteristics that make it obviously unusable
685        assert!(order.id.to_string().contains("00000000"));
686        assert!(order.symbol.contains("INVALID"));
687        assert!(order.client_id.as_str().contains("POOL"));
688        assert!(order.quantity.is_zero());
689        assert_eq!(order.creation_time_ns, 0); // No valid order has zero timestamp
690
691        // Verify metadata marks it as a pool object
692        assert_eq!(order.metadata["pool_object"], true);
693    }
694}