1use super::*;
4
5#[derive(Debug, Deserialize, schemars::JsonSchema)]
6#[serde(deny_unknown_fields)]
7pub struct SymbolReq {
8 #[schemars(
9 description = "Security symbol in MARKET.CODE format, e.g. HK.00700, US.AAPL \
10 (alias: code / stock / security for SDK compat)"
11 )]
12 #[serde(alias = "code", alias = "stock", alias = "security")]
16 pub symbol: String,
17}
18
19#[derive(Debug, Deserialize, schemars::JsonSchema)]
20#[serde(deny_unknown_fields)]
21pub struct ShortInfoReq {
22 #[schemars(
23 description = "Security symbol in MARKET.CODE format, e.g. HK.00700, US.AAPL \
24 (alias: code / stock / security for SDK compat)"
25 )]
26 #[serde(alias = "code", alias = "stock", alias = "security")]
27 pub symbol: String,
28 #[schemars(description = "Pagination key; alias: nextKey")]
29 #[serde(default, alias = "nextKey")]
30 pub next_key: Option<String>,
31 #[schemars(description = "Page size, 1..50; omitted uses backend default 10")]
32 #[serde(default)]
33 pub num: Option<i32>,
34}
35
36impl ShortInfoReq {
37 pub fn validate(&self, tool: &str) -> Result<(), String> {
38 validate_optional_i32_range(tool, "num", self.num, 1, 50)
39 }
40}
41
42#[derive(Debug, Deserialize, schemars::JsonSchema)]
43#[serde(deny_unknown_fields)]
44pub struct TopTenBuySellBrokersReq {
45 #[schemars(
46 description = "HK security symbol in MARKET.CODE format, e.g. HK.00700 \
47 (alias: code / stock / security for SDK compat)"
48 )]
49 #[serde(alias = "code", alias = "stock", alias = "security")]
50 pub symbol: String,
51 #[schemars(
52 description = "0 or omitted = realtime; N = previous N trading days; must be non-negative; alias: daysBefore"
53 )]
54 #[serde(default, alias = "daysBefore")]
55 pub days_before: Option<i32>,
56}
57
58impl TopTenBuySellBrokersReq {
59 pub fn validate(&self) -> Result<(), String> {
60 if self.days_before.unwrap_or(0) < 0 {
61 return Err(format!(
62 "days_before must be non-negative, got {}",
63 self.days_before.unwrap_or(0)
64 ));
65 }
66 Ok(())
67 }
68}
69
70#[derive(Debug, Deserialize, schemars::JsonSchema)]
71#[serde(deny_unknown_fields)]
72pub struct OptionVolatilityReq {
73 #[schemars(
74 description = "Option symbol in MARKET.CODE format, e.g. US.AAPL260116C200000 \
75 (alias: code / option / security for SDK compat)"
76 )]
77 #[serde(alias = "code", alias = "option", alias = "security")]
78 pub symbol: String,
79 #[schemars(
80 description = "Query period: 0/omitted=month, 1=week, 2=month, 3=quarter, 4=half-year, 5=year"
81 )]
82 #[serde(default, alias = "queryTimePeriod")]
83 pub query_time_period: Option<i32>,
84 #[schemars(
85 description = "Underlying historical-volatility period in days, 5..250; omitted uses backend default 30"
86 )]
87 #[serde(default, alias = "hvTimePeriod")]
88 pub hv_time_period: Option<i32>,
89}
90
91impl OptionVolatilityReq {
92 pub fn validate(&self) -> Result<(), String> {
93 if let Some(query_time_period) = self.query_time_period
94 && query_time_period != 0
95 && !(1..=5).contains(&query_time_period)
96 {
97 return Err(format!(
98 "query_time_period must be 0 or in 1..=5 for futu_get_option_volatility, got {query_time_period}"
99 ));
100 }
101 validate_optional_i32_range(
102 "futu_get_option_volatility",
103 "hv_time_period",
104 self.hv_time_period,
105 5,
106 250,
107 )
108 }
109}
110
111#[derive(Debug, Deserialize, schemars::JsonSchema)]
112#[serde(deny_unknown_fields)]
113pub struct OptionExerciseProbabilityReq {
114 #[schemars(
115 description = "Option symbol in MARKET.CODE format, e.g. US.AAPL260116C200000 \
116 (alias: code / option / security for SDK compat)"
117 )]
118 #[serde(alias = "code", alias = "option", alias = "security")]
119 pub symbol: String,
120}
121
122#[derive(Debug, Deserialize, schemars::JsonSchema)]
123#[serde(deny_unknown_fields)]
124pub struct SymbolListReq {
125 #[schemars(description = "Array of security symbols in MARKET.CODE format \
126 (e.g. [\"HK.00700\", \"US.AAPL\"]). Field name is \
127 `symbols` (Rust native snake_case); aliases: `stocks` \
128 / `code_list` / `symbol_list` / `security_list` \
129 for SDK compat.")]
130 #[serde(
133 alias = "stocks",
134 alias = "code_list",
135 alias = "symbol_list",
136 alias = "security_list"
137 )]
138 pub symbols: Vec<String>,
139}
140
141#[derive(Debug, Deserialize, schemars::JsonSchema)]
142#[serde(deny_unknown_fields)]
143pub struct KLineReq {
144 #[schemars(description = "Security symbol (MARKET.CODE); alias: code / stock")]
145 #[serde(alias = "code", alias = "stock")]
147 pub symbol: String,
148 #[schemars(
149 description = "K-line type: day|week|month|quarter|year|1min|3min|5min|15min|30min|60min \
150 (alias: ktype / k_type / kl_type for SDK compat)"
151 )]
152 #[serde(default = "default_kl_type", alias = "ktype", alias = "k_type")]
153 pub kl_type: String,
154 #[schemars(
155 description = "Number of candles to return (default 100); alias: num / max_count / req_count"
156 )]
157 #[serde(alias = "num", alias = "max_count", alias = "req_count")]
158 pub count: Option<i32>,
159 #[schemars(
160 description = "Start date yyyy-MM-dd (optional; default computed from count); alias: begin_time / from"
161 )]
162 #[serde(alias = "begin_time", alias = "from")]
163 pub begin: Option<String>,
164 #[schemars(
165 description = "End date yyyy-MM-dd (optional; default today); alias: end_time / to"
166 )]
167 #[serde(alias = "end_time", alias = "to")]
168 pub end: Option<String>,
169}
170
171impl KLineReq {
172 pub fn validate(&self) -> Result<(), String> {
173 if let Some(count) = self.count
174 && !(1..=1000).contains(&count)
175 {
176 return Err(format!(
177 "count must be in 1..=1000 for futu_get_kline, got {count}"
178 ));
179 }
180 Ok(())
181 }
182}
183
184#[derive(Debug, Deserialize, schemars::JsonSchema)]
185#[serde(deny_unknown_fields)]
186pub struct OrderBookReq {
187 #[schemars(description = "Security symbol (MARKET.CODE); alias: code / stock / security")]
188 #[serde(alias = "code", alias = "stock", alias = "security")]
190 pub symbol: String,
191 #[schemars(description = "Order book depth, 1-40 (default 10); alias: num")]
192 #[serde(default = "default_depth", alias = "num")]
193 pub depth: i32,
194 #[schemars(
195 description = "Set true to query SG/MY odd-lot orderbook (SubType_OrderBook_Odd=22)"
196 )]
197 #[serde(default, alias = "oddLot", alias = "is_odd_lot")]
198 pub odd_lot: bool,
199}
200
201impl OrderBookReq {
202 pub fn validate(&self) -> Result<(), String> {
203 if !(1..=40).contains(&self.depth) {
204 return Err(format!(
205 "depth must be in 1..=40 for futu_get_orderbook, got {}",
206 self.depth
207 ));
208 }
209 Ok(())
210 }
211}
212
213#[derive(Debug, Deserialize, schemars::JsonSchema)]
214#[serde(deny_unknown_fields)]
215pub struct TickerReq {
216 #[schemars(description = "Security symbol (MARKET.CODE); alias: code / stock / security")]
217 #[serde(alias = "code", alias = "stock", alias = "security")]
219 pub symbol: String,
220 #[schemars(
221 description = "Number of ticks to fetch (default 100, max 1000); alias: num / max_count / req_count"
222 )]
223 #[serde(
224 default = "default_ticker_count",
225 alias = "num",
226 alias = "max_count",
227 alias = "req_count"
228 )]
229 pub count: i32,
230}
231
232impl TickerReq {
233 pub fn validate(&self) -> Result<(), String> {
234 if !(1..=1000).contains(&self.count) {
235 return Err(format!(
236 "count must be in 1..=1000 for futu_get_ticker, got {}",
237 self.count
238 ));
239 }
240 Ok(())
241 }
242}
243
244#[derive(Debug, Deserialize, schemars::JsonSchema)]
245#[serde(deny_unknown_fields)]
246pub struct PlateListReq {
247 #[schemars(description = "Market: HK|HK_FUTURE|US|SH|SZ")]
248 pub market: String,
249 #[schemars(
250 description = "Plate set: all|industry|region|concept (default all); alias: plate_set_type. \
251 region only has backend data for SH/SZ; HK/HK_FUTURE/US returns an empty successful list like the native gateway."
252 )]
253 #[serde(default = "default_plate_set", alias = "plate_set_type")]
255 pub plate_set: String,
256}
257
258#[derive(Debug, Deserialize, schemars::JsonSchema)]
259#[serde(deny_unknown_fields)]
260pub struct PlateStocksReq {
261 #[schemars(
262 description = "Plate symbol, MARKET.CODE format (e.g. HK.LIST1001); alias: symbol / code / plate_code"
263 )]
264 #[serde(alias = "symbol", alias = "code", alias = "plate_code")]
266 pub plate: String,
267}
268
269#[derive(Debug, Deserialize, schemars::JsonSchema)]
270#[serde(deny_unknown_fields)]
271pub struct MarketStateReq {
272 #[schemars(
273 description = "Symbols list in MARKET.CODE format; alias: stocks / code_list / symbol_list / security_list"
274 )]
275 #[serde(
277 alias = "stocks",
278 alias = "code_list",
279 alias = "symbol_list",
280 alias = "security_list"
281 )]
282 pub symbols: Vec<String>,
283}