futu_backend/stock_list.rs
1// 股票列表同步
2//
3// 对应 C++ SecListDBUpdater
4// CMD 6746: 增量拉取股票列表 (响应 zlib 压缩)
5// CMD 6822: 注册市场事件推送 (需要 header reserved 设置市场类型)
6// CMD 6823: 拉取市场状态
7
8#[cfg(test)]
9use crate::proto_internal::stock_list_sync_svr;
10
11mod event_notice;
12mod event_notice_push;
13mod market;
14mod parse;
15mod sync;
16
17pub use event_notice::{
18 MarketStatus, market_status_snapshot_updates, pick_market_state, pull_all_market_status,
19 pull_market_status, pull_single_market_status, register_markets,
20};
21#[cfg(test)]
22pub(crate) use event_notice::{decode_market_status_rsp, pull_market_status_for, register_market};
23pub use event_notice_push::{MarketEventPushBatch, decode_event_notice_push};
24pub use market::{
25 QuoteMktType, make_quote_reserved, market_id_matches, qot_market_to_backend,
26 quote_market_from_market_id, quote_market_type_from_market_id, trd_market_to_backend,
27};
28#[cfg(test)]
29use market::{market_state_priority, quote_mkt_to_nn_mkt_type};
30#[cfg(test)]
31use parse::parse_stock_item;
32pub use sync::{StockListPage, fetch_stock_list_page};
33
34/// 股票列表同步命令 ID
35pub use futu_command_spec::CMD_QOT_UPDATE_SEC_LIST as CMD_UPDATE_SEC_LIST;
36/// 缓存的证券信息 (从 CSStockItem 解析)
37#[derive(Debug, Clone)]
38pub struct StockInfo {
39 pub stock_id: u64,
40 pub sequence: u64,
41 pub code: String,
42 pub name_sc: String,
43 pub name_tc: String,
44 pub name_en: String,
45 /// C++ `Ndt_Qot_SecInfo::szNameJp`, from stock_list_sync `CSStockItem.ja_name` field 65.
46 pub name_jp: String,
47 pub market_code: u32,
48 pub instrument_type: u32,
49 /// C++ `Ndt_Qot_SecInfo::nSpreadCode` data source.
50 ///
51 /// Source: stock_list_sync `CSStockItem.spread_table_code` field 13.
52 pub spread_table_code: u32,
53 pub sub_instrument_type: u32,
54 /// C++ `Ndt_Qot_SecInfo::enSubTypeV2` data source.
55 ///
56 /// Source: stock_list_sync `CSStockItem.sub_instrument_type_v2` field 69.
57 /// v10.6 `GetCompanyProfile` uses this to split Trust/ETF routing exactly like
58 /// C++ `APIServer_Qot_CompanyProfile.cpp:55-63`.
59 pub sub_instrument_type_v2: u32,
60 pub lot_size: u32,
61 pub currency_code: u32,
62 pub listing_date: u32,
63 pub delisting: bool,
64 pub delete_flag: bool,
65 /// 窝轮所属正股 ID (warrnt_stock_owner), 0 表示无
66 pub warrnt_stock_owner: u64,
67 /// C++ internal `NN_QotWarrantType` from stock-list `warrnt_type`.
68 ///
69 /// Values 1-5 match public `Qot_Common.WarrantType`; values 6/7 are C++
70 /// internal DLC Long/Short and are filtered out by `GetReference(WARRANT)`.
71 pub warrant_type: u32,
72 /// 不可搜索标记 (no_search), true 表示不可搜索
73 pub no_search: bool,
74 /// v1.4.106 codex F5: 期货主连合约关联 stock_id (proto field 41 origin_id).
75 ///
76 /// 含义 (对齐 C++ `Ndt_Qot_SecInfo::nFutureOriginID`): 当前 row 是**主连合约**
77 /// (e.g. `HSImain`, `NQmain`) 时, `origin_id` 指向真实月份合约的 stock_id;
78 /// 普通合约 (`HSI2604` / `NQ2606`) 此字段为 0.
79 ///
80 /// **F5 用途**: PlaceOrder 在 `IsFuturesTrdMarket && origin_id != 0` 时
81 /// 异步发 CMD 6747 拉真实合约 code, 用真实 code 下单 (对齐 C++
82 /// `APIServer_Trd_PlaceOrder.cpp:632-650` `ReqMainLinkContract` 流程).
83 pub future_origin_id: u64,
84 /// v1.4.106 codex F5: 期货主力合约 stock_id (proto field 40 zhuli_id).
85 ///
86 /// 含义: 主连合约持有此字段, 指向当前**主力合约** stock_id (流动性最大).
87 /// CMD 6747 响应解析此字段后用 `id_to_key` 反查 code → 替换 PlaceOrder
88 /// `c2s.code` 后下发. 普通合约此字段为 0.
89 pub zhuli_id: u64,
90 /// Crypto 货币对左侧货币 (C++ `CSStockItem.cc_origin`, proto field 60).
91 pub cc_origin: String,
92 /// Crypto 货币对右侧货币 (C++ `CSStockItem.cc_destination`, proto field 61).
93 pub cc_destination: String,
94 /// v1.4.110 final E.5 P2#6: 交易所 (proto field 57, e.g. "SEHK", "NASDAQ").
95 ///
96 /// 数据驱动 fallback (pitfall #35 C++ 数据驱动 vs Rust 启发式): trade
97 /// handler 的 `derive_exchange_str` 应优先用此字段, 缺失时再 fallback 到
98 /// pattern match heuristic. backend 不下发此字段时为空串.
99 pub exchange: String,
100 /// v1.4.110 final E.5 P2#6: 上市交易所 (proto field 74).
101 ///
102 /// 通常与 `exchange` 相同, dual-listed ADR / 双重主要上市等场景下不同
103 /// (e.g. 港股通的 H 股可能 exchange=HKEX, listed_exchange=SEHK).
104 pub listed_exchange: String,
105}
106
107#[cfg(test)]
108mod tests;