futu_mcp/tool_args/
mod.rs1mod push;
11mod qot;
12mod trd;
13
14pub use push::*;
15pub use qot::*;
16pub use trd::*;
17
18use rmcp::schemars;
19use serde::Deserialize;
20
21use crate::tool_enums::ToolEnum;
22
23#[derive(Debug, Default, Deserialize, schemars::JsonSchema)]
29#[serde(deny_unknown_fields)]
30pub struct NoArgs {}
31
32fn deser_int_or_order_type_str<'de, D>(deserializer: D) -> std::result::Result<i32, D::Error>
47where
48 D: serde::Deserializer<'de>,
49{
50 #[derive(Deserialize)]
51 #[serde(untagged)]
52 enum IntOrStr {
53 Int(i32),
54 Str(String),
55 }
56 match IntOrStr::deserialize(deserializer)? {
57 IntOrStr::Int(i) => Ok(i),
58 IntOrStr::Str(s) => match s.trim().to_ascii_uppercase().as_str() {
59 "NORMAL" | "LIMIT" => Ok(1),
60 "MARKET" => Ok(2),
61 "ABSOLUTE_LIMIT" => Ok(5),
62 "AUCTION" => Ok(6),
63 "AUCTION_LIMIT" => Ok(7),
64 "SPECIAL_LIMIT" => Ok(8),
65 other => other.parse::<i32>().map_err(|_| {
67 serde::de::Error::custom(format!(
68 "unknown order_type {other:?}: expect integer or one of \
69 NORMAL|LIMIT|MARKET|ABSOLUTE_LIMIT|AUCTION|AUCTION_LIMIT|SPECIAL_LIMIT"
70 ))
71 }),
72 },
73 }
74}
75
76fn deser_order_id_raw_from_int_or_str<'de, D>(
83 deserializer: D,
84) -> std::result::Result<String, D::Error>
85where
86 D: serde::Deserializer<'de>,
87{
88 #[derive(Deserialize)]
89 #[serde(untagged)]
90 enum IntOrStr {
91 Int(u64),
92 Str(String),
93 }
94
95 match IntOrStr::deserialize(deserializer)? {
96 IntOrStr::Int(i) => Ok(i.to_string()),
97 IntOrStr::Str(s) => {
98 let trimmed = s.trim();
99 if trimmed.is_empty() {
100 return Err(serde::de::Error::custom(
101 "invalid order_id string: must not be empty",
102 ));
103 }
104 Ok(trimmed.to_string())
105 }
106 }
107}
108
109fn deser_trd_market_string_allow_empty<'de, D>(
118 deserializer: D,
119) -> std::result::Result<String, D::Error>
120where
121 D: serde::Deserializer<'de>,
122{
123 let opt: Option<serde_json::Value> = Option::deserialize(deserializer)?;
124 match opt {
125 None | Some(serde_json::Value::Null) => Ok(String::new()),
126 Some(serde_json::Value::String(s)) if s.trim().is_empty() => Ok(String::new()),
127 Some(v) => {
128 let e = match v {
130 serde_json::Value::Number(n) => {
131 let i = n.as_i64().ok_or_else(|| {
132 serde::de::Error::custom(format!("trd_market number invalid: {n}"))
133 })? as i32;
134 crate::tool_enums::TrdMarketEnum::from_i32(i).ok_or_else(|| {
135 serde::de::Error::custom(format!(
136 "unknown trd_market int {i}: valid = {:?}",
137 crate::tool_enums::TrdMarketEnum::all_int_values()
138 ))
139 })?
140 }
141 serde_json::Value::String(s) => {
142 let t = s.trim();
143 crate::tool_enums::TrdMarketEnum::from_str(t)
144 .or_else(|| {
145 t.parse::<i32>()
146 .ok()
147 .and_then(crate::tool_enums::TrdMarketEnum::from_i32)
148 })
149 .ok_or_else(|| {
150 serde::de::Error::custom(format!(
151 "unknown trd_market {s:?}: valid = {:?}",
152 crate::tool_enums::TrdMarketEnum::all_string_values()
153 ))
154 })?
155 }
156 _ => {
157 return Err(serde::de::Error::custom(format!(
158 "trd_market must be int or string, got: {v}"
159 )));
160 }
161 };
162 let i = e.as_i32();
164 let names = crate::tool_enums::TrdMarketEnum::all_string_values();
165 let ints = crate::tool_enums::TrdMarketEnum::all_int_values();
166 let idx = ints
167 .iter()
168 .position(|&v| v == i)
169 .ok_or_else(|| serde::de::Error::custom("trd_market i32 has no canonical"))?;
170 Ok(names[idx].to_string())
171 }
172 }
173}
174
175fn default_kl_type() -> String {
176 "day".to_string()
177}
178
179fn default_depth() -> i32 {
180 10
181}
182
183fn default_ticker_count() -> i32 {
184 100
185}
186
187fn default_plate_set() -> String {
188 "all".to_string()
189}
190
191fn default_env() -> String {
192 "real".to_string()
193}
194
195fn default_env_simulate() -> String {
196 "simulate".to_string()
197}
198
199fn default_order_type() -> String {
200 "NORMAL".to_string()
201}
202
203fn default_modify_op() -> String {
204 "NORMAL".to_string()
205}
206
207fn default_true() -> bool {
208 true
209}
210
211fn default_rehab_none() -> String {
212 "none".to_string()
213}
214
215fn default_history_kline_max_count() -> Option<i32> {
218 Some(1000)
219}
220
221fn default_reference_type() -> String {
222 "warrant".to_string()
224}
225
226fn default_warrant_num() -> i32 {
227 20
228}
229
230fn default_user_security_group_type() -> i32 {
231 1
232}
233
234fn default_stock_filter_num() -> i32 {
235 50
236}
237
238fn default_is_first_push() -> bool {
239 true
240}
241
242fn default_is_reg_push() -> bool {
243 true
244}