1use anyhow::Result;
4use futu_surface_spec::input::{parse_plate_market_id, parse_plate_set_id};
5use serde::Serialize;
6use tabled::Tabled;
7
8use crate::common::{connect_gateway, format_symbol, parse_symbol};
9use crate::output::OutputFormat;
10use crate::qot_sdk_adapter;
11use futu_qot::types::QotMarket;
12
13fn parse_market(s: &str) -> Result<QotMarket> {
15 let market = parse_plate_market_id(s)
16 .map_err(|error| anyhow::anyhow!("unknown market {:?}: {error}", error.raw()))?;
17 Ok(qot_sdk_adapter::qot_market_from_id(market))
18}
19
20fn parse_plate_set(s: &str) -> Result<i32> {
22 parse_plate_set_id(s)
23 .map_err(|error| anyhow::anyhow!("unknown plate-set {:?}: {error}", error.raw()))
24}
25
26#[derive(Tabled)]
27struct PlateRow {
28 #[tabled(rename = "Plate")]
29 plate: String,
30 #[tabled(rename = "Name")]
31 name: String,
32 #[tabled(rename = "Type")]
33 plate_type: String,
34}
35
36#[derive(Serialize)]
37struct PlateJson {
38 plate: String,
39 name: String,
40 plate_type: Option<i32>,
41}
42
43pub async fn list(gateway: &str, market: &str, set: &str, format: OutputFormat) -> Result<()> {
44 let m = parse_market(market)?;
45 let set_type = parse_plate_set(set)?;
46
47 let (client, _push_rx) = connect_gateway(gateway, "futucli-plate-list").await?;
48 let plates = futu_qot::market_misc::get_plate_set(&client, m, set_type).await?;
49
50 let rows: Vec<PlateRow> = plates
51 .iter()
52 .map(|p| PlateRow {
53 plate: format_symbol(&p.security),
54 name: p.name.clone(),
55 plate_type: p.plate_type.map(|v| v.to_string()).unwrap_or_default(),
56 })
57 .collect();
58
59 let jsons: Vec<PlateJson> = plates
60 .iter()
61 .map(|p| PlateJson {
62 plate: format_symbol(&p.security),
63 name: p.name.clone(),
64 plate_type: p.plate_type,
65 })
66 .collect();
67
68 format.print_rows(&rows, &jsons)?;
69 Ok(())
70}
71
72#[derive(Tabled)]
73struct StockRow {
74 #[tabled(rename = "Symbol")]
75 symbol: String,
76 #[tabled(rename = "Name")]
77 name: String,
78 #[tabled(rename = "ID")]
79 id: String,
80 #[tabled(rename = "Type")]
81 sec_type: i32,
82 #[tabled(rename = "Lot")]
83 lot_size: i32,
84}
85
86#[derive(Serialize)]
87struct StockJson {
88 symbol: String,
89 id: i64,
90 name: String,
91 sec_type: i32,
92 lot_size: i32,
93 list_time: String,
94 delisting: bool,
95}
96
97pub async fn stocks(gateway: &str, plate_symbol: &str, format: OutputFormat) -> Result<()> {
98 let plate = parse_symbol(plate_symbol)?;
99 let (client, _push_rx) = connect_gateway(gateway, "futucli-plate-stocks").await?;
100 let list = futu_qot::market_misc::get_plate_security(&client, &plate).await?;
101
102 let rows: Vec<StockRow> = list
103 .iter()
104 .map(|i| StockRow {
105 symbol: format_symbol(&i.security),
106 name: i.name.clone(),
107 id: i.id.to_string(),
108 sec_type: i.sec_type,
109 lot_size: i.lot_size,
110 })
111 .collect();
112
113 let jsons: Vec<StockJson> = list
114 .iter()
115 .map(|i| StockJson {
116 symbol: format_symbol(&i.security),
117 id: i.id,
118 name: i.name.clone(),
119 sec_type: i.sec_type,
120 lot_size: i.lot_size,
121 list_time: i.list_time.clone(),
122 delisting: i.delisting,
123 })
124 .collect();
125
126 format.print_rows(&rows, &jsons)?;
127 Ok(())
128}