1use nautilus_core::serialization::serialize_decimal_as_str;
22use nautilus_model::{
23 data::{Bar, Data, OrderBookDeltas},
24 events::{OrderCancelRejected, OrderRejected},
25 identifiers::ClientOrderId,
26 reports::{FillReport, OrderStatusReport},
27};
28use rust_decimal::Decimal;
29use serde::{Deserialize, Serialize};
30use ustr::Ustr;
31
32use super::error::AxWsErrorResponse;
33use crate::common::{
34 enums::{AxCandleWidth, AxMarketDataLevel, AxOrderSide, AxOrderStatus, AxTimeInForce},
35 parse::deserialize_decimal_or_zero,
36};
37
38#[derive(Clone, Debug, Serialize, Deserialize)]
43pub struct AxMdSubscribe {
44 pub request_id: i64,
46 #[serde(rename = "type")]
48 pub msg_type: String,
49 pub symbol: String,
51 pub level: AxMarketDataLevel,
53}
54
55#[derive(Clone, Debug, Serialize, Deserialize)]
60pub struct AxMdUnsubscribe {
61 pub request_id: i64,
63 #[serde(rename = "type")]
65 pub msg_type: String,
66 pub symbol: String,
68}
69
70#[derive(Clone, Debug, Serialize, Deserialize)]
75pub struct AxMdSubscribeCandles {
76 pub request_id: i64,
78 #[serde(rename = "type")]
80 pub msg_type: String,
81 pub symbol: String,
83 pub width: AxCandleWidth,
85}
86
87#[derive(Clone, Debug, Serialize, Deserialize)]
92pub struct AxMdUnsubscribeCandles {
93 pub request_id: i64,
95 #[serde(rename = "type")]
97 pub msg_type: String,
98 pub symbol: String,
100 pub width: AxCandleWidth,
102}
103
104#[derive(Clone, Debug, Serialize, Deserialize)]
109pub struct AxMdHeartbeat {
110 pub t: String,
112 pub ts: i64,
114 pub tn: i64,
116}
117
118#[derive(Clone, Debug, Serialize, Deserialize)]
123pub struct AxMdTicker {
124 pub t: String,
126 pub ts: i64,
128 pub tn: i64,
130 pub s: Ustr,
132 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
134 pub p: Decimal,
135 pub q: i64,
137 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
139 pub o: Decimal,
140 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
142 pub l: Decimal,
143 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
145 pub h: Decimal,
146 pub v: i64,
148 #[serde(default)]
150 pub oi: Option<i64>,
151}
152
153#[derive(Clone, Debug, Serialize, Deserialize)]
160pub struct AxMdTrade {
161 pub t: String,
163 pub ts: i64,
165 pub tn: i64,
167 pub s: Ustr,
169 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
171 pub p: Decimal,
172 pub q: i64,
174 pub d: AxOrderSide,
176}
177
178#[derive(Clone, Debug, Serialize, Deserialize)]
183pub struct AxMdCandle {
184 pub t: String,
186 pub symbol: Ustr,
188 pub ts: i64,
190 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
192 pub open: Decimal,
193 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
195 pub low: Decimal,
196 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
198 pub high: Decimal,
199 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
201 pub close: Decimal,
202 pub volume: i64,
204 pub buy_volume: i64,
206 pub sell_volume: i64,
208 pub width: AxCandleWidth,
210}
211
212#[derive(Clone, Debug, Serialize, Deserialize)]
214pub struct AxBookLevel {
215 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
217 pub p: Decimal,
218 pub q: i64,
220}
221
222#[derive(Clone, Debug, Serialize, Deserialize)]
224pub struct AxBookLevelL3 {
225 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
227 pub p: Decimal,
228 pub q: i64,
230 pub o: Vec<i64>,
232}
233
234#[derive(Clone, Debug, Serialize, Deserialize)]
239pub struct AxMdBookL1 {
240 pub t: String,
242 pub ts: i64,
244 pub tn: i64,
246 pub s: Ustr,
248 pub b: Vec<AxBookLevel>,
250 pub a: Vec<AxBookLevel>,
252}
253
254#[derive(Clone, Debug, Serialize, Deserialize)]
259pub struct AxMdBookL2 {
260 pub t: String,
262 pub ts: i64,
264 pub tn: i64,
266 pub s: Ustr,
268 pub b: Vec<AxBookLevel>,
270 pub a: Vec<AxBookLevel>,
272}
273
274#[derive(Clone, Debug, Serialize, Deserialize)]
279pub struct AxMdBookL3 {
280 pub t: String,
282 pub ts: i64,
284 pub tn: i64,
286 pub s: Ustr,
288 pub b: Vec<AxBookLevelL3>,
290 pub a: Vec<AxBookLevelL3>,
292}
293
294#[derive(Clone, Debug, Serialize, Deserialize)]
299pub struct AxWsPlaceOrder {
300 pub rid: i64,
302 pub t: String,
304 pub s: String,
306 pub d: AxOrderSide,
308 pub q: i64,
310 #[serde(
312 serialize_with = "serialize_decimal_as_str",
313 deserialize_with = "deserialize_decimal_or_zero"
314 )]
315 pub p: Decimal,
316 pub tif: AxTimeInForce,
318 pub po: bool,
320 #[serde(skip_serializing_if = "Option::is_none")]
322 pub tag: Option<String>,
323}
324
325#[derive(Clone, Debug, Serialize, Deserialize)]
330pub struct AxWsCancelOrder {
331 pub rid: i64,
333 pub t: String,
335 pub oid: String,
337}
338
339#[derive(Clone, Debug, Serialize, Deserialize)]
344pub struct AxWsGetOpenOrders {
345 pub rid: i64,
347 pub t: String,
349}
350
351#[derive(Clone, Debug, Serialize, Deserialize)]
356pub struct AxWsPlaceOrderResponse {
357 pub rid: i64,
359 pub res: AxWsPlaceOrderResult,
361}
362
363#[derive(Clone, Debug, Serialize, Deserialize)]
365pub struct AxWsPlaceOrderResult {
366 pub oid: String,
368}
369
370#[derive(Clone, Debug, Serialize, Deserialize)]
375pub struct AxWsCancelOrderResponse {
376 pub rid: i64,
378 pub res: AxWsCancelOrderResult,
380}
381
382#[derive(Clone, Debug, Serialize, Deserialize)]
384pub struct AxWsCancelOrderResult {
385 pub cxl_rx: bool,
387}
388
389#[derive(Clone, Debug, Serialize, Deserialize)]
394pub struct AxWsOpenOrdersResponse {
395 pub rid: i64,
397 pub res: Vec<AxWsOrder>,
399}
400
401#[derive(Clone, Debug, Serialize, Deserialize)]
403pub struct AxWsOrder {
404 pub oid: String,
406 pub u: String,
408 pub s: Ustr,
410 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
412 pub p: Decimal,
413 pub q: i64,
415 pub xq: i64,
417 pub rq: i64,
419 pub o: AxOrderStatus,
421 pub d: AxOrderSide,
423 pub tif: AxTimeInForce,
425 pub ts: i64,
427 pub tn: i64,
429 #[serde(default)]
431 pub tag: Option<String>,
432}
433
434#[derive(Clone, Debug, Serialize, Deserialize)]
439pub struct AxWsHeartbeat {
440 pub t: String,
442 pub ts: i64,
444 pub tn: i64,
446}
447
448#[derive(Clone, Debug, Serialize, Deserialize)]
453pub struct AxWsOrderAcknowledged {
454 pub t: String,
456 pub ts: i64,
458 pub tn: i64,
460 pub eid: String,
462 pub o: AxWsOrder,
464}
465
466#[derive(Clone, Debug, Serialize, Deserialize)]
468pub struct AxWsTradeExecution {
469 pub tid: String,
471 pub s: Ustr,
473 pub q: i64,
475 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
477 pub p: Decimal,
478 pub d: AxOrderSide,
480 pub agg: bool,
482}
483
484#[derive(Clone, Debug, Serialize, Deserialize)]
489pub struct AxWsOrderPartiallyFilled {
490 pub t: String,
492 pub ts: i64,
494 pub tn: i64,
496 pub eid: String,
498 pub o: AxWsOrder,
500 pub xs: AxWsTradeExecution,
502}
503
504#[derive(Clone, Debug, Serialize, Deserialize)]
509pub struct AxWsOrderFilled {
510 pub t: String,
512 pub ts: i64,
514 pub tn: i64,
516 pub eid: String,
518 pub o: AxWsOrder,
520 pub xs: AxWsTradeExecution,
522}
523
524#[derive(Clone, Debug, Serialize, Deserialize)]
529pub struct AxWsOrderCanceled {
530 pub t: String,
532 pub ts: i64,
534 pub tn: i64,
536 pub eid: String,
538 pub o: AxWsOrder,
540 pub xr: String,
542 #[serde(default)]
544 pub txt: Option<String>,
545}
546
547#[derive(Clone, Debug, Serialize, Deserialize)]
552pub struct AxWsOrderRejected {
553 pub t: String,
555 pub ts: i64,
557 pub tn: i64,
559 pub eid: String,
561 pub o: AxWsOrder,
563 pub r: String,
565 #[serde(default)]
567 pub txt: Option<String>,
568}
569
570#[derive(Clone, Debug, Serialize, Deserialize)]
575pub struct AxWsOrderExpired {
576 pub t: String,
578 pub ts: i64,
580 pub tn: i64,
582 pub eid: String,
584 pub o: AxWsOrder,
586}
587
588#[derive(Clone, Debug, Serialize, Deserialize)]
593pub struct AxWsOrderReplaced {
594 pub t: String,
596 pub ts: i64,
598 pub tn: i64,
600 pub eid: String,
602 pub o: AxWsOrder,
604}
605
606#[derive(Clone, Debug, Serialize, Deserialize)]
611pub struct AxWsOrderDoneForDay {
612 pub t: String,
614 pub ts: i64,
616 pub tn: i64,
618 pub eid: String,
620 pub o: AxWsOrder,
622}
623
624#[derive(Clone, Debug, Serialize, Deserialize)]
629pub struct AxWsCancelRejected {
630 pub t: String,
632 pub ts: i64,
634 pub tn: i64,
636 pub oid: String,
638 pub r: String,
640 #[serde(default)]
642 pub txt: Option<String>,
643}
644
645#[derive(Debug, Clone)]
650pub enum NautilusWsMessage {
651 Data(Vec<Data>),
653 Deltas(OrderBookDeltas),
655 Bar(Bar),
657 Heartbeat,
659 Error(AxWsError),
661 Reconnected,
663}
664
665#[derive(Debug, Clone)]
671pub enum AxOrdersWsMessage {
672 OrderStatusReports(Vec<OrderStatusReport>),
674 FillReports(Vec<FillReport>),
676 OrderRejected(OrderRejected),
678 OrderCancelRejected(OrderCancelRejected),
680 OrderAcknowledged(AxWsOrderAcknowledged),
682 OrderPartiallyFilled(AxWsOrderPartiallyFilled),
684 OrderFilled(AxWsOrderFilled),
686 OrderCanceled(AxWsOrderCanceled),
688 OrderRejectedRaw(AxWsOrderRejected),
690 OrderExpired(AxWsOrderExpired),
692 OrderReplaced(AxWsOrderReplaced),
694 OrderDoneForDay(AxWsOrderDoneForDay),
696 CancelRejected(AxWsCancelRejected),
698 PlaceOrderResponse(AxWsPlaceOrderResponse),
700 CancelOrderResponse(AxWsCancelOrderResponse),
702 OpenOrdersResponse(AxWsOpenOrdersResponse),
704 Error(AxWsError),
706 Reconnected,
708 Authenticated,
710}
711
712#[derive(Debug, Clone)]
714pub struct AxWsError {
715 pub code: Option<String>,
717 pub message: String,
719 pub request_id: Option<i64>,
721}
722
723impl AxWsError {
724 #[must_use]
726 pub fn new(message: impl Into<String>) -> Self {
727 Self {
728 code: None,
729 message: message.into(),
730 request_id: None,
731 }
732 }
733
734 #[must_use]
736 pub fn with_code(code: impl Into<String>, message: impl Into<String>) -> Self {
737 Self {
738 code: Some(code.into()),
739 message: message.into(),
740 request_id: None,
741 }
742 }
743}
744
745impl From<AxWsErrorResponse> for AxWsError {
746 fn from(resp: AxWsErrorResponse) -> Self {
747 Self {
748 code: resp.code,
749 message: resp.message.unwrap_or_else(|| "Unknown error".to_string()),
750 request_id: resp.rid,
751 }
752 }
753}
754
755#[derive(Debug, Clone)]
759pub struct OrderMetadata {
760 pub client_order_id: ClientOrderId,
762 pub symbol: Ustr,
764}
765
766#[cfg(test)]
767mod tests {
768 use rstest::rstest;
769 use rust_decimal_macros::dec;
770
771 use super::*;
772
773 #[rstest]
774 fn test_md_subscribe_serialization() {
775 let msg = AxMdSubscribe {
776 request_id: 2,
777 msg_type: "subscribe".to_string(),
778 symbol: "BTCUSD-PERP".to_string(),
779 level: AxMarketDataLevel::Level2,
780 };
781 let json = serde_json::to_string(&msg).unwrap();
782 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
783
784 assert_eq!(parsed["request_id"], 2);
785 assert_eq!(parsed["type"], "subscribe");
786 assert_eq!(parsed["symbol"], "BTCUSD-PERP");
787 assert_eq!(parsed["level"], "LEVEL_2");
788 }
789
790 #[rstest]
791 fn test_md_unsubscribe_serialization() {
792 let msg = AxMdUnsubscribe {
793 request_id: 3,
794 msg_type: "unsubscribe".to_string(),
795 symbol: "BTCUSD-PERP".to_string(),
796 };
797 let json = serde_json::to_string(&msg).unwrap();
798 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
799
800 assert_eq!(parsed["request_id"], 3);
801 assert_eq!(parsed["type"], "unsubscribe");
802 assert_eq!(parsed["symbol"], "BTCUSD-PERP");
803 }
804
805 #[rstest]
806 fn test_md_subscribe_candles_serialization() {
807 let msg = AxMdSubscribeCandles {
808 request_id: 4,
809 msg_type: "subscribe_candles".to_string(),
810 symbol: "BTCUSD-PERP".to_string(),
811 width: AxCandleWidth::Minutes1,
812 };
813 let json = serde_json::to_string(&msg).unwrap();
814 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
815
816 assert_eq!(parsed["request_id"], 4);
817 assert_eq!(parsed["type"], "subscribe_candles");
818 assert_eq!(parsed["symbol"], "BTCUSD-PERP");
819 assert_eq!(parsed["width"], "1m");
820 }
821
822 #[rstest]
823 fn test_md_unsubscribe_candles_serialization() {
824 let msg = AxMdUnsubscribeCandles {
825 request_id: 5,
826 msg_type: "unsubscribe_candles".to_string(),
827 symbol: "BTCUSD-PERP".to_string(),
828 width: AxCandleWidth::Minutes1,
829 };
830 let json = serde_json::to_string(&msg).unwrap();
831 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
832
833 assert_eq!(parsed["request_id"], 5);
834 assert_eq!(parsed["type"], "unsubscribe_candles");
835 assert_eq!(parsed["symbol"], "BTCUSD-PERP");
836 assert_eq!(parsed["width"], "1m");
837 }
838
839 #[rstest]
840 fn test_ws_place_order_serialization() {
841 let msg = AxWsPlaceOrder {
842 rid: 1,
843 t: "p".to_string(),
844 s: "BTCUSD-PERP".to_string(),
845 d: AxOrderSide::Buy,
846 q: 100,
847 p: dec!(50000.50),
848 tif: AxTimeInForce::Gtc,
849 po: false,
850 tag: Some("trade001".to_string()),
851 };
852
853 let json = serde_json::to_string(&msg).unwrap();
854 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
855
856 assert_eq!(parsed["rid"], 1);
857 assert_eq!(parsed["t"], "p");
858 assert_eq!(parsed["s"], "BTCUSD-PERP");
859 assert_eq!(parsed["d"], "B");
860 assert_eq!(parsed["q"], 100);
861 assert_eq!(parsed["p"], "50000.5");
862 assert_eq!(parsed["tif"], "GTC");
863 assert_eq!(parsed["po"], false);
864 assert_eq!(parsed["tag"], "trade001");
865 }
866
867 #[rstest]
868 fn test_ws_cancel_order_serialization() {
869 let msg = AxWsCancelOrder {
870 rid: 2,
871 t: "x".to_string(),
872 oid: "O-01ARZ3NDEKTSV4RRFFQ69G5FAV".to_string(),
873 };
874 let json = serde_json::to_string(&msg).unwrap();
875 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
876
877 assert_eq!(parsed["rid"], 2);
878 assert_eq!(parsed["t"], "x");
879 assert_eq!(parsed["oid"], "O-01ARZ3NDEKTSV4RRFFQ69G5FAV");
880 }
881
882 #[rstest]
883 fn test_ws_get_open_orders_serialization() {
884 let msg = AxWsGetOpenOrders {
885 rid: 3,
886 t: "o".to_string(),
887 };
888 let json = serde_json::to_string(&msg).unwrap();
889 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
890
891 assert_eq!(parsed["rid"], 3);
892 assert_eq!(parsed["t"], "o");
893 }
894
895 #[rstest]
896 fn test_load_md_heartbeat_from_file() {
897 let json = include_str!("../../test_data/ws_md_heartbeat.json");
898 let msg: AxMdHeartbeat = serde_json::from_str(json).unwrap();
899 assert_eq!(msg.t, "h");
900 }
901
902 #[rstest]
903 fn test_load_md_ticker_from_file() {
904 let json = include_str!("../../test_data/ws_md_ticker.json");
905 let msg: AxMdTicker = serde_json::from_str(json).unwrap();
906 assert_eq!(msg.s.as_str(), "BTCUSD-PERP");
907 }
908
909 #[rstest]
910 fn test_load_md_trade_from_file() {
911 let json = include_str!("../../test_data/ws_md_trade.json");
912 let msg: AxMdTrade = serde_json::from_str(json).unwrap();
913 assert_eq!(msg.d, AxOrderSide::Buy);
914 }
915
916 #[rstest]
917 fn test_load_md_candle_from_file() {
918 let json = include_str!("../../test_data/ws_md_candle.json");
919 let msg: AxMdCandle = serde_json::from_str(json).unwrap();
920 assert_eq!(msg.width, AxCandleWidth::Minutes1);
921 }
922
923 #[rstest]
924 fn test_load_md_book_l1_from_file() {
925 let json = include_str!("../../test_data/ws_md_book_l1.json");
926 let msg: AxMdBookL1 = serde_json::from_str(json).unwrap();
927 assert_eq!(msg.b.len(), 1);
928 assert_eq!(msg.a.len(), 1);
929 }
930
931 #[rstest]
932 fn test_load_md_book_l2_from_file() {
933 let json = include_str!("../../test_data/ws_md_book_l2.json");
934 let msg: AxMdBookL2 = serde_json::from_str(json).unwrap();
935 assert_eq!(msg.b.len(), 3);
936 assert_eq!(msg.a.len(), 3);
937 }
938
939 #[rstest]
940 fn test_load_md_book_l3_from_file() {
941 let json = include_str!("../../test_data/ws_md_book_l3.json");
942 let msg: AxMdBookL3 = serde_json::from_str(json).unwrap();
943 assert_eq!(msg.b.len(), 2);
944 assert!(!msg.b[0].o.is_empty());
945 }
946
947 #[rstest]
948 fn test_load_order_place_response_from_file() {
949 let json = include_str!("../../test_data/ws_order_place_response.json");
950 let msg: AxWsPlaceOrderResponse = serde_json::from_str(json).unwrap();
951 assert_eq!(msg.res.oid, "O-01ARZ3NDEKTSV4RRFFQ69G5FAV");
952 }
953
954 #[rstest]
955 fn test_load_order_cancel_response_from_file() {
956 let json = include_str!("../../test_data/ws_order_cancel_response.json");
957 let msg: AxWsCancelOrderResponse = serde_json::from_str(json).unwrap();
958 assert!(msg.res.cxl_rx);
959 }
960
961 #[rstest]
962 fn test_load_order_open_orders_response_from_file() {
963 let json = include_str!("../../test_data/ws_order_open_orders_response.json");
964 let msg: AxWsOpenOrdersResponse = serde_json::from_str(json).unwrap();
965 assert_eq!(msg.res.len(), 1);
966 }
967
968 #[rstest]
969 fn test_load_order_heartbeat_from_file() {
970 let json = include_str!("../../test_data/ws_order_heartbeat.json");
971 let msg: AxWsHeartbeat = serde_json::from_str(json).unwrap();
972 assert_eq!(msg.t, "h");
973 }
974
975 #[rstest]
976 fn test_load_order_acknowledged_from_file() {
977 let json = include_str!("../../test_data/ws_order_acknowledged.json");
978 let msg: AxWsOrderAcknowledged = serde_json::from_str(json).unwrap();
979 assert_eq!(msg.t, "n");
980 }
981
982 #[rstest]
983 fn test_load_order_filled_from_file() {
984 let json = include_str!("../../test_data/ws_order_filled.json");
985 let msg: AxWsOrderFilled = serde_json::from_str(json).unwrap();
986 assert_eq!(msg.o.o, AxOrderStatus::Filled);
987 }
988
989 #[rstest]
990 fn test_load_order_partially_filled_from_file() {
991 let json = include_str!("../../test_data/ws_order_partially_filled.json");
992 let msg: AxWsOrderPartiallyFilled = serde_json::from_str(json).unwrap();
993 assert_eq!(msg.xs.q, 50);
994 }
995
996 #[rstest]
997 fn test_load_order_canceled_from_file() {
998 let json = include_str!("../../test_data/ws_order_canceled.json");
999 let msg: AxWsOrderCanceled = serde_json::from_str(json).unwrap();
1000 assert_eq!(msg.xr, "USER_REQUESTED");
1001 }
1002
1003 #[rstest]
1004 fn test_load_order_rejected_from_file() {
1005 let json = include_str!("../../test_data/ws_order_rejected.json");
1006 let msg: AxWsOrderRejected = serde_json::from_str(json).unwrap();
1007 assert_eq!(msg.r, "INSUFFICIENT_MARGIN");
1008 }
1009
1010 #[rstest]
1011 fn test_load_order_expired_from_file() {
1012 let json = include_str!("../../test_data/ws_order_expired.json");
1013 let msg: AxWsOrderExpired = serde_json::from_str(json).unwrap();
1014 assert_eq!(msg.o.tif, AxTimeInForce::Ioc);
1015 }
1016
1017 #[rstest]
1018 fn test_load_order_replaced_from_file() {
1019 let json = include_str!("../../test_data/ws_order_replaced.json");
1020 let msg: AxWsOrderReplaced = serde_json::from_str(json).unwrap();
1021 assert_eq!(msg.t, "r");
1022 assert_eq!(msg.o.p, dec!(50500.00));
1023 }
1024
1025 #[rstest]
1026 fn test_load_order_done_for_day_from_file() {
1027 let json = include_str!("../../test_data/ws_order_done_for_day.json");
1028 let msg: AxWsOrderDoneForDay = serde_json::from_str(json).unwrap();
1029 assert_eq!(msg.t, "d");
1030 assert_eq!(msg.o.xq, 50);
1031 }
1032
1033 #[rstest]
1034 fn test_load_cancel_rejected_from_file() {
1035 let json = include_str!("../../test_data/ws_cancel_rejected.json");
1036 let msg: AxWsCancelRejected = serde_json::from_str(json).unwrap();
1037 assert_eq!(msg.r, "ORDER_NOT_FOUND");
1038 }
1039}