Skip to main content

futu_backend/trade_query/orders/
status_helpers.rs

1//! trade_query/orders/status_helpers — backend response_status_like_cpp + backend_order_status/type/market_to_ftapi + init_trade_data
2//! (v1.4.110 CC Batch J: 拆自 orders.rs L781-888 + 1073-1213)
3
4use std::sync::Arc;
5
6use futu_cache::{qot_right::QotRightCache, trd_cache::TrdCache};
7pub use futu_domain_trade_history::projection::orders::is_valid_real_trd_market_like_cpp;
8#[cfg(test)]
9pub use futu_domain_trade_history::projection::scalars::backend_order_type_to_ftapi_like_cpp as backend_order_type_to_ftapi;
10pub use futu_domain_trade_history::projection::scalars::{
11    backend_order_status_to_ftapi_like_cpp as backend_order_status_to_ftapi,
12    backend_real_market_to_trd_market_like_cpp,
13};
14use futu_domain_trade_history::status::{
15    BackendTradeMsgHeaderFacts, BackendTradeResponseStatusInput,
16    backend_order_fill_info_status_like_cpp as domain_backend_order_fill_info_status_like_cpp,
17    backend_order_fill_list_status_like_cpp as domain_backend_order_fill_list_status_like_cpp,
18    backend_order_info_status_by_account_like_cpp as domain_backend_order_info_status_by_account_like_cpp,
19    backend_order_info_status_like_cpp as domain_backend_order_info_status_like_cpp,
20    backend_order_list_status_like_cpp as domain_backend_order_list_status_like_cpp,
21};
22
23use super::super::*;
24use crate::conn::BackendConn;
25use crate::proto_internal::odr_sys_cmn;
26
27use super::types::BackendResponseStatusError;
28
29/// Match C++ order-list response gating for backend refresh helpers.
30///
31/// Ref:
32/// - `FutuOpenD/Src/NNProtoCenter/Trade/Order/NNProto_Trd_OrderReal.cpp:245-288`
33/// - `FutuOpenD/Src/NNProtoCenter/Trade/Order/NNProto_Trd_OrderSimulate.cpp:239-282`
34#[cfg(test)]
35pub fn backend_order_list_status_like_cpp(
36    result: Option<i32>,
37    msg_header: Option<&odr_sys_cmn::MsgHeader>,
38    err_msg: Option<&str>,
39    acc_id: u64,
40) -> std::result::Result<(), BackendResponseStatusError> {
41    backend_order_list_status_by_account_like_cpp(
42        result,
43        msg_header.and_then(|header| header.account_id),
44        err_msg,
45        acc_id,
46    )
47}
48
49pub(super) fn backend_order_list_status_by_account_like_cpp(
50    result: Option<i32>,
51    backend_acc_id: Option<u64>,
52    err_msg: Option<&str>,
53    acc_id: u64,
54) -> std::result::Result<(), BackendResponseStatusError> {
55    domain_backend_order_list_status_like_cpp(BackendTradeResponseStatusInput {
56        message_name: "OrderListRsp",
57        result,
58        msg_header: backend_acc_id.map(|account_id| BackendTradeMsgHeaderFacts {
59            account_id: Some(account_id),
60        }),
61        err_msg,
62        acc_id,
63    })
64}
65
66/// Match C++ single-order-info response gating.
67///
68/// Ref:
69/// - `FutuOpenD/Src/NNProtoCenter/Trade/Order/NNProto_Trd_OrderReal.cpp:368-418`
70/// - `FutuOpenD/Src/NNProtoCenter/Trade/Order/NNProto_Trd_OrderSimulate.cpp:362-412`
71pub fn backend_order_info_status_like_cpp(
72    result: Option<i32>,
73    msg_header: Option<&odr_sys_cmn::MsgHeader>,
74    err_msg: Option<&str>,
75    acc_id: u64,
76    expected_count: usize,
77    actual_count: usize,
78) -> std::result::Result<(), BackendResponseStatusError> {
79    domain_backend_order_info_status_like_cpp(
80        BackendTradeResponseStatusInput {
81            message_name: "OrderDetailRsp",
82            result,
83            msg_header: msg_header.map(backend_trade_msg_header_facts),
84            err_msg,
85            acc_id,
86        },
87        expected_count,
88        actual_count,
89    )
90}
91
92pub(super) fn backend_order_info_status_by_account_like_cpp(
93    result: Option<i32>,
94    backend_acc_id: Option<u64>,
95    err_msg: Option<&str>,
96    acc_id: u64,
97    expected_count: usize,
98    actual_count: usize,
99) -> std::result::Result<(), BackendResponseStatusError> {
100    domain_backend_order_info_status_by_account_like_cpp(
101        result,
102        backend_acc_id,
103        err_msg,
104        acc_id,
105        expected_count,
106        actual_count,
107    )
108}
109
110/// Match C++ current-deal response gating for backend refresh helpers.
111///
112/// Ref:
113/// - `FutuOpenD/Src/NNProtoCenter/Trade/Deal/NNProto_Trd_DealReal.cpp:259-305`
114/// - `FutuOpenD/Src/NNProtoCenter/Trade/_NNProto_Trd_Comm.h:20-30`
115pub fn backend_order_fill_list_status_like_cpp(
116    result: Option<i32>,
117    msg_header: Option<&odr_sys_cmn::MsgHeader>,
118    err_msg: Option<&str>,
119    acc_id: u64,
120) -> std::result::Result<(), BackendResponseStatusError> {
121    domain_backend_order_fill_list_status_like_cpp(BackendTradeResponseStatusInput {
122        message_name: "OrderFillListRsp",
123        result,
124        msg_header: msg_header.map(backend_trade_msg_header_facts),
125        err_msg,
126        acc_id,
127    })
128}
129
130/// Match C++ single-deal-info response gating.
131///
132/// Ref: `FutuOpenD/Src/NNProtoCenter/Trade/Deal/NNProto_Trd_DealReal.cpp:382-431`.
133pub fn backend_order_fill_info_status_like_cpp(
134    result: Option<i32>,
135    msg_header: Option<&odr_sys_cmn::MsgHeader>,
136    err_msg: Option<&str>,
137    acc_id: u64,
138    expected_count: usize,
139    actual_count: usize,
140) -> std::result::Result<(), BackendResponseStatusError> {
141    domain_backend_order_fill_info_status_like_cpp(
142        BackendTradeResponseStatusInput {
143            message_name: "OrderFillInfoRsp",
144            result,
145            msg_header: msg_header.map(backend_trade_msg_header_facts),
146            err_msg,
147            acc_id,
148        },
149        expected_count,
150        actual_count,
151    )
152}
153
154fn backend_trade_msg_header_facts(header: &odr_sys_cmn::MsgHeader) -> BackendTradeMsgHeaderFacts {
155    BackendTradeMsgHeaderFacts {
156        account_id: header.account_id,
157    }
158}
159
160/// 为所有真实账户查询资金和持仓 (CMD 3020)
161pub async fn init_trade_data(
162    backend: &Arc<BackendConn>,
163    trd_cache: &Arc<TrdCache>,
164    qot_right_cache: &Arc<QotRightCache>,
165) {
166    let accounts = trd_cache.get_accounts();
167    let real_accounts: Vec<u64> = accounts
168        .iter()
169        .filter(|a| a.trd_env == 1) // 只查真实账户
170        .map(|a| a.acc_id)
171        .collect();
172
173    tracing::info!(
174        count = real_accounts.len(),
175        "querying trade data for real accounts"
176    );
177
178    for &acc_id in &real_accounts {
179        // v1.4.106 codex 1556 F1+F3 + v1.4.107 fanout:
180        // bootstrap query 不知 user-requested currency / asset_category, 全传
181        // None 走 backend helper 的 C++ category expansion (JP margin=Foreign,
182        // JP derivative=Domestic+Foreign, other=None).
183        let quote_level = super::super::account_info::Cmd3020QuoteLevel::from_has_us_utp(
184            qot_right_cache.get().has_us_utp,
185        );
186        if let Err(e) =
187            query_account_info(backend, acc_id, trd_cache, None, None, quote_level).await
188        {
189            tracing::warn!(
190                error = %e,
191                "init trade data account info query failed"
192            );
193        }
194    }
195
196    tracing::info!("trade data initialization complete");
197}