futu_cache/trd_cache/types/confirm.rs
1/// v1.4.106 codex 0226 F1+F2: PlaceOrder 阶段 backend 返回 `OrderNewRsp.action`
2/// (CltAction.type == ORDER_CONFIRM=5) 时, 携带 `CltActionOrderConfirm` 二次
3/// 确认上下文 — 客户端需把这些字段透传给 backend `OrderConfirmReq` (cmd 4728).
4///
5/// 来源 (proto-internal/odr_sys_cmn.proto:883-893):
6/// ```text
7/// message CltActionOrderConfirm {
8/// optional string order_id = 1; // 订单 id (= backend 真实
9/// // szOrderID, alphanumeric)
10/// optional string title = 2; // 弹窗标题文案
11/// optional string content = 3; // 弹窗内容文案
12/// optional string confirm_button_title = 4;
13/// optional string cancel_button_title = 5;
14/// optional uint32 confirm_type = 6; // 必传给 OrderConfirmReq
15/// optional uint32 exchange_code = 7; // 期货上游交易所代码
16/// optional string exchange = 8; // 股票所属交易所
17/// }
18/// ```
19///
20/// daemon 在 PlaceOrder ack 路径里 capture 此 context, 然后在
21/// `Trd_ReconfirmOrder` 收到客户端确认请求时按 (acc_id, ftapi_order_id) 取出来
22/// 构造 backend `OrderConfirmReq`. 缺 context = backend 不需要二次确认 (e.g.
23/// HK 高买低卖未触发 / sim 路径) → ReconfirmOrder handler 早 reject loud.
24///
25/// **来源 cmd_id**: `CS_CMDID_TRADE_ORDER_CONFIRM_ORDER = 4728`
26/// (`moomoo/Moomoo/Include/FTTrade/TradeCmdDefine.h:132`).
27#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
28pub struct OrderConfirmContext {
29 /// backend 真实 szOrderID (alphanumeric); 写到 `OrderConfirmReq.order_id`.
30 pub backend_order_id: String,
31 /// `CltActionOrderConfirm.confirm_type` (来自 OrderConfirmType enum).
32 /// **必传** (backend 用此值校验客户端确实看到了对应弹窗).
33 pub confirm_type: u32,
34 /// `CltActionOrderConfirm.exchange_code` (期货必传).
35 pub exchange_code: u32,
36 /// `CltActionOrderConfirm.exchange` (股票必传).
37 pub exchange: String,
38 /// 弹窗 title (用于 daemon 日志, 客户端可参考).
39 pub title: String,
40 /// 弹窗 content (用于 daemon 日志, 客户端可参考).
41 pub content: String,
42 /// confirm_button / cancel_button title 透传 (UX, 不影响 backend).
43 pub confirm_button_title: String,
44 pub cancel_button_title: String,
45 /// 写入时间 (unix epoch ms), TTL 用. PlaceOrder 与 ReconfirmOrder 之间通常
46 /// <60s, 远超 60s 视为 stale → handler 拒绝.
47 pub inserted_at_ms: u64,
48}
49
50/// v1.4.106 codex 0226 F1+F2: pending OrderConfirm cache key.
51///
52/// `(acc_id, ftapi_order_id)` 而不是 `(acc_id, backend_order_id)`, 因为 FTAPI
53/// 客户端发 ReconfirmOrder 用的是 PlaceOrder 返的 `s2c.order_id` (FTAPI u64,
54/// 由 `hash_backend_id_to_u64` 派生). FTAPI 客户端**不**直接看到 backend
55/// alphanumeric szOrderID; daemon 必须按 FTAPI order_id 反查 context.
56#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
57pub struct OrderConfirmKey {
58 pub acc_id: u64,
59 /// FTAPI order_id (= `hash_backend_id_to_u64(backend.order_id)`).
60 pub ftapi_order_id: u64,
61}
62
63impl OrderConfirmKey {
64 pub fn new(acc_id: u64, ftapi_order_id: u64) -> Self {
65 Self {
66 acc_id,
67 ftapi_order_id,
68 }
69 }
70}
71
72/// C++ `m_mapReqIDOrderID` key, scoped by account to avoid cross-account
73/// collisions in the shared Rust trade cache.
74#[derive(Debug, Clone, PartialEq, Eq, Hash)]
75pub struct OrderOpReqKey {
76 pub acc_id: u64,
77 pub req_id: String,
78}
79
80impl OrderOpReqKey {
81 pub fn new(acc_id: u64, req_id: String) -> Self {
82 Self { acc_id, req_id }
83 }
84}
85
86/// C++ `FindOrderIDByReqID` clears the helper map once it reaches 512 entries.
87pub const ORDER_OP_REQ_ORDER_MAP_CLEAR_LIMIT: usize = 512;
88
89/// v1.4.106 codex 0226 F1+F2: pending order confirm context TTL (ms).
90///
91/// PlaceOrder → ReconfirmOrder 通常 <60s (用户看到弹窗后立即点确认). 超过 60s
92/// 视为弹窗已被忽略 / 用户 abandon → daemon 不允许 reconfirm (backend 也会拒绝
93/// 因为 confirm_type 已过期). 当前选 5min (300_000 ms) 作宽松 TTL — 给真机用户
94/// 更多缓冲, 同时防内存泄漏.
95pub const ORDER_CONFIRM_CONTEXT_TTL_MS: u64 = 300_000;