futu_mcp/handlers/reference/
short_info.rs1use std::sync::Arc;
4
5use anyhow::{Result, anyhow, bail};
6use futu_net::client::FutuClient;
7use prost::Message;
8use serde::Serialize;
9
10use crate::state::parse_symbol;
11
12#[derive(Serialize)]
13struct CorporateActionsBuybacksOut {
14 symbol: String,
15 s2c: futu_proto::qot_get_corporate_actions_buybacks::S2c,
16}
17
18#[derive(Serialize)]
19struct CorporateActionsDividendsOut {
20 symbol: String,
21 s2c: futu_proto::qot_get_corporate_actions_dividends::S2c,
22}
23
24#[derive(Serialize)]
25struct CorporateActionsStockSplitsOut {
26 symbol: String,
27 s2c: futu_proto::qot_get_corporate_actions_stock_splits::S2c,
28}
29
30pub async fn get_corporate_actions_dividends(
31 client: &Arc<FutuClient>,
32 symbol: &str,
33) -> Result<String> {
34 let sec = parse_symbol(symbol)?;
35 let req = futu_proto::qot_get_corporate_actions_dividends::Request {
36 c2s: futu_proto::qot_get_corporate_actions_dividends::C2s {
37 security: futu_proto::qot_common::Security {
38 market: sec.market as i32,
39 code: sec.code.clone(),
40 },
41 },
42 };
43 let frame = client
44 .request(
45 futu_core::proto_id::QOT_GET_CORPORATE_ACTIONS_DIVIDENDS,
46 req.encode_to_vec(),
47 )
48 .await?;
49 let resp =
50 futu_proto::qot_get_corporate_actions_dividends::Response::decode(frame.body.as_ref())
51 .map_err(|e| anyhow!("decode corporate_actions_dividends: {e}"))?;
52 if resp.ret_type != 0 {
53 bail!(
54 "corporate_actions_dividends ret_type={} msg={:?}",
55 resp.ret_type,
56 resp.ret_msg
57 );
58 }
59 let s2c = resp.s2c.ok_or_else(|| anyhow!("missing s2c"))?;
60 Ok(serde_json::to_string_pretty(
61 &CorporateActionsDividendsOut {
62 symbol: symbol.to_string(),
63 s2c,
64 },
65 )?)
66}
67
68pub async fn get_corporate_actions_buybacks(
69 client: &Arc<FutuClient>,
70 symbol: &str,
71 next_key: Option<&str>,
72 num: Option<i32>,
73) -> Result<String> {
74 let sec = parse_symbol(symbol)?;
75 let req = futu_proto::qot_get_corporate_actions_buybacks::Request {
76 c2s: futu_proto::qot_get_corporate_actions_buybacks::C2s {
77 security: futu_proto::qot_common::Security {
78 market: sec.market as i32,
79 code: sec.code.clone(),
80 },
81 next_key: next_key.map(str::to_string),
82 num,
83 },
84 };
85 let frame = client
86 .request(
87 futu_core::proto_id::QOT_GET_CORPORATE_ACTIONS_BUYBACKS,
88 req.encode_to_vec(),
89 )
90 .await?;
91 let resp =
92 futu_proto::qot_get_corporate_actions_buybacks::Response::decode(frame.body.as_ref())
93 .map_err(|e| anyhow!("decode corporate_actions_buybacks: {e}"))?;
94 if resp.ret_type != 0 {
95 bail!(
96 "corporate_actions_buybacks ret_type={} msg={:?}",
97 resp.ret_type,
98 resp.ret_msg
99 );
100 }
101 let s2c = resp.s2c.ok_or_else(|| anyhow!("missing s2c"))?;
102 Ok(serde_json::to_string_pretty(
103 &CorporateActionsBuybacksOut {
104 symbol: symbol.to_string(),
105 s2c,
106 },
107 )?)
108}
109
110pub async fn get_corporate_actions_stock_splits(
111 client: &Arc<FutuClient>,
112 symbol: &str,
113 next_key: Option<&str>,
114 num: Option<i32>,
115) -> Result<String> {
116 let sec = parse_symbol(symbol)?;
117 let req = futu_proto::qot_get_corporate_actions_stock_splits::Request {
118 c2s: futu_proto::qot_get_corporate_actions_stock_splits::C2s {
119 security: futu_proto::qot_common::Security {
120 market: sec.market as i32,
121 code: sec.code.clone(),
122 },
123 next_key: next_key.map(str::to_string),
124 num,
125 },
126 };
127 let frame = client
128 .request(
129 futu_core::proto_id::QOT_GET_CORPORATE_ACTIONS_STOCK_SPLITS,
130 req.encode_to_vec(),
131 )
132 .await?;
133 let resp =
134 futu_proto::qot_get_corporate_actions_stock_splits::Response::decode(frame.body.as_ref())
135 .map_err(|e| anyhow!("decode corporate_actions_stock_splits: {e}"))?;
136 if resp.ret_type != 0 {
137 bail!(
138 "corporate_actions_stock_splits ret_type={} msg={:?}",
139 resp.ret_type,
140 resp.ret_msg
141 );
142 }
143 let s2c = resp.s2c.ok_or_else(|| anyhow!("missing s2c"))?;
144 Ok(serde_json::to_string_pretty(
145 &CorporateActionsStockSplitsOut {
146 symbol: symbol.to_string(),
147 s2c,
148 },
149 )?)
150}
151
152#[derive(Serialize)]
153struct DailyShortVolumeOut {
154 symbol: String,
155 s2c: futu_proto::qot_get_daily_short_volume::S2c,
156}
157
158pub async fn get_daily_short_volume(
159 client: &Arc<FutuClient>,
160 symbol: &str,
161 next_key: Option<&str>,
162 num: Option<i32>,
163) -> Result<String> {
164 let sec = parse_symbol(symbol)?;
165 let req = futu_proto::qot_get_daily_short_volume::Request {
166 c2s: futu_proto::qot_get_daily_short_volume::C2s {
167 security: futu_proto::qot_common::Security {
168 market: sec.market as i32,
169 code: sec.code.clone(),
170 },
171 next_key: next_key.map(str::to_string),
172 num,
173 },
174 };
175 let frame = client
176 .request(
177 futu_core::proto_id::QOT_GET_DAILY_SHORT_VOLUME,
178 req.encode_to_vec(),
179 )
180 .await?;
181 let resp = futu_proto::qot_get_daily_short_volume::Response::decode(frame.body.as_ref())
182 .map_err(|e| anyhow!("decode daily_short_volume: {e}"))?;
183 if resp.ret_type != 0 {
184 bail!(
185 "daily_short_volume ret_type={} msg={:?}",
186 resp.ret_type,
187 resp.ret_msg
188 );
189 }
190 let s2c = resp.s2c.ok_or_else(|| anyhow!("missing s2c"))?;
191 Ok(serde_json::to_string_pretty(&DailyShortVolumeOut {
192 symbol: symbol.to_string(),
193 s2c,
194 })?)
195}
196
197#[derive(Serialize)]
198struct ShortInterestOut {
199 symbol: String,
200 s2c: futu_proto::qot_get_short_interest::S2c,
201}
202
203pub async fn get_short_interest(
204 client: &Arc<FutuClient>,
205 symbol: &str,
206 next_key: Option<&str>,
207 num: Option<i32>,
208) -> Result<String> {
209 let sec = parse_symbol(symbol)?;
210 let req = futu_proto::qot_get_short_interest::Request {
211 c2s: futu_proto::qot_get_short_interest::C2s {
212 security: futu_proto::qot_common::Security {
213 market: sec.market as i32,
214 code: sec.code.clone(),
215 },
216 next_key: next_key.map(str::to_string),
217 num,
218 },
219 };
220 let frame = client
221 .request(
222 futu_core::proto_id::QOT_GET_SHORT_INTEREST,
223 req.encode_to_vec(),
224 )
225 .await?;
226 let resp = futu_proto::qot_get_short_interest::Response::decode(frame.body.as_ref())
227 .map_err(|e| anyhow!("decode short_interest: {e}"))?;
228 if resp.ret_type != 0 {
229 bail!(
230 "short_interest ret_type={} msg={:?}",
231 resp.ret_type,
232 resp.ret_msg
233 );
234 }
235 let s2c = resp.s2c.ok_or_else(|| anyhow!("missing s2c"))?;
236 Ok(serde_json::to_string_pretty(&ShortInterestOut {
237 symbol: symbol.to_string(),
238 s2c,
239 })?)
240}
241
242#[derive(Serialize)]
243struct TopTenBuySellBrokersOut {
244 symbol: String,
245 s2c: futu_proto::qot_get_top_ten_buy_sell_brokers::S2c,
246}
247
248pub async fn get_top_ten_buy_sell_brokers(
249 client: &Arc<FutuClient>,
250 symbol: &str,
251 days_before: Option<i32>,
252) -> Result<String> {
253 let sec = parse_symbol(symbol)?;
254 let req = futu_proto::qot_get_top_ten_buy_sell_brokers::Request {
255 c2s: futu_proto::qot_get_top_ten_buy_sell_brokers::C2s {
256 security: futu_proto::qot_common::Security {
257 market: sec.market as i32,
258 code: sec.code.clone(),
259 },
260 days_before,
261 },
262 };
263 let frame = client
264 .request(
265 futu_core::proto_id::QOT_GET_TOP_TEN_BUY_SELL_BROKERS,
266 req.encode_to_vec(),
267 )
268 .await?;
269 let resp = futu_proto::qot_get_top_ten_buy_sell_brokers::Response::decode(frame.body.as_ref())
270 .map_err(|e| anyhow!("decode top_ten_buy_sell_brokers: {e}"))?;
271 if resp.ret_type != 0 {
272 bail!(
273 "top_ten_buy_sell_brokers ret_type={} msg={:?}",
274 resp.ret_type,
275 resp.ret_msg
276 );
277 }
278 let s2c = resp.s2c.ok_or_else(|| anyhow!("missing s2c"))?;
279 Ok(serde_json::to_string_pretty(&TopTenBuySellBrokersOut {
280 symbol: symbol.to_string(),
281 s2c,
282 })?)
283}