futu_qot/
sub.rs

1use futu_core::error::{FutuError, Result};
2use futu_core::proto_id;
3use futu_net::client::FutuClient;
4
5use crate::types::{Security, SubType};
6
7/// 订阅行情
8///
9/// 订阅指定股票的指定类型行情数据。
10/// 订阅后可通过推送接收实时数据更新。
11pub async fn subscribe(
12    client: &FutuClient,
13    securities: &[Security],
14    sub_types: &[SubType],
15    is_reg_push: bool,
16    is_first_push: bool,
17) -> Result<()> {
18    let req = futu_proto::qot_sub::Request {
19        c2s: futu_proto::qot_sub::C2s {
20            security_list: securities.iter().map(|s| s.to_proto()).collect(),
21            sub_type_list: sub_types.iter().map(|t| *t as i32).collect(),
22            is_sub_or_un_sub: true,
23            is_reg_or_un_reg_push: Some(is_reg_push),
24            reg_push_rehab_type_list: vec![],
25            is_first_push: Some(is_first_push),
26            is_unsub_all: None,
27            is_sub_order_book_detail: None,
28            extended_time: None,
29            session: None,
30        },
31    };
32
33    let body = prost::Message::encode_to_vec(&req);
34    let resp_frame = client.request(proto_id::QOT_SUB, body).await?;
35
36    let resp: futu_proto::qot_sub::Response =
37        prost::Message::decode(resp_frame.body.as_ref()).map_err(FutuError::Proto)?;
38
39    check_ret_type(resp.ret_type, resp.ret_msg)
40}
41
42/// 退订行情
43pub async fn unsubscribe(
44    client: &FutuClient,
45    securities: &[Security],
46    sub_types: &[SubType],
47) -> Result<()> {
48    let req = futu_proto::qot_sub::Request {
49        c2s: futu_proto::qot_sub::C2s {
50            security_list: securities.iter().map(|s| s.to_proto()).collect(),
51            sub_type_list: sub_types.iter().map(|t| *t as i32).collect(),
52            is_sub_or_un_sub: false,
53            is_reg_or_un_reg_push: Some(true),
54            reg_push_rehab_type_list: vec![],
55            is_first_push: None,
56            is_unsub_all: None,
57            is_sub_order_book_detail: None,
58            extended_time: None,
59            session: None,
60        },
61    };
62
63    let body = prost::Message::encode_to_vec(&req);
64    let resp_frame = client.request(proto_id::QOT_SUB, body).await?;
65
66    let resp: futu_proto::qot_sub::Response =
67        prost::Message::decode(resp_frame.body.as_ref()).map_err(FutuError::Proto)?;
68
69    check_ret_type(resp.ret_type, resp.ret_msg)
70}
71
72fn check_ret_type(ret_type: i32, ret_msg: Option<String>) -> Result<()> {
73    if ret_type != 0 {
74        return Err(FutuError::ServerError {
75            ret_type,
76            msg: ret_msg.unwrap_or_default(),
77        });
78    }
79    Ok(())
80}