1use futu_cache::trd_cache::CachedOrder;
4use futu_domain_trade_history::projection::backend_orders::{
5 BackendOrderSupFacts, BackendTradeReadOrderFacts, project_backend_trade_read_order_like_cpp,
6};
7use futu_domain_trade_history::projection::combo::{
8 HistoryOrderComboFacts, HistoryOrderComboLegFacts, ProjectedHistoryOrderComboLeg,
9};
10use futu_domain_trade_history::projection::orders::{
11 BackendOrderUnpackFacts, project_backend_order_unpacked_trd_market_like_cpp,
12};
13use futu_domain_trade_order::{OrderWireExtensionFacts, project_order_wire_extensions_like_cpp};
14
15use crate::proto_internal::{odr_sys_cmn, sim_odr_sys_cmn};
16
17pub fn order_proto_to_cached_like_cpp(trd_env: i32, o: &odr_sys_cmn::Order) -> Option<CachedOrder> {
18 order_proto_to_cached_with_jp_acc_type_like_cpp(trd_env, o, None)
19}
20
21pub fn order_proto_to_cached_with_jp_acc_type_like_cpp(
22 trd_env: i32,
23 o: &odr_sys_cmn::Order,
24 jp_acc_type: Option<i32>,
25) -> Option<CachedOrder> {
26 let trd_market = project_backend_order_unpacked_trd_market_like_cpp(BackendOrderUnpackFacts {
27 trd_env,
28 has_order_id: o.order_id.is_some(),
29 has_side: o.side.is_some(),
30 market: o.market,
31 has_symbol: o.symbol.is_some(),
32 has_create_time: o.create_time.is_some(),
33 has_expire_time: o.expire_time.is_some(),
34 has_status: o.status.is_some(),
35 })?;
36 let order_trade_time_type = o.sup.as_ref().and_then(|s| s.order_trade_time_type);
37 let combo = o
38 .multi_leg_info
39 .as_ref()
40 .map(|multi_leg| HistoryOrderComboFacts {
41 backend_strategy_type: multi_leg.strategy_type,
42 legs: multi_leg
43 .leg_infos
44 .iter()
45 .map(|leg| HistoryOrderComboLegFacts {
46 symbol: leg.leg_symbol.as_deref(),
47 exchange: leg.leg_exchange.as_deref(),
48 side: leg.leg_side,
49 ratio_qty: leg.leg_ratio_qty.as_deref(),
50 position_id: leg.position_id.as_deref(),
51 })
52 .collect(),
53 });
54 let sup = o.sup.as_ref();
55 let wire_extensions = project_order_wire_extensions_like_cpp(OrderWireExtensionFacts {
56 cash_order_qty: o.cash_order_qty.as_deref(),
57 has_condition: o.condition.is_some(),
58 portfolio_stock_id: o.portfolio_stock_id,
59 has_margin_trade_info: o.margin_trade_info.is_some(),
60 event_contract_quote_id: o
61 .order_extra
62 .as_ref()
63 .and_then(|extra| extra.quote_id.as_deref()),
64 });
65 let projected = project_backend_trade_read_order_like_cpp(BackendTradeReadOrderFacts {
66 trd_env,
67 sim_option_account: trd_env == 0 && matches!(o.market, Some(7 | 9)),
68 trd_market_ftapi: trd_market,
69 ex_destination: o.exdestination,
70 exchange: o.exchange.as_deref(),
71 order_type_trd_market_ftapi: trd_market,
72 currency: o.currency.map(|c| c as i32),
73 jp_acc_type,
74 app_lang: 0,
75 order_id_ex: o.order_id.as_deref(),
76 side: o.side,
77 order_type: o.r#type,
78 security_type: o.security_type,
79 status: o.status,
80 code: o.symbol.as_deref(),
81 stock_name: o.stock_name.as_deref(),
82 qty: o.qty.as_deref(),
83 price: o.price.as_deref(),
84 create_time_micros: o.create_time,
85 update_time_micros: o.update_time,
86 market_id: o.exchange_code,
87 cum_qty: o.cum_qty.as_deref(),
88 avg_fill_price: o.avg_fill_price.as_deref(),
89 last_err_msg: o.last_err_msg.as_deref(),
90 text: o.text.as_deref(),
91 aux_price: o.aux_price.as_deref(),
92 expire_time_micros: o.expire_time,
93 order_amount: o.order_amount.as_deref(),
94 sup: BackendOrderSupFacts {
95 order_trade_time_type,
96 time_in_force: sup.and_then(|value| value.time_in_force),
97 odr_enable_ba_trade: sup.and_then(|value| value.odr_enable_ba_trade),
98 hk_odr_enable_ba_trade: sup.and_then(|value| value.hk_odr_enable_ba_trade),
99 trail_type: sup.and_then(|value| value.trail_type),
100 trail_percent: sup.and_then(|value| value.trail_percent.as_deref()),
101 trail_price: sup.and_then(|value| value.trail_price.as_deref()),
102 },
103 combo,
104 });
105
106 Some(CachedOrder {
107 order_id: projected.order_id,
108 order_id_ex: projected.order_id_ex,
109 code: projected.code,
110 name: o.stock_name.as_ref().cloned().unwrap_or(projected.name),
113 trd_side: projected.trd_side,
114 order_type: projected.order_type,
115 order_status: projected.order_status,
116 qty: projected.qty,
117 price: projected.price.unwrap_or(0.0),
118 fill_qty: projected.fill_qty,
119 fill_avg_price: projected.fill_avg_price,
120 create_time: projected.create_time,
121 update_time: projected.update_time,
122 last_err_msg: projected.last_err_msg,
123 sec_market: projected.sec_market,
124 create_timestamp: projected.create_timestamp,
125 update_timestamp: projected.update_timestamp,
126 remark: projected.remark,
127 time_in_force: projected.time_in_force,
128 fill_outside_rth: projected.fill_outside_rth,
129 aux_price: projected.aux_price,
130 trail_type: projected.trail_type,
131 trail_value: projected.trail_value,
132 trail_spread: projected.trail_spread,
133 currency: projected.currency,
134 trd_market: projected.trd_market,
135 strategy_type: projected.strategy_type,
136 combo_legs: projected
137 .combo_legs
138 .into_iter()
139 .map(combo_leg_data_domain_to_api_like_cpp)
140 .collect(),
141 quote_id: wire_extensions
142 .event_contract_quote_id
143 .map(ToOwned::to_owned),
144 backend_order_id: o.order_id.clone().unwrap_or_default(),
145 order_version: o.version.unwrap_or(0) as i32,
146 exchange_code: o.exchange_code.unwrap_or(0) as i32,
147 exchange: o.exchange.clone().unwrap_or_default(),
148 security_type: o.security_type.unwrap_or(0) as i32,
149 session: projected.session,
150 order_trade_time_type,
151 sub_account_id: o.sub_account_id,
152 jp_acc_type: projected.jp_acc_type,
153 is_stub: false,
154 is_local_order: false,
155 stub_inserted_at_ms: 0,
156 is_pending_broker_confirm: false,
157 })
158}
159
160fn combo_leg_data_domain_to_api_like_cpp(
161 leg: ProjectedHistoryOrderComboLeg,
162) -> futu_proto::qot_common::ComboLeg {
163 futu_proto::qot_common::ComboLeg {
164 security: futu_proto::qot_common::Security {
165 market: leg.qot_market,
166 code: leg.code,
167 },
168 side: leg.side,
169 qty_ratio: leg.qty_ratio,
170 position_id: leg.position_id,
171 pred_side: None,
176 }
177}
178
179pub(crate) fn sim_order_proto_to_cached_like_cpp(
180 trd_env: i32,
181 o: &sim_odr_sys_cmn::Order,
182) -> Option<CachedOrder> {
183 let trd_market = project_backend_order_unpacked_trd_market_like_cpp(BackendOrderUnpackFacts {
184 trd_env,
185 has_order_id: o.order_id.is_some(),
186 has_side: o.side.is_some(),
187 market: o.market,
188 has_symbol: o.symbol.is_some(),
189 has_create_time: o.create_time.is_some(),
190 has_expire_time: o.expire_time.is_some(),
191 has_status: o.status.is_some(),
192 })?;
193
194 let order_trade_time_type = o.sup.as_ref().and_then(|s| s.order_trade_time_type);
195 let sup = o.sup.as_ref();
196 let projected = project_backend_trade_read_order_like_cpp(BackendTradeReadOrderFacts {
197 trd_env,
198 sim_option_account: trd_env == 0 && matches!(o.market, Some(7 | 9)),
199 trd_market_ftapi: trd_market,
200 ex_destination: o.exdestination,
201 exchange: o.exchange.as_deref(),
202 order_type_trd_market_ftapi: trd_market,
203 currency: o.currency.map(|c| c as i32),
204 jp_acc_type: o.sub_account.map(|v| v as i32),
205 app_lang: 0,
206 order_id_ex: o.order_id.as_deref(),
207 side: o.side,
208 order_type: o.r#type,
209 security_type: o.security_type,
210 status: o.status,
211 code: o.symbol.as_deref(),
212 stock_name: o.stock_name.as_deref(),
213 qty: o.qty.as_deref(),
214 price: o.price.as_deref(),
215 create_time_micros: o.create_time,
216 update_time_micros: o.update_time,
217 market_id: o.exchange_code,
218 cum_qty: o.cum_qty.as_deref(),
219 avg_fill_price: o.avg_fill_price.as_deref(),
220 last_err_msg: o.last_err_msg.as_deref(),
221 text: o.text.as_deref(),
222 aux_price: o.aux_price.as_deref(),
223 expire_time_micros: o.expire_time,
224 order_amount: o.order_amount.as_deref(),
225 sup: BackendOrderSupFacts {
226 order_trade_time_type,
227 time_in_force: sup.and_then(|value| value.time_in_force),
228 odr_enable_ba_trade: sup.and_then(|value| value.odr_enable_ba_trade),
229 hk_odr_enable_ba_trade: sup.and_then(|value| value.hk_odr_enable_ba_trade),
230 trail_type: sup.and_then(|value| value.trail_type),
231 trail_percent: sup.and_then(|value| value.trail_percent.as_deref()),
232 trail_price: sup.and_then(|value| value.trail_price.as_deref()),
233 },
234 combo: None,
235 });
236
237 Some(CachedOrder {
238 order_id: projected.order_id,
239 order_id_ex: projected.order_id_ex.clone(),
240 code: projected.code,
241 name: projected.name,
242 trd_side: projected.trd_side,
243 order_type: projected.order_type,
244 order_status: projected.order_status,
245 qty: projected.qty,
246 price: projected.price.unwrap_or(0.0),
247 fill_qty: projected.fill_qty,
248 fill_avg_price: projected.fill_avg_price,
249 create_time: projected.create_time,
250 update_time: projected.update_time,
251 last_err_msg: projected.last_err_msg,
252 sec_market: projected.sec_market,
253 create_timestamp: projected.create_timestamp,
254 update_timestamp: projected.update_timestamp,
255 remark: projected.remark,
256 time_in_force: projected.time_in_force,
257 fill_outside_rth: projected.fill_outside_rth,
258 aux_price: projected.aux_price,
259 trail_type: projected.trail_type,
260 trail_value: projected.trail_value,
261 trail_spread: projected.trail_spread,
262 currency: projected.currency,
263 trd_market: projected.trd_market,
264 strategy_type: None,
265 combo_legs: Vec::new(),
266 quote_id: None,
267 backend_order_id: projected.order_id_ex,
268 order_version: o.version.unwrap_or(0) as i32,
269 exchange_code: o.exchange_code.unwrap_or(0) as i32,
270 exchange: o.exchange.clone().unwrap_or_default(),
271 security_type: o.security_type.unwrap_or(0) as i32,
272 session: projected.session,
273 order_trade_time_type,
274 sub_account_id: None,
275 jp_acc_type: projected.jp_acc_type,
276 is_stub: false,
277 is_local_order: false,
278 stub_inserted_at_ms: 0,
279 is_pending_broker_confirm: false,
280 })
281}