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 futu_trd::market::parse_trd_market(s).ok_or_else(|| {
9 anyhow::anyhow!(
10 "unknown trd market {:?} ({})",
11 s.trim().to_ascii_uppercase(),
12 futu_trd::market::TRD_MARKET_PARSE_CHOICES
13 )
14 })
15}
16
17pub fn parse_trd_env(s: &str) -> Result<TrdEnv> {
18 futu_trd::parsing::parse_trd_env(s).ok_or_else(|| {
19 anyhow::anyhow!(
20 "unknown trd env {:?} ({})",
21 s.trim().to_ascii_lowercase(),
22 futu_trd::parsing::TRD_ENV_PARSE_CHOICES
23 )
24 })
25}
26
27pub fn parse_trd_env_int(s: &str) -> Result<i32> {
32 Ok(parse_trd_env(s)? as i32)
33}
34
35pub fn parse_trd_market_strict_no_fund(s: &str) -> Result<TrdMarket> {
40 let m = parse_trd_market(s)?;
41 if let Some(label) = futu_trd::market::canonical_fund_trd_market_label(m) {
42 bail!(
43 "trd market {label} 仅 view-only read endpoints \
44 (positions/funds/cash-log/history-orders/history-fills) 真机 verified; \
45 active/calculation path (orders/deals/max_trd_qtys/margin_ratio/order_fee) \
46 用主市场. v1.4.102 audit 33 F5 / 34 F4 / 35 F4 fix."
47 );
48 }
49 Ok(m)
50}
51
52pub fn build_header_strict_no_fund(env: &str, acc_id: u64, market: &str) -> Result<TrdHeader> {
56 build_header_strict_no_fund_with_jp_acc_type(env, acc_id, market, None)
57}
58
59pub fn build_header_strict_no_fund_with_jp_acc_type(
60 env: &str,
61 acc_id: u64,
62 market: &str,
63 jp_acc_type: Option<i32>,
64) -> Result<TrdHeader> {
65 Ok(TrdHeader {
66 trd_env: parse_trd_env(env)?,
67 acc_id,
68 trd_market: parse_trd_market_strict_no_fund(market)?,
69 jp_acc_type,
70 })
71}
72
73pub fn build_header(env: &str, acc_id: u64, market: &str) -> Result<TrdHeader> {
74 Ok(TrdHeader {
75 trd_env: parse_trd_env(env)?,
76 acc_id,
77 trd_market: parse_trd_market(market)?,
78 jp_acc_type: None,
79 })
80}