futu_qot/
ticker.rs

1use futu_core::error::{FutuError, Result};
2use futu_core::proto_id;
3use futu_net::client::FutuClient;
4
5use crate::types::Security;
6
7/// 逐笔成交数据
8#[derive(Debug, Clone)]
9pub struct Ticker {
10    pub time: String,
11    pub sequence: i64,
12    pub dir: i32,
13    pub price: f64,
14    pub volume: i64,
15    pub turnover: f64,
16    pub ticker_type: Option<i32>,
17    pub timestamp: f64,
18}
19
20impl Ticker {
21    pub fn from_proto(t: &futu_proto::qot_common::Ticker) -> Self {
22        Self {
23            time: t.time.clone(),
24            sequence: t.sequence,
25            dir: t.dir,
26            price: t.price,
27            volume: t.volume,
28            turnover: t.turnover,
29            ticker_type: t.r#type,
30            timestamp: t.timestamp.unwrap_or(0.0),
31        }
32    }
33}
34
35/// 逐笔查询结果
36#[derive(Debug, Clone)]
37pub struct TickerResult {
38    pub security: Security,
39    pub ticker_list: Vec<Ticker>,
40}
41
42/// 获取逐笔成交数据
43///
44/// 需要先订阅 SubType::Ticker。
45/// `max_ret_num`: 最多返回的逐笔个数,最多 1000。
46pub async fn get_ticker(
47    client: &FutuClient,
48    security: &Security,
49    max_ret_num: i32,
50) -> Result<TickerResult> {
51    let req = futu_proto::qot_get_ticker::Request {
52        c2s: futu_proto::qot_get_ticker::C2s {
53            security: security.to_proto(),
54            max_ret_num,
55        },
56    };
57
58    let body = prost::Message::encode_to_vec(&req);
59    let resp_frame = client.request(proto_id::QOT_GET_TICKER, body).await?;
60
61    let resp: futu_proto::qot_get_ticker::Response =
62        prost::Message::decode(resp_frame.body.as_ref()).map_err(FutuError::Proto)?;
63
64    if resp.ret_type != 0 {
65        return Err(FutuError::ServerError {
66            ret_type: resp.ret_type,
67            msg: resp.ret_msg.unwrap_or_default(),
68        });
69    }
70
71    let s2c = resp
72        .s2c
73        .ok_or(FutuError::Codec("missing s2c in GetTicker".into()))?;
74
75    Ok(TickerResult {
76        security: Security::from_proto(&s2c.security),
77        ticker_list: s2c.ticker_list.iter().map(Ticker::from_proto).collect(),
78    })
79}