1use std::time::Duration;
4
5use anyhow::Result;
6use serde::Serialize;
7use tabled::Tabled;
8
9use crate::common::{connect_gateway, format_symbol, parse_symbol};
10use crate::output::OutputFormat;
11use crate::qot_sdk_adapter;
12
13#[derive(Tabled)]
14struct OrderBookRow {
15 #[tabled(rename = "Side")]
16 side: String,
17 #[tabled(rename = "Level")]
18 level: i32,
19 #[tabled(rename = "Price")]
20 price: String,
21 #[tabled(rename = "Volume")]
22 volume: String,
23 #[tabled(rename = "Orders")]
24 orders: i32,
25}
26
27#[derive(Serialize)]
28struct OrderBookJson {
29 symbol: String,
30 odd_lot: bool,
31 bids: Vec<Level>,
32 asks: Vec<Level>,
33}
34
35#[derive(Serialize)]
36struct Level {
37 price: f64,
38 volume: i64,
39 orders: i32,
40}
41
42pub async fn run(
43 gateway: &str,
44 symbol: &str,
45 depth: i32,
46 odd_lot: bool,
47 format: OutputFormat,
48) -> Result<()> {
49 let sec = parse_symbol(symbol)?;
50 let (client, _push_rx) = connect_gateway(gateway, "futucli-orderbook").await?;
51 let sub_type = qot_sdk_adapter::order_book_sub_type(odd_lot);
52 let order_book_type = odd_lot.then_some(1);
53
54 futu_qot::sub::subscribe(&client, std::slice::from_ref(&sec), &[sub_type], true, true).await?;
56 tokio::time::sleep(Duration::from_millis(300)).await;
57
58 let ob = futu_qot::order_book::get_order_book_with_type(&client, &sec, depth, order_book_type)
59 .await?;
60
61 let mut rows = Vec::new();
63 for (i, a) in ob.ask_list.iter().enumerate().rev() {
64 rows.push(OrderBookRow {
65 side: "ASK".to_string(),
66 level: (i + 1) as i32,
67 price: format!("{:.3}", a.price),
68 volume: a.volume.to_string(),
69 orders: a.order_count,
70 });
71 }
72 for (i, b) in ob.bid_list.iter().enumerate() {
73 rows.push(OrderBookRow {
74 side: "BID".to_string(),
75 level: (i + 1) as i32,
76 price: format!("{:.3}", b.price),
77 volume: b.volume.to_string(),
78 orders: b.order_count,
79 });
80 }
81
82 let json = OrderBookJson {
83 symbol: format_symbol(&ob.security),
84 odd_lot,
85 bids: ob
86 .bid_list
87 .iter()
88 .map(|e| Level {
89 price: e.price,
90 volume: e.volume,
91 orders: e.order_count,
92 })
93 .collect(),
94 asks: ob
95 .ask_list
96 .iter()
97 .map(|e| Level {
98 price: e.price,
99 volume: e.volume,
100 orders: e.order_count,
101 })
102 .collect(),
103 };
104
105 format.print_rows(&rows, std::slice::from_ref(&json))?;
106 Ok(())
107}