1use crate::model::order::{OrderSide, OrderType, TimeInForce};
7use pretty_simple_display::{DebugPretty, DisplaySimple};
8
9use serde::{Deserialize, Serialize};
10
11pub mod fix {
13 use super::*;
14
15 #[derive(DebugPretty, DisplaySimple, Clone, Serialize, Deserialize)]
17 pub struct NewOrderRequest {
18 pub symbol: String,
20 pub side: OrderSide,
22 pub order_type: OrderType,
24 pub quantity: f64,
26 pub price: Option<f64>,
28 pub time_in_force: TimeInForce,
30 pub client_order_id: Option<String>,
32 }
33
34 impl NewOrderRequest {
35 pub fn market_buy(symbol: String, quantity: f64) -> Self {
37 Self {
38 symbol,
39 side: OrderSide::Buy,
40 order_type: OrderType::Market,
41 quantity,
42 price: None,
43 time_in_force: TimeInForce::ImmediateOrCancel,
44 client_order_id: None,
45 }
46 }
47
48 pub fn market_sell(symbol: String, quantity: f64) -> Self {
50 Self {
51 symbol,
52 side: OrderSide::Sell,
53 order_type: OrderType::Market,
54 quantity,
55 price: None,
56 time_in_force: TimeInForce::ImmediateOrCancel,
57 client_order_id: None,
58 }
59 }
60
61 pub fn limit_buy(symbol: String, quantity: f64, price: f64) -> Self {
63 Self {
64 symbol,
65 side: OrderSide::Buy,
66 order_type: OrderType::Limit,
67 quantity,
68 price: Some(price),
69 time_in_force: TimeInForce::GoodTilCancelled,
70 client_order_id: None,
71 }
72 }
73
74 pub fn limit_sell(symbol: String, quantity: f64, price: f64) -> Self {
76 Self {
77 symbol,
78 side: OrderSide::Sell,
79 order_type: OrderType::Limit,
80 quantity,
81 price: Some(price),
82 time_in_force: TimeInForce::GoodTilCancelled,
83 client_order_id: None,
84 }
85 }
86
87 pub fn with_client_order_id(mut self, client_order_id: String) -> Self {
89 self.client_order_id = Some(client_order_id);
90 self
91 }
92
93 pub fn with_time_in_force(mut self, tif: TimeInForce) -> Self {
95 self.time_in_force = tif;
96 self
97 }
98 }
99
100 impl From<super::NewOrderRequest> for NewOrderRequest {
102 fn from(rest_order: super::NewOrderRequest) -> Self {
103 Self {
104 symbol: rest_order.instrument_name,
105 side: rest_order.side,
106 order_type: rest_order.order_type,
107 quantity: rest_order.amount,
108 price: rest_order.price,
109 time_in_force: rest_order.time_in_force,
110 client_order_id: rest_order.client_order_id,
111 }
112 }
113 }
114
115 impl From<NewOrderRequest> for super::NewOrderRequest {
117 fn from(fix_order: NewOrderRequest) -> Self {
118 Self {
119 instrument_name: fix_order.symbol,
120 amount: fix_order.quantity,
121 order_type: fix_order.order_type,
122 side: fix_order.side,
123 price: fix_order.price,
124 time_in_force: fix_order.time_in_force,
125 post_only: None,
126 reduce_only: None,
127 label: None,
128 stop_price: None,
129 trigger: None,
130 advanced: None,
131 max_show: None,
132 reject_post_only: None,
133 valid_until: None,
134 client_order_id: fix_order.client_order_id,
135 }
136 }
137 }
138}
139
140#[derive(DebugPretty, DisplaySimple, Clone, Serialize, Deserialize)]
142pub struct NewOrderRequest {
143 pub instrument_name: String,
145 pub amount: f64,
147 #[serde(rename = "type")]
149 pub order_type: OrderType,
150 pub side: OrderSide,
152 pub price: Option<f64>,
154 pub time_in_force: TimeInForce,
156 pub post_only: Option<bool>,
158 pub reduce_only: Option<bool>,
160 pub label: Option<String>,
162 pub stop_price: Option<f64>,
164 pub trigger: Option<TriggerType>,
166 pub advanced: Option<AdvancedOrderType>,
168 pub max_show: Option<f64>,
170 pub reject_post_only: Option<bool>,
172 pub valid_until: Option<i64>,
174 pub client_order_id: Option<String>,
176}
177
178impl NewOrderRequest {
179 pub fn market_buy(instrument_name: String, amount: f64) -> Self {
181 Self {
182 instrument_name,
183 amount,
184 order_type: OrderType::Market,
185 side: OrderSide::Buy,
186 price: None,
187 time_in_force: TimeInForce::ImmediateOrCancel,
188 post_only: None,
189 reduce_only: None,
190 label: None,
191 stop_price: None,
192 trigger: None,
193 advanced: None,
194 max_show: None,
195 reject_post_only: None,
196 valid_until: None,
197 client_order_id: None,
198 }
199 }
200
201 pub fn market_sell(instrument_name: String, amount: f64) -> Self {
203 Self {
204 instrument_name,
205 amount,
206 order_type: OrderType::Market,
207 side: OrderSide::Sell,
208 price: None,
209 time_in_force: TimeInForce::ImmediateOrCancel,
210 post_only: None,
211 reduce_only: None,
212 label: None,
213 stop_price: None,
214 trigger: None,
215 advanced: None,
216 max_show: None,
217 reject_post_only: None,
218 valid_until: None,
219 client_order_id: None,
220 }
221 }
222
223 pub fn limit_buy(instrument_name: String, amount: f64, price: f64) -> Self {
225 Self {
226 instrument_name,
227 amount,
228 order_type: OrderType::Limit,
229 side: OrderSide::Buy,
230 price: Some(price),
231 time_in_force: TimeInForce::GoodTilCancelled,
232 post_only: None,
233 reduce_only: None,
234 label: None,
235 stop_price: None,
236 trigger: None,
237 advanced: None,
238 max_show: None,
239 reject_post_only: None,
240 valid_until: None,
241 client_order_id: None,
242 }
243 }
244
245 pub fn limit_sell(instrument_name: String, amount: f64, price: f64) -> Self {
247 Self {
248 instrument_name,
249 amount,
250 order_type: OrderType::Limit,
251 side: OrderSide::Sell,
252 price: Some(price),
253 time_in_force: TimeInForce::GoodTilCancelled,
254 post_only: None,
255 reduce_only: None,
256 label: None,
257 stop_price: None,
258 trigger: None,
259 advanced: None,
260 max_show: None,
261 reject_post_only: None,
262 valid_until: None,
263 client_order_id: None,
264 }
265 }
266
267 pub fn with_post_only(mut self, post_only: bool) -> Self {
269 self.post_only = Some(post_only);
270 self
271 }
272
273 pub fn with_reduce_only(mut self, reduce_only: bool) -> Self {
275 self.reduce_only = Some(reduce_only);
276 self
277 }
278
279 pub fn with_label(mut self, label: String) -> Self {
281 self.label = Some(label);
282 self
283 }
284
285 pub fn with_time_in_force(mut self, tif: TimeInForce) -> Self {
287 self.time_in_force = tif;
288 self
289 }
290}
291
292#[derive(DebugPretty, DisplaySimple, Clone, PartialEq, Eq, Serialize, Deserialize)]
294#[serde(rename_all = "snake_case")]
295pub enum TriggerType {
296 IndexPrice,
298 MarkPrice,
300 LastPrice,
302}
303
304#[derive(DebugPretty, DisplaySimple, Clone, PartialEq, Eq, Serialize, Deserialize)]
306#[serde(rename_all = "snake_case")]
307pub enum LinkedOrderType {
308 OneTriggersOther,
310 OneCancelsOther,
312 OneTriggersOneCancelsOther,
314}
315
316#[derive(DebugPretty, DisplaySimple, Clone, PartialEq, Eq, Serialize, Deserialize)]
318#[serde(rename_all = "snake_case")]
319pub enum TriggerFillCondition {
320 FirstHit,
322 CompleteFill,
324 Incremental,
326}
327
328#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
330#[serde(rename_all = "lowercase")]
331pub enum AdvancedOrderType {
332 Usd,
334 Implv,
336}
337
338#[derive(DebugPretty, DisplaySimple, Clone, Serialize, Deserialize)]
340pub struct ModifyOrderRequest {
341 pub order_id: String,
343 pub amount: Option<f64>,
345 pub price: Option<f64>,
347 pub stop_price: Option<f64>,
349 pub post_only: Option<bool>,
351 pub reduce_only: Option<bool>,
353 pub reject_post_only: Option<bool>,
355 pub advanced: Option<AdvancedOrderType>,
357}
358
359#[derive(DebugPretty, DisplaySimple, Clone, Serialize, Deserialize)]
361pub struct CancelOrderRequest {
362 pub order_id: String,
364}
365
366#[derive(DebugPretty, DisplaySimple, Clone, Serialize, Deserialize)]
368pub struct CancelAllOrdersRequest {
369 pub currency: Option<String>,
371 pub kind: Option<String>,
373 #[serde(rename = "type")]
375 pub instrument_type: Option<String>,
376}
377
378#[derive(DebugPretty, DisplaySimple, Clone, Serialize, Deserialize)]
380pub struct ClosePositionRequest {
381 pub instrument_name: String,
383 #[serde(rename = "type")]
385 pub order_type: OrderType,
386 pub price: Option<f64>,
388}
389
390#[derive(DebugPretty, DisplaySimple, Clone, Serialize, Deserialize)]
392pub struct AuthRequest {
393 pub grant_type: String,
395 pub client_id: String,
397 pub client_secret: String,
399 pub refresh_token: Option<String>,
401 pub scope: Option<String>,
403}
404
405impl AuthRequest {
406 pub fn client_credentials(client_id: String, client_secret: String) -> Self {
408 Self {
409 grant_type: "client_credentials".to_string(),
410 client_id,
411 client_secret,
412 refresh_token: None,
413 scope: None,
414 }
415 }
416
417 pub fn refresh_token(client_id: String, client_secret: String, refresh_token: String) -> Self {
419 Self {
420 grant_type: "refresh_token".to_string(),
421 client_id,
422 client_secret,
423 refresh_token: Some(refresh_token),
424 scope: None,
425 }
426 }
427}
428
429#[cfg(test)]
430mod tests {
431 use super::*;
432
433 #[test]
434 fn test_fix_new_order_request_market_buy() {
435 let order = fix::NewOrderRequest::market_buy("BTC-PERPETUAL".to_string(), 1.0);
436 assert_eq!(order.symbol, "BTC-PERPETUAL");
437 assert_eq!(order.side, OrderSide::Buy);
438 assert_eq!(order.order_type, OrderType::Market);
439 assert_eq!(order.quantity, 1.0);
440 assert_eq!(order.price, None);
441 assert_eq!(order.time_in_force, TimeInForce::ImmediateOrCancel);
442 assert_eq!(order.client_order_id, None);
443 }
444
445 #[test]
446 fn test_fix_new_order_request_market_sell() {
447 let order = fix::NewOrderRequest::market_sell("ETH-PERPETUAL".to_string(), 2.0);
448 assert_eq!(order.symbol, "ETH-PERPETUAL");
449 assert_eq!(order.side, OrderSide::Sell);
450 assert_eq!(order.order_type, OrderType::Market);
451 assert_eq!(order.quantity, 2.0);
452 assert_eq!(order.price, None);
453 assert_eq!(order.time_in_force, TimeInForce::ImmediateOrCancel);
454 }
455
456 #[test]
457 fn test_fix_new_order_request_limit_buy() {
458 let order = fix::NewOrderRequest::limit_buy("BTC-PERPETUAL".to_string(), 1.0, 50000.0);
459 assert_eq!(order.symbol, "BTC-PERPETUAL");
460 assert_eq!(order.side, OrderSide::Buy);
461 assert_eq!(order.order_type, OrderType::Limit);
462 assert_eq!(order.quantity, 1.0);
463 assert_eq!(order.price, Some(50000.0));
464 assert_eq!(order.time_in_force, TimeInForce::GoodTilCancelled);
465 }
466
467 #[test]
468 fn test_fix_new_order_request_limit_sell() {
469 let order = fix::NewOrderRequest::limit_sell("ETH-PERPETUAL".to_string(), 2.0, 3500.0);
470 assert_eq!(order.symbol, "ETH-PERPETUAL");
471 assert_eq!(order.side, OrderSide::Sell);
472 assert_eq!(order.order_type, OrderType::Limit);
473 assert_eq!(order.quantity, 2.0);
474 assert_eq!(order.price, Some(3500.0));
475 assert_eq!(order.time_in_force, TimeInForce::GoodTilCancelled);
476 }
477
478 #[test]
479 fn test_fix_new_order_request_with_client_order_id() {
480 let order = fix::NewOrderRequest::market_buy("BTC-PERPETUAL".to_string(), 1.0)
481 .with_client_order_id("CLIENT_ORDER_123".to_string());
482 assert_eq!(order.client_order_id, Some("CLIENT_ORDER_123".to_string()));
483 }
484
485 #[test]
486 fn test_fix_new_order_request_with_time_in_force() {
487 let order = fix::NewOrderRequest::limit_buy("BTC-PERPETUAL".to_string(), 1.0, 50000.0)
488 .with_time_in_force(TimeInForce::FillOrKill);
489 assert_eq!(order.time_in_force, TimeInForce::FillOrKill);
490 }
491
492 #[test]
493 fn test_new_order_request_market_buy() {
494 let order = NewOrderRequest::market_buy("BTC-PERPETUAL".to_string(), 1.0);
495 assert_eq!(order.instrument_name, "BTC-PERPETUAL");
496 assert_eq!(order.amount, 1.0);
497 assert_eq!(order.order_type, OrderType::Market);
498 assert_eq!(order.side, OrderSide::Buy);
499 assert_eq!(order.price, None);
500 assert_eq!(order.time_in_force, TimeInForce::ImmediateOrCancel);
501 assert_eq!(order.post_only, None);
502 assert_eq!(order.reduce_only, None);
503 }
504
505 #[test]
506 fn test_new_order_request_market_sell() {
507 let order = NewOrderRequest::market_sell("ETH-PERPETUAL".to_string(), 2.0);
508 assert_eq!(order.instrument_name, "ETH-PERPETUAL");
509 assert_eq!(order.amount, 2.0);
510 assert_eq!(order.order_type, OrderType::Market);
511 assert_eq!(order.side, OrderSide::Sell);
512 assert_eq!(order.price, None);
513 assert_eq!(order.time_in_force, TimeInForce::ImmediateOrCancel);
514 }
515
516 #[test]
517 fn test_new_order_request_limit_buy() {
518 let order = NewOrderRequest::limit_buy("BTC-PERPETUAL".to_string(), 1.0, 50000.0);
519 assert_eq!(order.instrument_name, "BTC-PERPETUAL");
520 assert_eq!(order.amount, 1.0);
521 assert_eq!(order.order_type, OrderType::Limit);
522 assert_eq!(order.side, OrderSide::Buy);
523 assert_eq!(order.price, Some(50000.0));
524 assert_eq!(order.time_in_force, TimeInForce::GoodTilCancelled);
525 }
526
527 #[test]
528 fn test_new_order_request_limit_sell() {
529 let order = NewOrderRequest::limit_sell("ETH-PERPETUAL".to_string(), 2.0, 3500.0);
530 assert_eq!(order.instrument_name, "ETH-PERPETUAL");
531 assert_eq!(order.amount, 2.0);
532 assert_eq!(order.order_type, OrderType::Limit);
533 assert_eq!(order.side, OrderSide::Sell);
534 assert_eq!(order.price, Some(3500.0));
535 assert_eq!(order.time_in_force, TimeInForce::GoodTilCancelled);
536 }
537
538 #[test]
539 fn test_new_order_request_with_post_only() {
540 let order = NewOrderRequest::limit_buy("BTC-PERPETUAL".to_string(), 1.0, 50000.0)
541 .with_post_only(true);
542 assert_eq!(order.post_only, Some(true));
543 }
544
545 #[test]
546 fn test_new_order_request_with_reduce_only() {
547 let order = NewOrderRequest::limit_sell("BTC-PERPETUAL".to_string(), 1.0, 50000.0)
548 .with_reduce_only(true);
549 assert_eq!(order.reduce_only, Some(true));
550 }
551
552 #[test]
553 fn test_new_order_request_with_label() {
554 let order = NewOrderRequest::market_buy("BTC-PERPETUAL".to_string(), 1.0)
555 .with_label("test_order".to_string());
556 assert_eq!(order.label, Some("test_order".to_string()));
557 }
558
559 #[test]
560 fn test_new_order_request_with_time_in_force() {
561 let order = NewOrderRequest::limit_buy("BTC-PERPETUAL".to_string(), 1.0, 50000.0)
562 .with_time_in_force(TimeInForce::FillOrKill);
563 assert_eq!(order.time_in_force, TimeInForce::FillOrKill);
564 }
565
566 #[test]
567 fn test_trigger_type_serialization() {
568 let trigger_types = vec![
569 TriggerType::IndexPrice,
570 TriggerType::MarkPrice,
571 TriggerType::LastPrice,
572 ];
573
574 for trigger_type in trigger_types {
575 let json = serde_json::to_string(&trigger_type).unwrap();
576 let deserialized: TriggerType = serde_json::from_str(&json).unwrap();
577 assert_eq!(trigger_type, deserialized);
578 }
579 }
580
581 #[test]
582 fn test_advanced_order_type_serialization() {
583 let advanced_types = vec![AdvancedOrderType::Usd, AdvancedOrderType::Implv];
584
585 for advanced_type in advanced_types {
586 let json = serde_json::to_string(&advanced_type).unwrap();
587 let deserialized: AdvancedOrderType = serde_json::from_str(&json).unwrap();
588 assert_eq!(advanced_type, deserialized);
589 }
590 }
591
592 #[test]
593 fn test_modify_order_request() {
594 let modify_request = ModifyOrderRequest {
595 order_id: "ORDER_123".to_string(),
596 amount: Some(2.0),
597 price: Some(51000.0),
598 stop_price: None,
599 post_only: Some(true),
600 reduce_only: Some(false),
601 reject_post_only: None,
602 advanced: Some(AdvancedOrderType::Usd),
603 };
604
605 assert_eq!(modify_request.order_id, "ORDER_123");
606 assert_eq!(modify_request.amount, Some(2.0));
607 assert_eq!(modify_request.price, Some(51000.0));
608 assert_eq!(modify_request.post_only, Some(true));
609 assert_eq!(modify_request.advanced, Some(AdvancedOrderType::Usd));
610 }
611
612 #[test]
613 fn test_cancel_order_request() {
614 let cancel_request = CancelOrderRequest {
615 order_id: "ORDER_123".to_string(),
616 };
617 assert_eq!(cancel_request.order_id, "ORDER_123");
618 }
619
620 #[test]
621 fn test_cancel_all_orders_request() {
622 let cancel_all_request = CancelAllOrdersRequest {
623 currency: Some("BTC".to_string()),
624 kind: Some("future".to_string()),
625 instrument_type: Some("perpetual".to_string()),
626 };
627
628 assert_eq!(cancel_all_request.currency, Some("BTC".to_string()));
629 assert_eq!(cancel_all_request.kind, Some("future".to_string()));
630 assert_eq!(
631 cancel_all_request.instrument_type,
632 Some("perpetual".to_string())
633 );
634 }
635
636 #[test]
637 fn test_cancel_all_orders_request_empty() {
638 let cancel_all_request = CancelAllOrdersRequest {
639 currency: None,
640 kind: None,
641 instrument_type: None,
642 };
643
644 assert_eq!(cancel_all_request.currency, None);
645 assert_eq!(cancel_all_request.kind, None);
646 assert_eq!(cancel_all_request.instrument_type, None);
647 }
648
649 #[test]
650 fn test_close_position_request() {
651 let close_request = ClosePositionRequest {
652 instrument_name: "BTC-PERPETUAL".to_string(),
653 order_type: OrderType::Market,
654 price: None,
655 };
656
657 assert_eq!(close_request.instrument_name, "BTC-PERPETUAL");
658 assert_eq!(close_request.order_type, OrderType::Market);
659 assert_eq!(close_request.price, None);
660
661 let close_limit_request = ClosePositionRequest {
662 instrument_name: "ETH-PERPETUAL".to_string(),
663 order_type: OrderType::Limit,
664 price: Some(3500.0),
665 };
666
667 assert_eq!(close_limit_request.price, Some(3500.0));
668 }
669
670 #[test]
671 fn test_auth_request_client_credentials() {
672 let auth_request = AuthRequest::client_credentials(
673 "client_id_123".to_string(),
674 "client_secret_456".to_string(),
675 );
676
677 assert_eq!(auth_request.grant_type, "client_credentials");
678 assert_eq!(auth_request.client_id, "client_id_123");
679 assert_eq!(auth_request.client_secret, "client_secret_456");
680 assert_eq!(auth_request.refresh_token, None);
681 assert_eq!(auth_request.scope, None);
682 }
683
684 #[test]
685 fn test_auth_request_refresh_token() {
686 let auth_request = AuthRequest::refresh_token(
687 "client_id_123".to_string(),
688 "client_secret_456".to_string(),
689 "refresh_token_789".to_string(),
690 );
691
692 assert_eq!(auth_request.grant_type, "refresh_token");
693 assert_eq!(auth_request.client_id, "client_id_123");
694 assert_eq!(auth_request.client_secret, "client_secret_456");
695 assert_eq!(
696 auth_request.refresh_token,
697 Some("refresh_token_789".to_string())
698 );
699 assert_eq!(auth_request.scope, None);
700 }
701
702 #[test]
703 fn test_fix_to_rest_conversion() {
704 let fix_order = fix::NewOrderRequest::limit_buy("BTC-PERPETUAL".to_string(), 1.0, 50000.0)
705 .with_client_order_id("CLIENT_ORDER_123".to_string());
706
707 let rest_order: NewOrderRequest = fix_order.into();
708
709 assert_eq!(rest_order.instrument_name, "BTC-PERPETUAL");
710 assert_eq!(rest_order.amount, 1.0);
711 assert_eq!(rest_order.order_type, OrderType::Limit);
712 assert_eq!(rest_order.side, OrderSide::Buy);
713 assert_eq!(rest_order.price, Some(50000.0));
714 assert_eq!(
715 rest_order.client_order_id,
716 Some("CLIENT_ORDER_123".to_string())
717 );
718 assert_eq!(rest_order.post_only, None);
719 assert_eq!(rest_order.reduce_only, None);
720 }
721
722 #[test]
723 fn test_rest_to_fix_conversion() {
724 let rest_order = NewOrderRequest::limit_sell("ETH-PERPETUAL".to_string(), 2.0, 3500.0)
725 .with_label("test_order".to_string())
726 .with_post_only(true);
727
728 let fix_order: fix::NewOrderRequest = rest_order.into();
729
730 assert_eq!(fix_order.symbol, "ETH-PERPETUAL");
731 assert_eq!(fix_order.quantity, 2.0);
732 assert_eq!(fix_order.order_type, OrderType::Limit);
733 assert_eq!(fix_order.side, OrderSide::Sell);
734 assert_eq!(fix_order.price, Some(3500.0));
735 assert_eq!(fix_order.time_in_force, TimeInForce::GoodTilCancelled);
736 }
737
738 #[test]
739 fn test_serialization_roundtrip() {
740 let order = NewOrderRequest::limit_buy("BTC-PERPETUAL".to_string(), 1.0, 50000.0)
741 .with_post_only(true)
742 .with_label("test_order".to_string());
743
744 let json = serde_json::to_string(&order).unwrap();
745 let deserialized: NewOrderRequest = serde_json::from_str(&json).unwrap();
746
747 assert_eq!(order.instrument_name, deserialized.instrument_name);
748 assert_eq!(order.amount, deserialized.amount);
749 assert_eq!(order.order_type, deserialized.order_type);
750 assert_eq!(order.side, deserialized.side);
751 assert_eq!(order.price, deserialized.price);
752 assert_eq!(order.post_only, deserialized.post_only);
753 assert_eq!(order.label, deserialized.label);
754 }
755
756 #[test]
757 fn test_debug_and_display_implementations() {
758 let order = NewOrderRequest::market_buy("BTC-PERPETUAL".to_string(), 1.0);
759 let debug_str = format!("{:?}", order);
760 let display_str = format!("{}", order);
761
762 assert!(debug_str.contains("BTC-PERPETUAL"));
763 assert!(display_str.contains("BTC-PERPETUAL"));
764
765 let auth_request =
766 AuthRequest::client_credentials("client_id".to_string(), "client_secret".to_string());
767 let auth_debug = format!("{:?}", auth_request);
768 let auth_display = format!("{}", auth_request);
769
770 assert!(auth_debug.contains("client_credentials"));
771 assert!(auth_display.contains("client_credentials"));
772 }
773
774 #[test]
775 fn test_enum_equality_and_cloning() {
776 let trigger1 = TriggerType::IndexPrice;
777 let trigger2 = trigger1.clone();
778 assert_eq!(trigger1, trigger2);
779
780 let advanced1 = AdvancedOrderType::Usd;
781 let advanced2 = advanced1.clone();
782 assert_eq!(advanced1, advanced2);
783 }
784
785 #[test]
786 fn test_complex_order_with_all_fields() {
787 let order = NewOrderRequest {
788 instrument_name: "BTC-PERPETUAL".to_string(),
789 amount: 1.5,
790 order_type: OrderType::StopLimit,
791 side: OrderSide::Buy,
792 price: Some(50000.0),
793 time_in_force: TimeInForce::GoodTilDay,
794 post_only: Some(true),
795 reduce_only: Some(false),
796 label: Some("complex_order".to_string()),
797 stop_price: Some(49000.0),
798 trigger: Some(TriggerType::MarkPrice),
799 advanced: Some(AdvancedOrderType::Implv),
800 max_show: Some(0.5),
801 reject_post_only: Some(false),
802 valid_until: Some(1640995200000),
803 client_order_id: Some("CLIENT_ORDER_COMPLEX".to_string()),
804 };
805
806 assert_eq!(order.instrument_name, "BTC-PERPETUAL");
807 assert_eq!(order.amount, 1.5);
808 assert_eq!(order.order_type, OrderType::StopLimit);
809 assert_eq!(order.stop_price, Some(49000.0));
810 assert_eq!(order.trigger, Some(TriggerType::MarkPrice));
811 assert_eq!(order.advanced, Some(AdvancedOrderType::Implv));
812 assert_eq!(order.max_show, Some(0.5));
813 assert_eq!(order.valid_until, Some(1640995200000));
814 }
815}