futu_backend/trade_query/orders/
helpers.rs1use futu_cache::trd_cache::TrdCache;
5
6use super::super::*;
7use crate::proto_internal::odr_sys_cmn;
8
9pub const BACKEND_SECURITY_TYPE_COMMON: u32 = 1;
10pub const BACKEND_SECURITY_TYPE_OPTION: u32 = 2;
11pub const BACKEND_SECURITY_TYPE_FUTURES: u32 = 4;
12pub const BACKEND_SECURITY_TYPE_MULTILEG: u32 = 7;
13
14pub fn is_valid_trd_market(trd_env: i32, market: i32) -> bool {
15 if trd_env == 0 {
16 return true;
18 }
19 matches!(market, 1 | 2 | 4 | 5 | 6 | 8 | 15 | 111 | 112)
20}
21
22pub fn is_futures_trd_market_like_cpp(market: i32) -> bool {
30 matches!(market, 5 | 10 | 11 | 12 | 13)
31}
32
33pub fn order_query_security_types_like_cpp(
43 trd_env: i32,
44 account_trd_market: Option<i32>,
45) -> Vec<u32> {
46 if trd_env == 1 {
47 if account_trd_market.is_some_and(is_futures_trd_market_like_cpp) {
48 vec![BACKEND_SECURITY_TYPE_FUTURES]
49 } else {
50 vec![
51 BACKEND_SECURITY_TYPE_COMMON,
52 BACKEND_SECURITY_TYPE_OPTION,
53 BACKEND_SECURITY_TYPE_MULTILEG,
54 ]
55 }
56 } else {
57 vec![
58 BACKEND_SECURITY_TYPE_COMMON,
59 BACKEND_SECURITY_TYPE_OPTION,
60 BACKEND_SECURITY_TYPE_FUTURES,
61 ]
62 }
63}
64
65pub fn backend_deal_status_to_ftapi(is_cancelled: bool, is_corrected: bool) -> i32 {
74 if is_cancelled {
75 1 } else if is_corrected {
77 2 } else {
79 0 }
81}
82
83pub fn parse_backend_decimal(value: &Option<String>) -> f64 {
84 value
85 .as_ref()
86 .and_then(|v| v.parse::<f64>().ok())
87 .unwrap_or(0.0)
88}
89
90pub fn backend_order_fill_qty_price_for_ftapi(fill: &odr_sys_cmn::OrderFill) -> (f64, f64) {
98 let use_original = fill.is_cancelled.unwrap_or(false)
99 && fill.original_price.is_some()
100 && fill.original_qty.is_some();
101 let qty = if use_original {
102 parse_backend_decimal(&fill.original_qty)
103 } else {
104 parse_backend_decimal(&fill.qty)
105 };
106 let price = if use_original {
107 parse_backend_decimal(&fill.original_price)
108 } else {
109 parse_backend_decimal(&fill.price)
110 };
111 (qty, price)
112}
113
114pub fn convert_trd_market_c2s(client_market: i32) -> u32 {
121 match client_market {
122 111 => 11, 112 => 12, 113 => 13, 114 => 14, 123 => 23, 124 => 24, m if m >= 0 => m as u32,
130 _ => 0,
131 }
132}
133
134pub fn derive_acc_query_context(trd_cache: &TrdCache, acc_id: u64) -> (i32, Option<i32>, Vec<i32>) {
141 if let Some(entry) = trd_cache.accounts.get(&acc_id) {
142 let acc = entry.value();
143 return (
144 acc.trd_env,
145 acc.trd_market,
146 acc.trd_market_auth_list.clone(),
147 );
148 }
149 (0, None, Vec::new())
150}
151
152pub fn derive_backend_market_list(trd_env: i32, enabled_markets: &[i32]) -> Vec<u32> {
155 enabled_markets
156 .iter()
157 .copied()
158 .filter(|m| is_valid_trd_market(trd_env, *m))
159 .map(convert_trd_market_c2s)
160 .collect()
161}
162
163pub fn order_fill_list_cmd_for_env(trd_env: i32) -> u16 {
164 if trd_env == 1 {
165 trade_query_command(TradeQueryOperation::Fills).real_cmd
166 } else {
167 trade_query_command(TradeQueryOperation::Fills).sim_cmd
168 }
169}
170
171pub fn order_info_cmd_for_env(trd_env: i32) -> u16 {
172 if trd_env == 1 {
173 trade_query_command(TradeQueryOperation::OrderInfo).real_cmd
174 } else {
175 trade_query_command(TradeQueryOperation::OrderInfo).sim_cmd
176 }
177}
178
179pub fn order_fill_info_cmd_for_env(trd_env: i32) -> u16 {
180 if trd_env == 1 {
181 trade_query_command(TradeQueryOperation::FillInfo).real_cmd
182 } else {
183 trade_query_command(TradeQueryOperation::FillInfo).sim_cmd
184 }
185}
186
187pub fn history_order_list_cmd_for_env(trd_env: i32) -> u16 {
188 if trd_env == 1 {
189 trade_query_command(TradeQueryOperation::HistoryOrders).real_cmd
190 } else {
191 trade_query_command(TradeQueryOperation::HistoryOrders).sim_cmd
192 }
193}
194
195pub fn history_order_fill_list_cmd_for_env(trd_env: i32) -> u16 {
196 if trd_env == 1 {
197 trade_query_command(TradeQueryOperation::HistoryFills).real_cmd
198 } else {
199 trade_query_command(TradeQueryOperation::HistoryFills).sim_cmd
200 }
201}