futu_mcp/handlers/trade/
helpers.rs1use anyhow::{Result, bail};
5use futu_core::{trade_market, trade_parsing};
6use futu_trd::types::{TrdEnv, TrdHeader, TrdMarket};
7
8use crate::trd_sdk_adapter;
9
10pub fn parse_trd_market(s: &str) -> Result<TrdMarket> {
11 let market = trade_market::parse_trd_market_id(s).ok_or_else(|| {
12 anyhow::anyhow!(
13 "unknown trd market {:?} ({})",
14 s.trim().to_ascii_uppercase(),
15 trade_market::TRD_MARKET_PARSE_CHOICES
16 )
17 })?;
18 trd_sdk_adapter::trd_market_from_id(market).ok_or_else(|| {
19 anyhow::anyhow!("unknown trd market id {market} after core parser accepted it")
20 })
21}
22
23pub fn parse_trd_env(s: &str) -> Result<TrdEnv> {
24 let env = trade_parsing::parse_trd_env_id(s).ok_or_else(|| {
25 anyhow::anyhow!(
26 "unknown trd env {:?} ({})",
27 s.trim().to_ascii_lowercase(),
28 trade_parsing::TRD_ENV_PARSE_CHOICES
29 )
30 })?;
31 trd_sdk_adapter::trd_env_from_id(env)
32 .ok_or_else(|| anyhow::anyhow!("unknown trd env id {env} after core parser accepted it"))
33}
34
35pub fn parse_trd_env_int(s: &str) -> Result<i32> {
40 Ok(parse_trd_env(s)? as i32)
41}
42
43pub fn parse_trd_market_strict_no_fund(s: &str) -> Result<TrdMarket> {
48 let m = parse_trd_market(s)?;
49 if let Some(label) = trade_market::canonical_fund_trd_market_label(m as i32) {
50 bail!(
51 "trd market {label} 仅 view-only read endpoints \
52 (positions/funds/cash-log/history-orders/history-fills) 真机 verified; \
53 active/calculation path (orders/deals/max_trd_qtys/margin_ratio/order_fee) \
54 用主市场. v1.4.102 audit 33 F5 / 34 F4 / 35 F4 fix."
55 );
56 }
57 Ok(m)
58}
59
60pub fn build_header_strict_no_fund(env: &str, acc_id: u64, market: &str) -> Result<TrdHeader> {
64 build_header_strict_no_fund_with_jp_acc_type(env, acc_id, market, None)
65}
66
67pub fn build_header_strict_no_fund_with_jp_acc_type(
68 env: &str,
69 acc_id: u64,
70 market: &str,
71 jp_acc_type: Option<i32>,
72) -> Result<TrdHeader> {
73 Ok(TrdHeader {
74 trd_env: parse_trd_env(env)?,
75 acc_id,
76 trd_market: parse_trd_market_strict_no_fund(market)?,
77 jp_acc_type,
78 })
79}
80
81pub fn build_header(env: &str, acc_id: u64, market: &str) -> Result<TrdHeader> {
82 Ok(TrdHeader {
83 trd_env: parse_trd_env(env)?,
84 acc_id,
85 trd_market: parse_trd_market(market)?,
86 jp_acc_type: None,
87 })
88}