futu_backend/trade_query/orders/
status_helpers.rs1use std::sync::Arc;
5
6use futu_cache::trd_cache::TrdCache;
7
8use super::super::*;
9use crate::conn::BackendConn;
10use crate::proto_internal::odr_sys_cmn;
11
12use super::types::BackendResponseStatusError;
13
14pub fn backend_trade_response_status_like_cpp(
15 message_name: &str,
16 result: Option<i32>,
17 msg_header: Option<&odr_sys_cmn::MsgHeader>,
18 err_msg: Option<&str>,
19 acc_id: u64,
20) -> std::result::Result<(), BackendResponseStatusError> {
21 let result = result.ok_or_else(|| BackendResponseStatusError {
22 result: -1,
23 message: format!("{message_name} missing result"),
24 is_backend_error: false,
25 })?;
26 let msg_header = msg_header.ok_or_else(|| BackendResponseStatusError {
27 result: -1,
28 message: format!("{message_name} missing msg_header"),
29 is_backend_error: false,
30 })?;
31 let backend_acc_id = msg_header
32 .account_id
33 .ok_or_else(|| BackendResponseStatusError {
34 result: -1,
35 message: format!("{message_name} msg_header missing account_id"),
36 is_backend_error: false,
37 })?;
38 if backend_acc_id != acc_id {
39 return Err(BackendResponseStatusError {
40 result: -1,
41 message: format!(
42 "{message_name} msg_header.account_id mismatch, got {backend_acc_id}, expected {acc_id}"
43 ),
44 is_backend_error: false,
45 });
46 }
47 if result != 0 {
48 return Err(BackendResponseStatusError {
49 result,
50 message: err_msg
51 .unwrap_or("trade query backend rejected")
52 .to_string(),
53 is_backend_error: true,
54 });
55 }
56 Ok(())
57}
58
59pub fn backend_order_list_status_like_cpp(
65 result: Option<i32>,
66 msg_header: Option<&odr_sys_cmn::MsgHeader>,
67 err_msg: Option<&str>,
68 acc_id: u64,
69) -> std::result::Result<(), BackendResponseStatusError> {
70 backend_trade_response_status_like_cpp("OrderListRsp", result, msg_header, err_msg, acc_id)
71}
72
73pub fn backend_order_fill_list_status_like_cpp(
79 result: Option<i32>,
80 msg_header: Option<&odr_sys_cmn::MsgHeader>,
81 err_msg: Option<&str>,
82 acc_id: u64,
83) -> std::result::Result<(), BackendResponseStatusError> {
84 backend_trade_response_status_like_cpp("OrderFillListRsp", result, msg_header, err_msg, acc_id)
85}
86
87pub fn backend_order_fill_info_status_like_cpp(
91 result: Option<i32>,
92 msg_header: Option<&odr_sys_cmn::MsgHeader>,
93 err_msg: Option<&str>,
94 acc_id: u64,
95 expected_count: usize,
96 actual_count: usize,
97) -> std::result::Result<(), BackendResponseStatusError> {
98 backend_trade_response_status_like_cpp(
99 "OrderFillInfoRsp",
100 result,
101 msg_header,
102 err_msg,
103 acc_id,
104 )?;
105 if actual_count == 0 || actual_count != expected_count {
106 return Err(BackendResponseStatusError {
107 result: -1,
108 message: format!(
109 "OrderFillInfoRsp order_fills count mismatch, got {actual_count}, expected {expected_count}"
110 ),
111 is_backend_error: false,
112 });
113 }
114 Ok(())
115}
116
117pub fn backend_order_status_to_ftapi(status: u32) -> i32 {
123 match status {
124 1 => 2, 2 => 5, 3 => 10, 4 => 11, 5 => 15, 6 => 21, 7 => 14, 101 => 22, 102 => 1, 103 => 24, 104 => 23, _ => -1, }
137}
138
139pub fn backend_order_type_to_ftapi(
152 order_type: u32,
153 trd_market: Option<i32>,
154 security_type: Option<i32>,
155) -> i32 {
156 const TRD_MARKET_HK: i32 = 1;
157 const SECURITY_TYPE_COMMON: i32 = 1;
158 let is_hk_common =
159 trd_market == Some(TRD_MARKET_HK) && security_type == Some(SECURITY_TYPE_COMMON);
160
161 match order_type {
162 1 if is_hk_common => 5, 1 => 1, 2 => 1, 3 => 2, 4 => 6, 5 => 7, 6 => 9, 7 => 8, 8 => 10, 9 => 11, 10 => 12, 11 => 13, 12 => 14, 13 => 15, 21 => 16, 22 => 17, 23 => 18, 24 => 19, _ => -1,
181 }
182}
183
184pub fn map_backend_market_to_trd_market(market: u32) -> i32 {
186 match market {
187 1 => 1, 2 => 2, 3 => 3, 10 => 5, 15 => 6, v => v as i32,
193 }
194}
195
196pub fn backend_real_market_to_trd_market_like_cpp(market: u32) -> i32 {
197 match market {
198 7 => 200, 11 => 111, 12 => 112, 13 => 113, 14 => 114, 15 => 15, 23 => 123, 24 => 124, v => v as i32,
207 }
208}
209
210pub fn is_valid_real_trd_market_like_cpp(trd_market: i32) -> bool {
211 matches!(trd_market, 1 | 2 | 4 | 5 | 6 | 8 | 15 | 111 | 112 | 200)
212}
213
214pub fn backend_order_unpacked_trd_market_like_cpp(
215 trd_env: i32,
216 o: &odr_sys_cmn::Order,
217) -> Option<Option<i32>> {
218 o.order_id.as_ref()?;
222 o.side?;
223 let trd_market = if trd_env == 1 {
224 let trd_market = backend_real_market_to_trd_market_like_cpp(o.market?);
225 if !is_valid_real_trd_market_like_cpp(trd_market) {
226 return None;
227 }
228 Some(trd_market)
229 } else {
230 o.market.map(map_backend_market_to_trd_market)
231 };
232 o.symbol.as_ref()?;
233 o.create_time?;
234 o.status?;
235 Some(trd_market)
236}
237
238pub async fn init_trade_data(backend: &Arc<BackendConn>, trd_cache: &Arc<TrdCache>) {
240 let accounts = trd_cache.get_accounts();
241 let real_accounts: Vec<u64> = accounts
242 .iter()
243 .filter(|a| a.trd_env == 1) .map(|a| a.acc_id)
245 .collect();
246
247 tracing::info!(
248 count = real_accounts.len(),
249 "querying trade data for real accounts"
250 );
251
252 for &acc_id in &real_accounts {
253 let _ = query_account_info(backend, acc_id, trd_cache, None, None).await;
258 }
259
260 tracing::info!("trade data initialization complete");
261}