Skip to main content

futu_trd/
query.rs

1use futu_core::error::{FutuError, Result};
2use futu_core::proto_id;
3use futu_net::client::FutuClient;
4
5use crate::types::TrdHeader;
6
7/// 订单信息
8#[derive(Debug, Clone)]
9pub struct Order {
10    pub order_id: u64,
11    pub order_id_ex: String,
12    pub trd_side: i32,
13    pub order_type: i32,
14    pub order_status: i32,
15    pub code: String,
16    pub name: String,
17    pub qty: f64,
18    pub price: f64,
19    pub create_time: String,
20    pub update_time: String,
21    pub fill_qty: f64,
22    pub fill_avg_price: f64,
23    pub last_err_msg: String,
24}
25
26impl Order {
27    pub fn from_proto(o: &futu_proto::trd_common::Order) -> Self {
28        Self {
29            order_id: o.order_id,
30            order_id_ex: o.order_id_ex.clone(),
31            trd_side: o.trd_side,
32            order_type: o.order_type,
33            order_status: o.order_status,
34            code: o.code.clone(),
35            name: o.name.clone(),
36            qty: o.qty,
37            price: o.price.unwrap_or(0.0),
38            create_time: o.create_time.clone(),
39            update_time: o.update_time.clone(),
40            fill_qty: o.fill_qty.unwrap_or(0.0),
41            fill_avg_price: o.fill_avg_price.unwrap_or(0.0),
42            last_err_msg: o.last_err_msg.clone().unwrap_or_default(),
43        }
44    }
45}
46
47/// 成交信息
48#[derive(Debug, Clone)]
49pub struct OrderFill {
50    pub fill_id: u64,
51    pub fill_id_ex: String,
52    pub order_id: u64,
53    pub trd_side: i32,
54    pub code: String,
55    pub name: String,
56    pub qty: f64,
57    pub price: f64,
58    pub create_time: String,
59}
60
61impl OrderFill {
62    pub fn from_proto(f: &futu_proto::trd_common::OrderFill) -> Result<Self> {
63        let order_id = f.order_id.ok_or_else(|| {
64            FutuError::Codec(
65                "missing orderID in OrderFill; C++ _APIServer_Trd_Comm.cpp:2145-2151 \
66                 sets orderID before sending FTAPI OrderFill"
67                    .into(),
68            )
69        })?;
70
71        Ok(Self {
72            fill_id: f.fill_id,
73            fill_id_ex: f.fill_id_ex.clone(),
74            order_id,
75            trd_side: f.trd_side,
76            code: f.code.clone(),
77            name: f.name.clone(),
78            qty: f.qty,
79            price: f.price,
80            create_time: f.create_time.clone(),
81        })
82    }
83}
84
85/// 查询当日订单列表
86pub async fn get_order_list(client: &FutuClient, header: &TrdHeader) -> Result<Vec<Order>> {
87    let req = futu_proto::trd_get_order_list::Request {
88        c2s: futu_proto::trd_get_order_list::C2s {
89            header: header.to_proto(),
90            filter_conditions: None,
91            filter_status_list: vec![],
92            refresh_cache: None,
93        },
94    };
95
96    let body = prost::Message::encode_to_vec(&req);
97    let resp_frame = client.request(proto_id::TRD_GET_ORDER_LIST, body).await?;
98
99    let resp: futu_proto::trd_get_order_list::Response =
100        prost::Message::decode(resp_frame.body.as_ref()).map_err(FutuError::Proto)?;
101
102    if resp.ret_type != 0 {
103        return Err(crate::server_err(
104            resp.ret_type,
105            resp.ret_msg,
106            resp.err_code,
107        ));
108    }
109
110    let s2c = resp
111        .s2c
112        .ok_or(FutuError::Codec("missing s2c in GetOrderList".into()))?;
113
114    Ok(s2c.order_list.iter().map(Order::from_proto).collect())
115}
116
117/// 查询当日成交列表
118pub async fn get_order_fill_list(
119    client: &FutuClient,
120    header: &TrdHeader,
121) -> Result<Vec<OrderFill>> {
122    let req = futu_proto::trd_get_order_fill_list::Request {
123        c2s: futu_proto::trd_get_order_fill_list::C2s {
124            header: header.to_proto(),
125            filter_conditions: None,
126            refresh_cache: None,
127        },
128    };
129
130    let body = prost::Message::encode_to_vec(&req);
131    let resp_frame = client
132        .request(proto_id::TRD_GET_ORDER_FILL_LIST, body)
133        .await?;
134
135    let resp: futu_proto::trd_get_order_fill_list::Response =
136        prost::Message::decode(resp_frame.body.as_ref()).map_err(FutuError::Proto)?;
137
138    if resp.ret_type != 0 {
139        return Err(crate::server_err(
140            resp.ret_type,
141            resp.ret_msg,
142            resp.err_code,
143        ));
144    }
145
146    let s2c = resp
147        .s2c
148        .ok_or(FutuError::Codec("missing s2c in GetOrderFillList".into()))?;
149
150    s2c.order_fill_list
151        .iter()
152        .map(OrderFill::from_proto)
153        .collect()
154}
155
156#[cfg(test)]
157mod tests;