Skip to main content

futu_mcp/tool_args/
qot.rs

1//! v1.4.110 P1-1: 拆自 `tool_args.rs` 按 handler 域分组.
2
3use rmcp::schemars;
4use serde::Deserialize;
5
6use crate::tool_enums;
7
8use super::*;
9
10mod basic;
11mod f10;
12mod misc;
13mod price_reminder;
14mod reference;
15mod screen_unusual;
16mod shareholders;
17
18pub use basic::{
19    KLineReq, MarketStateReq, OptionExerciseProbabilityReq, OptionVolatilityReq, OrderBookReq,
20    PlateListReq, PlateStocksReq, ShortInfoReq, SymbolListReq, SymbolReq, TickerReq,
21    TopTenBuySellBrokersReq,
22};
23pub use f10::{
24    CompanyExecutiveBackgroundReq, CompanyOperationalEfficiencyReq,
25    FinancialsEarningsPriceHistoryReq, FinancialsEarningsPriceMoveReq,
26    FinancialsRevenueBreakdownReq, FinancialsStatementsReq, ResearchAnalystConsensusReq,
27    ResearchMorningstarReportReq, ResearchRatingSummaryReq, ValuationDetailReq,
28    ValuationPlateStockListReq,
29};
30pub use misc::{
31    BizGroupReq, BondSymbolReq, CodeChangeReq, HistoryKlQuotaReq, HoldingChangeReq,
32    ModifyUserSecurityReq, QuoteRightsReq, StockFilterReq, SuspendReq, TickerStatisticDetailReq,
33    TickerStatisticReq, TradingDaysReq, UserSecurityGroupReq, UserSecurityReq,
34};
35pub use price_reminder::{GetPriceReminderReq, OptionExpirationDateReq, SetPriceReminderReq};
36pub use reference::{
37    FutureInfoReq, HistoryKLineReq, IpoListReq, OptionChainReq, ReferenceReq, WarrantReq,
38};
39pub use screen_unusual::{
40    DerivativeUnusualReq, FinancialUnusualReq, OptionScreenReq, StockScreenReq,
41    TechnicalUnusualReq, WarrantScreenReq,
42};
43pub use shareholders::{
44    InsiderHolderListReq, InsiderTradeListReq, ShareholdersHolderDetailReq,
45    ShareholdersHoldingChangesReq, ShareholdersInstitutionalReq, ShareholdersOverviewReq,
46};
47
48fn validate_optional_i32_range(
49    tool: &str,
50    field: &str,
51    value: Option<i32>,
52    min: i32,
53    max: i32,
54) -> Result<(), String> {
55    if let Some(value) = value
56        && !(min..=max).contains(&value)
57    {
58        return Err(format!(
59            "{field} must be in {min}..={max} for {tool}, got {value}"
60        ));
61    }
62    Ok(())
63}
64
65fn validate_optional_f64_min_max(
66    tool: &str,
67    field: &str,
68    min: Option<f64>,
69    max: Option<f64>,
70) -> Result<(), String> {
71    if let (Some(min), Some(max)) = (min, max)
72        && min > max
73    {
74        return Err(format!("{field}_min must be <= {field}_max for {tool}"));
75    }
76    Ok(())
77}
78
79fn deser_hk_hkfuture_us_cn_market_as_i32<'de, D>(deserializer: D) -> Result<i32, D::Error>
80where
81    D: serde::Deserializer<'de>,
82{
83    #[derive(Deserialize)]
84    #[serde(untagged)]
85    enum IntOrStr {
86        Int(i32),
87        Str(String),
88    }
89
90    match IntOrStr::deserialize(deserializer)? {
91        IntOrStr::Int(value) => Ok(value),
92        IntOrStr::Str(value) => {
93            let trimmed = value.trim();
94            if let Ok(value) = trimmed.parse::<i32>() {
95                return Ok(value);
96            }
97            match trimmed.to_ascii_uppercase().as_str() {
98                "HK" => Ok(1),
99                "HK_FUTURE" | "HKFUTURE" => Ok(2),
100                "US" => Ok(11),
101                "SH" | "CN" => Ok(21),
102                "SZ" => Ok(22),
103                "SG" => Ok(31),
104                "JP" => Ok(41),
105                "MY" => Ok(61),
106                _ => Err(serde::de::Error::custom(format!(
107                    "unknown market {value:?}: valid = HK/HK_FUTURE/US/SH/SZ/SG/JP/MY or integer 1/2/11/21/22/31/41/61"
108                ))),
109            }
110        }
111    }
112}