futu_trd/market.rs
1//! Shared trade market projection helpers.
2//!
3//! These are pure helpers used by gateway response projection and CLI/domain
4//! adapters. Keep them here instead of in one surface handler so market prefix
5//! and futures-ticker fallback rules have a single callable source.
6
7use crate::types::TrdMarket;
8use futu_core::market::TrdSecMarketId;
9pub use futu_core::trade_market::{
10 CachedAccountMarket, RawAccountMarket, TRD_MARKET_INT_VALUES, TRD_MARKET_NON_FUND_INT_VALUES,
11 TRD_MARKET_NON_FUND_PARSE_CHOICES, TRD_MARKET_NON_FUND_STRING_VALUES, TRD_MARKET_PARSE_CHOICES,
12 TRD_MARKET_STRING_VALUES,
13};
14
15/// Parse a user-facing trade market string into the canonical OpenAPI
16/// `Trd_Common.TrdMarket` enum.
17///
18/// Keep the alias table in `futu-core`; this function is the compatibility
19/// facade that converts the core-owned official integer into `futu-trd`'s enum.
20/// The parser intentionally accepts both labels and official enum integers.
21#[must_use]
22pub fn parse_trd_market(raw: &str) -> Option<TrdMarket> {
23 futu_core::trade_market::parse_trd_market_id(raw).and_then(trd_market_from_i32)
24}
25
26/// Convert official OpenAPI `Trd_Common.TrdMarket` integer values into the
27/// canonical project enum.
28#[must_use]
29pub fn trd_market_from_i32(value: i32) -> Option<TrdMarket> {
30 TrdMarket::try_from(value).ok()
31}
32
33/// Label for canonical OpenAPI fund markets only.
34///
35/// Do not use `view_only_fund_market_label` for parsed enum values: that helper
36/// also covers backend raw cache IDs, where raw HKFund=13 overlaps canonical
37/// `TrdMarket::FuturesSimulateJP`.
38#[must_use]
39pub fn canonical_fund_trd_market_label(market: TrdMarket) -> Option<&'static str> {
40 futu_core::trade_market::canonical_fund_trd_market_label(market as i32)
41}
42
43/// Parse a trade market for active write/calculation paths.
44#[must_use]
45pub fn parse_non_fund_trd_market(raw: &str) -> Option<TrdMarket> {
46 futu_core::trade_market::parse_non_fund_trd_market_id(raw).and_then(trd_market_from_i32)
47}
48
49/// Strip a known FTAPI market prefix from a user/security code.
50///
51/// Unknown dotted symbols such as `BRK.B` are preserved.
52pub fn strip_market_prefix(code: &str) -> String {
53 futu_core::trade_security::strip_market_prefix(code)
54}
55
56/// Derive FTAPI `TrdSecMarket` from explicit value, account market, and code.
57///
58/// Prefix and futures ticker fallback intentionally win over SDK supplied
59/// market, matching the established v1.4.56 behavior for futures symbols where
60/// client SDK market metadata can be stale or too generic.
61pub fn derive_trd_sec_market(ftapi_sec_market: i32, trd_market: i32, code: &str) -> TrdSecMarketId {
62 TrdSecMarketId::new(futu_core::trade_security::derive_trd_sec_market_like_cpp(
63 futu_core::trade_security::TrdSecMarketInput {
64 ftapi_sec_market,
65 trd_market,
66 code,
67 },
68 ))
69}
70
71/// Derive FTAPI `TrdSecMarket` from explicit value, account market, and code.
72///
73/// Legacy raw-value facade. New code should prefer [`derive_trd_sec_market`] at
74/// the boundary, then unwrap to `i32` only when writing the FTAPI/backend wire.
75pub fn derive_sec_market(ftapi_sec_market: i32, trd_market: i32, code: &str) -> i32 {
76 derive_trd_sec_market(ftapi_sec_market, trd_market, code).raw_i32()
77}
78
79/// Derive `TrdSecMarket` from an explicit code prefix such as `HK.` / `US.`.
80pub fn sec_market_from_code_prefix(code: &str) -> Option<i32> {
81 sec_market_from_code_prefix_typed(code).map(TrdSecMarketId::raw_i32)
82}
83
84/// Typed variant of [`sec_market_from_code_prefix`].
85pub fn sec_market_from_code_prefix_typed(code: &str) -> Option<TrdSecMarketId> {
86 futu_core::trade_security::sec_market_from_code_prefix_like_cpp(code).map(TrdSecMarketId::new)
87}
88
89/// Canonical `Trd_Common.TrdMarket` label used by user-facing filters and
90/// surface adapters.
91///
92/// Keep this table in the trade domain so CLI / MCP / REST do not drift on
93/// newer view-only markets such as HKFUND / USFUND.
94#[must_use]
95pub fn trd_market_label(i: i32) -> Option<&'static str> {
96 futu_core::trade_market::trd_market_label(i)
97}
98
99/// Label for fund markets that are view-only on active write/calculation paths.
100///
101/// This intentionally covers two namespaces:
102/// - backend raw `Account.market` values cached in `CachedTrdAcc.trd_market`;
103/// - canonical OpenAPI `Trd_Common.TrdMarket` fund values.
104///
105/// `None` means the market is not a fund/view-only market. Do not use this as a
106/// generic display label; use `trd_market_label` for ordinary surface labels.
107#[must_use]
108pub fn view_only_fund_market_label(trd_market: i32) -> Option<&'static str> {
109 futu_core::trade_market::view_only_fund_market_label(trd_market)
110}
111
112/// Return whether the code looks like a futures symbol.
113///
114/// This is a cache-miss pattern fallback; cache-backed security type remains
115/// the more authoritative source when available.
116pub fn is_futures_code(code: &str) -> bool {
117 futu_core::trade_security::is_futures_code(code)
118}
119
120/// Derive `TrdSecMarket` from known futures ticker prefixes.
121pub fn futures_ticker_to_trd_sec_market(code: &str) -> Option<TrdSecMarketId> {
122 futu_core::trade_security::futures_ticker_to_sec_market_like_cpp(code).map(TrdSecMarketId::new)
123}
124
125/// Legacy raw-value facade for futures ticker fallback.
126pub fn futures_ticker_to_sec_market(code: &str) -> Option<i32> {
127 futures_ticker_to_trd_sec_market(code).map(TrdSecMarketId::raw_i32)
128}
129
130/// Extract the ticker prefix from a futures code.
131pub fn extract_futures_ticker_prefix(code: &str) -> String {
132 futu_core::trade_security::extract_futures_ticker_prefix_like_cpp(code)
133}
134
135#[cfg(test)]
136mod tests;