Skip to main content

futucli/cmd/
orderbook.rs

1//! `futucli orderbook` — 获取摆盘数据
2
3use 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    bids: Vec<Level>,
31    asks: Vec<Level>,
32}
33
34#[derive(Serialize)]
35struct Level {
36    price: f64,
37    volume: i64,
38    orders: i32,
39}
40
41pub async fn run(gateway: &str, symbol: &str, depth: i32, format: OutputFormat) -> Result<()> {
42    let sec = parse_symbol(symbol)?;
43    let (client, _push_rx) = connect_gateway(gateway, "futucli-orderbook").await?;
44
45    // 订阅 OrderBook,首次推送会携带完整快照
46    futu_qot::sub::subscribe(
47        &client,
48        std::slice::from_ref(&sec),
49        &[SubType::OrderBook],
50        true,
51        true,
52    )
53    .await?;
54    tokio::time::sleep(Duration::from_millis(300)).await;
55
56    let ob = futu_qot::order_book::get_order_book(&client, &sec, depth).await?;
57
58    // 表格:先卖档(高到低),再买档(高到低)
59    let mut rows = Vec::new();
60    for (i, a) in ob.ask_list.iter().enumerate().rev() {
61        rows.push(OrderBookRow {
62            side: "ASK".to_string(),
63            level: (i + 1) as i32,
64            price: format!("{:.3}", a.price),
65            volume: a.volume.to_string(),
66            orders: a.order_count,
67        });
68    }
69    for (i, b) in ob.bid_list.iter().enumerate() {
70        rows.push(OrderBookRow {
71            side: "BID".to_string(),
72            level: (i + 1) as i32,
73            price: format!("{:.3}", b.price),
74            volume: b.volume.to_string(),
75            orders: b.order_count,
76        });
77    }
78
79    let json = OrderBookJson {
80        symbol: format_symbol(&ob.security),
81        bids: ob
82            .bid_list
83            .iter()
84            .map(|e| Level {
85                price: e.price,
86                volume: e.volume,
87                orders: e.order_count,
88            })
89            .collect(),
90        asks: ob
91            .ask_list
92            .iter()
93            .map(|e| Level {
94                price: e.price,
95                volume: e.volume,
96                orders: e.order_count,
97            })
98            .collect(),
99    };
100
101    format.print_rows(&rows, std::slice::from_ref(&json))?;
102    Ok(())
103}