futu_mcp/handlers/trade/
helpers.rs1use anyhow::{Result, bail};
5use futu_trd::types::{TrdEnv, TrdHeader, TrdMarket};
6
7pub fn parse_trd_market(s: &str) -> Result<TrdMarket> {
8 let trimmed = s.trim();
15 let upper = trimmed.to_ascii_uppercase();
16 let m = match upper.as_str() {
17 "HK" | "1" => TrdMarket::HK,
18 "US" | "2" => TrdMarket::US,
19 "CN" | "3" => TrdMarket::CN,
20 "HKCC" | "4" => TrdMarket::HKCC,
21 "FUTURES" | "5" => TrdMarket::Futures,
22 "SG" | "6" => TrdMarket::SG,
23 "CRYPTO" | "7" => TrdMarket::Crypto,
24 "AU" | "8" => TrdMarket::AU,
25 "FUTURES_SIMULATE_HK" | "FUTURESSIMULATEHK" | "10" => TrdMarket::FuturesSimulateHK,
26 "FUTURES_SIMULATE_US" | "FUTURESSIMULATEUS" | "11" => TrdMarket::FuturesSimulateUS,
27 "FUTURES_SIMULATE_SG" | "FUTURESSIMULATESG" | "12" => TrdMarket::FuturesSimulateSG,
28 "FUTURES_SIMULATE_JP" | "FUTURESSIMULATEJP" | "13" => TrdMarket::FuturesSimulateJP,
29 "JP" | "15" => TrdMarket::JP,
30 "MY" | "111" => TrdMarket::MY,
31 "CA" | "112" => TrdMarket::CA,
32 "HKFUND" | "HK_FUND" | "113" => TrdMarket::HKFund,
33 "USFUND" | "US_FUND" | "123" => TrdMarket::USFund,
34 "SGFUND" | "SG_FUND" | "124" => TrdMarket::SGFund,
35 "MYFUND" | "MY_FUND" | "125" => TrdMarket::MYFund,
36 "JPFUND" | "JP_FUND" | "126" => TrdMarket::JPFund,
37 other => bail!(
38 "unknown trd market {other:?} \
39 (HK|US|CN|HKCC|FUTURES|SG|CRYPTO|AU|FUTURES_SIMULATE_HK|\
40 FUTURES_SIMULATE_US|FUTURES_SIMULATE_SG|FUTURES_SIMULATE_JP|JP|MY|CA|\
41 HKFUND|USFUND|SGFUND|MYFUND|JPFUND or official TrdMarket int)"
42 ),
43 };
44 Ok(m)
45}
46
47pub fn parse_trd_env(s: &str) -> Result<TrdEnv> {
48 let e = match s.trim().to_ascii_lowercase().as_str() {
49 "simulate" | "sim" => TrdEnv::Simulate,
50 "real" => TrdEnv::Real,
51 other => bail!("unknown trd env {other:?} (real|simulate)"),
52 };
53 Ok(e)
54}
55
56pub fn parse_trd_env_int(s: &str) -> Result<i32> {
61 Ok(parse_trd_env(s)? as i32)
62}
63
64pub fn parse_trd_market_strict_no_fund(s: &str) -> Result<TrdMarket> {
69 let m = parse_trd_market(s)?;
70 if let Some(label) = futu_trd::market::view_only_fund_market_label(m as i32) {
71 bail!(
72 "trd market {label} 仅 view-only read endpoints \
73 (positions/funds/cash-log/history-orders/history-fills) 真机 verified; \
74 active/calculation path (orders/deals/max_trd_qtys/margin_ratio/order_fee) \
75 用主市场. v1.4.102 audit 33 F5 / 34 F4 / 35 F4 fix."
76 );
77 }
78 Ok(m)
79}
80
81pub fn build_header_strict_no_fund(env: &str, acc_id: u64, market: &str) -> Result<TrdHeader> {
85 build_header_strict_no_fund_with_jp_acc_type(env, acc_id, market, None)
86}
87
88pub fn build_header_strict_no_fund_with_jp_acc_type(
89 env: &str,
90 acc_id: u64,
91 market: &str,
92 jp_acc_type: Option<i32>,
93) -> Result<TrdHeader> {
94 Ok(TrdHeader {
95 trd_env: parse_trd_env(env)?,
96 acc_id,
97 trd_market: parse_trd_market_strict_no_fund(market)?,
98 jp_acc_type,
99 })
100}
101
102pub fn build_header(env: &str, acc_id: u64, market: &str) -> Result<TrdHeader> {
103 Ok(TrdHeader {
104 trd_env: parse_trd_env(env)?,
105 acc_id,
106 trd_market: parse_trd_market(market)?,
107 jp_acc_type: None,
108 })
109}