1use std::time::Duration;
4
5use anyhow::Result;
6use serde::Serialize;
7use tabled::Tabled;
8
9use crate::common::{connect_gateway, parse_symbol};
10use crate::output::OutputFormat;
11use futu_qot::types::SubType;
12
13#[derive(Tabled)]
14struct RtRow {
15 #[tabled(rename = "Time")]
16 time: String,
17 #[tabled(rename = "Price")]
18 price: String,
19 #[tabled(rename = "Avg")]
20 avg: String,
21 #[tabled(rename = "Volume")]
22 volume: String,
23 #[tabled(rename = "Turnover")]
24 turnover: String,
25}
26
27#[derive(Serialize)]
28struct RtJson {
29 time: String,
30 minute: i32,
31 is_blank: bool,
32 price: f64,
33 last_close_price: f64,
34 avg_price: f64,
35 volume: i64,
36 turnover: f64,
37 timestamp: f64,
38}
39
40pub async fn run(gateway: &str, symbol: &str, format: OutputFormat) -> Result<()> {
41 let sec = parse_symbol(symbol)?;
42 let (client, _push_rx) = connect_gateway(gateway, "futucli-rt").await?;
43
44 futu_qot::sub::subscribe(
45 &client,
46 std::slice::from_ref(&sec),
47 &[SubType::RT],
48 true,
49 true,
50 )
51 .await?;
52 tokio::time::sleep(Duration::from_millis(300)).await;
53
54 let result = futu_qot::rt::get_rt(&client, &sec).await?;
55
56 let rows: Vec<RtRow> = result
57 .rt_list
58 .iter()
59 .filter(|r| !r.is_blank)
60 .map(|r| RtRow {
61 time: r.time.clone(),
62 price: format!("{:.3}", r.price),
63 avg: format!("{:.3}", r.avg_price),
64 volume: r.volume.to_string(),
65 turnover: format!("{:.0}", r.turnover),
66 })
67 .collect();
68
69 let jsons: Vec<RtJson> = result
70 .rt_list
71 .iter()
72 .map(|r| RtJson {
73 time: r.time.clone(),
74 minute: r.minute,
75 is_blank: r.is_blank,
76 price: r.price,
77 last_close_price: r.last_close_price,
78 avg_price: r.avg_price,
79 volume: r.volume,
80 turnover: r.turnover,
81 timestamp: r.timestamp,
82 })
83 .collect();
84
85 format.print_rows(&rows, &jsons)?;
86 Ok(())
87}