futu_mcp/handlers/
plate.rs1use std::sync::Arc;
4
5use anyhow::{bail, Result};
6use futu_net::client::FutuClient;
7use futu_qot::types::QotMarket;
8use serde::Serialize;
9
10use crate::state::{format_symbol, parse_symbol};
11
12fn parse_market(s: &str) -> Result<QotMarket> {
13 let m = match s.trim().to_ascii_uppercase().as_str() {
14 "HK" => QotMarket::HkSecurity,
15 "HK_FUTURE" => QotMarket::HkFuture,
16 "US" => QotMarket::UsSecurity,
17 "SH" => QotMarket::CnshSecurity,
18 "SZ" => QotMarket::CnszSecurity,
19 other => bail!("unknown market {other:?} (HK|HK_FUTURE|US|SH|SZ)"),
20 };
21 Ok(m)
22}
23
24fn parse_plate_set(s: &str) -> Result<i32> {
25 let v = match s.trim().to_ascii_lowercase().as_str() {
26 "all" => 0,
27 "industry" => 1,
28 "region" => 2,
29 "concept" => 3,
30 other => bail!("unknown plate-set {other:?} (all|industry|region|concept)"),
31 };
32 Ok(v)
33}
34
35#[derive(Serialize)]
36struct PlateOut {
37 plate: String,
38 name: String,
39 plate_type: Option<i32>,
40}
41
42pub async fn list_plates(
43 client: &Arc<FutuClient>,
44 market: &str,
45 plate_set: &str,
46) -> Result<String> {
47 let m = parse_market(market)?;
48 let set = parse_plate_set(plate_set)?;
49 let plates = futu_qot::market_misc::get_plate_set(client, m, set).await?;
50 let out: Vec<PlateOut> = plates
51 .iter()
52 .map(|p| PlateOut {
53 plate: format_symbol(&p.security),
54 name: p.name.clone(),
55 plate_type: p.plate_type,
56 })
57 .collect();
58 Ok(serde_json::to_string_pretty(&out)?)
59}
60
61#[derive(Serialize)]
62struct StockOut {
63 symbol: String,
64 id: i64,
65 name: String,
66 sec_type: i32,
67 lot_size: i32,
68 list_time: String,
69 delisting: bool,
70}
71
72pub async fn plate_stocks(client: &Arc<FutuClient>, plate_symbol: &str) -> Result<String> {
73 let plate = parse_symbol(plate_symbol)?;
74 let list = futu_qot::market_misc::get_plate_security(client, &plate).await?;
75 let out: Vec<StockOut> = list
76 .iter()
77 .map(|i| StockOut {
78 symbol: format_symbol(&i.security),
79 id: i.id,
80 name: i.name.clone(),
81 sec_type: i.sec_type,
82 lot_size: i.lot_size,
83 list_time: i.list_time.clone(),
84 delisting: i.delisting,
85 })
86 .collect();
87 Ok(serde_json::to_string_pretty(&out)?)
88}