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 futu_qot::types::SubType;
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 = if odd_lot {
52 SubType::OrderBookOdd
53 } else {
54 SubType::OrderBook
55 };
56 let order_book_type = odd_lot.then_some(1);
57
58 futu_qot::sub::subscribe(&client, std::slice::from_ref(&sec), &[sub_type], true, true).await?;
60 tokio::time::sleep(Duration::from_millis(300)).await;
61
62 let ob = futu_qot::order_book::get_order_book_with_type(&client, &sec, depth, order_book_type)
63 .await?;
64
65 let mut rows = Vec::new();
67 for (i, a) in ob.ask_list.iter().enumerate().rev() {
68 rows.push(OrderBookRow {
69 side: "ASK".to_string(),
70 level: (i + 1) as i32,
71 price: format!("{:.3}", a.price),
72 volume: a.volume.to_string(),
73 orders: a.order_count,
74 });
75 }
76 for (i, b) in ob.bid_list.iter().enumerate() {
77 rows.push(OrderBookRow {
78 side: "BID".to_string(),
79 level: (i + 1) as i32,
80 price: format!("{:.3}", b.price),
81 volume: b.volume.to_string(),
82 orders: b.order_count,
83 });
84 }
85
86 let json = OrderBookJson {
87 symbol: format_symbol(&ob.security),
88 odd_lot,
89 bids: ob
90 .bid_list
91 .iter()
92 .map(|e| Level {
93 price: e.price,
94 volume: e.volume,
95 orders: e.order_count,
96 })
97 .collect(),
98 asks: ob
99 .ask_list
100 .iter()
101 .map(|e| Level {
102 price: e.price,
103 volume: e.volume,
104 orders: e.order_count,
105 })
106 .collect(),
107 };
108
109 format.print_rows(&rows, std::slice::from_ref(&json))?;
110 Ok(())
111}