1use futu_core::error::{FutuError, Result};
4use prost::Message;
5
6use crate::proto_internal::odr_sys_cmn::{AssetChangeData, Order, OrderFill, RequsetResult};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum TradeNotifyPushSource {
10 Real,
11 Sim,
12}
13
14impl TradeNotifyPushSource {
15 const fn cmd_id(self) -> u16 {
16 match self {
17 Self::Real => futu_command_spec::CMD_TRADE_NOTIFY_PUSH,
18 Self::Sim => futu_command_spec::CMD_TRADE_NOTIFY_PUSH_SIM,
19 }
20 }
21}
22
23#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct TradeNotifyHeader {
25 pub req_id: Option<Vec<u8>>,
26 pub account_id: Option<u64>,
27 pub cipher: Option<Vec<u8>>,
28 pub security_type: Option<u32>,
29 pub exchange_code: Option<u32>,
30 pub input_source: Option<u32>,
31 pub account_scope: Option<u64>,
34}
35
36#[derive(Debug, Clone, PartialEq)]
37pub struct TradeNotifyPush {
38 pub source: TradeNotifyPushSource,
39 pub header: Option<TradeNotifyHeader>,
40 pub notice_type: Option<u32>,
41 pub pstn_ids: Vec<String>,
42 pub order_ids: Vec<String>,
43 pub order_fill_ids: Vec<String>,
44 pub order_op_req_ids: Vec<String>,
45 pub exchange: Option<String>,
46 pub version: Option<u64>,
47 pub deprecated_asset_category: Option<u32>,
48 pub err_code: Option<i32>,
49 pub orders: Vec<Order>,
50 pub order_fills: Vec<OrderFill>,
51 pub origin_request_result: Vec<RequsetResult>,
52 pub asset_change_data: Option<AssetChangeData>,
53}
54
55pub fn decode_trade_notify_push(
56 source: TradeNotifyPushSource,
57 body: &[u8],
58) -> Result<TradeNotifyPush> {
59 let wire = TradeNotifyWire::decode(body)
60 .map_err(|error| FutuError::Codec(format!("CMD{} decode: {error}", source.cmd_id())))?;
61 Ok(TradeNotifyPush {
62 source,
63 header: wire.msg_header.map(TradeNotifyHeader::from),
64 notice_type: wire.notice_type,
65 pstn_ids: wire.pstn_ids,
66 order_ids: wire.order_ids,
67 order_fill_ids: wire.order_fill_ids,
68 order_op_req_ids: wire.order_op_req_ids,
69 exchange: wire.exchange,
70 version: wire.version,
71 deprecated_asset_category: wire.asset_category,
72 err_code: wire.err_code,
73 orders: wire.orders,
74 order_fills: wire.order_fills,
75 origin_request_result: wire.origin_request_result,
76 asset_change_data: wire.asset_change_data,
77 })
78}
79
80impl From<TradeNotifyHeaderWire> for TradeNotifyHeader {
81 fn from(wire: TradeNotifyHeaderWire) -> Self {
82 Self {
83 req_id: wire.req_id,
84 account_id: wire.account_id,
85 cipher: wire.cipher,
86 security_type: wire.security_type,
87 exchange_code: wire.exchange_code,
88 input_source: wire.input_source,
89 account_scope: wire.account_scope,
90 }
91 }
92}
93
94#[derive(Clone, PartialEq, Message)]
95struct TradeNotifyWire {
96 #[prost(message, optional, tag = "1")]
97 msg_header: Option<TradeNotifyHeaderWire>,
98 #[prost(uint32, optional, tag = "2")]
99 notice_type: Option<u32>,
100 #[prost(string, repeated, tag = "3")]
101 pstn_ids: Vec<String>,
102 #[prost(string, repeated, tag = "4")]
103 order_ids: Vec<String>,
104 #[prost(string, repeated, tag = "5")]
105 order_fill_ids: Vec<String>,
106 #[prost(string, repeated, tag = "6")]
107 order_op_req_ids: Vec<String>,
108 #[prost(string, optional, tag = "7")]
109 exchange: Option<String>,
110 #[prost(uint64, optional, tag = "8")]
111 version: Option<u64>,
112 #[prost(uint32, optional, tag = "9")]
113 asset_category: Option<u32>,
114 #[prost(int32, optional, tag = "10")]
115 err_code: Option<i32>,
116 #[prost(message, repeated, tag = "100")]
117 orders: Vec<Order>,
118 #[prost(message, repeated, tag = "101")]
119 order_fills: Vec<OrderFill>,
120 #[prost(message, repeated, tag = "102")]
121 origin_request_result: Vec<RequsetResult>,
122 #[prost(message, optional, tag = "103")]
123 asset_change_data: Option<AssetChangeData>,
124}
125
126#[derive(Clone, PartialEq, Eq, Message)]
127struct TradeNotifyHeaderWire {
128 #[prost(bytes = "vec", optional, tag = "1")]
131 req_id: Option<Vec<u8>>,
132 #[prost(uint64, optional, tag = "2")]
133 account_id: Option<u64>,
134 #[prost(bytes = "vec", optional, tag = "3")]
135 cipher: Option<Vec<u8>>,
136 #[prost(uint32, optional, tag = "4")]
137 security_type: Option<u32>,
138 #[prost(uint32, optional, tag = "5")]
139 exchange_code: Option<u32>,
140 #[prost(uint32, optional, tag = "6")]
141 input_source: Option<u32>,
142 #[prost(uint64, optional, tag = "7")]
143 account_scope: Option<u64>,
144}
145
146#[cfg(test)]
147#[path = "trade_notify_push_tests.rs"]
148mod trade_notify_push_tests;