1use futu_core::error::{FutuError, Result};
2use futu_core::proto_id;
3use futu_net::client::FutuClient;
4
5use crate::types::TrdHeader;
6
7#[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#[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) -> Self {
63 Self {
64 fill_id: f.fill_id,
65 fill_id_ex: f.fill_id_ex.clone(),
66 order_id: f.order_id.unwrap_or(0),
67 trd_side: f.trd_side,
68 code: f.code.clone(),
69 name: f.name.clone(),
70 qty: f.qty,
71 price: f.price,
72 create_time: f.create_time.clone(),
73 }
74 }
75}
76
77pub async fn get_order_list(client: &FutuClient, header: &TrdHeader) -> Result<Vec<Order>> {
79 let req = futu_proto::trd_get_order_list::Request {
80 c2s: futu_proto::trd_get_order_list::C2s {
81 header: header.to_proto(),
82 filter_conditions: None,
83 filter_status_list: vec![],
84 refresh_cache: None,
85 },
86 };
87
88 let body = prost::Message::encode_to_vec(&req);
89 let resp_frame = client.request(proto_id::TRD_GET_ORDER_LIST, body).await?;
90
91 let resp: futu_proto::trd_get_order_list::Response =
92 prost::Message::decode(resp_frame.body.as_ref()).map_err(FutuError::Proto)?;
93
94 if resp.ret_type != 0 {
95 return Err(FutuError::ServerError {
96 ret_type: resp.ret_type,
97 msg: resp.ret_msg.unwrap_or_default(),
98 });
99 }
100
101 let s2c = resp
102 .s2c
103 .ok_or(FutuError::Codec("missing s2c in GetOrderList".into()))?;
104
105 Ok(s2c.order_list.iter().map(Order::from_proto).collect())
106}
107
108pub async fn get_order_fill_list(
110 client: &FutuClient,
111 header: &TrdHeader,
112) -> Result<Vec<OrderFill>> {
113 let req = futu_proto::trd_get_order_fill_list::Request {
114 c2s: futu_proto::trd_get_order_fill_list::C2s {
115 header: header.to_proto(),
116 filter_conditions: None,
117 refresh_cache: None,
118 },
119 };
120
121 let body = prost::Message::encode_to_vec(&req);
122 let resp_frame = client
123 .request(proto_id::TRD_GET_ORDER_FILL_LIST, body)
124 .await?;
125
126 let resp: futu_proto::trd_get_order_fill_list::Response =
127 prost::Message::decode(resp_frame.body.as_ref()).map_err(FutuError::Proto)?;
128
129 if resp.ret_type != 0 {
130 return Err(FutuError::ServerError {
131 ret_type: resp.ret_type,
132 msg: resp.ret_msg.unwrap_or_default(),
133 });
134 }
135
136 let s2c = resp
137 .s2c
138 .ok_or(FutuError::Codec("missing s2c in GetOrderFillList".into()))?;
139
140 Ok(s2c
141 .order_fill_list
142 .iter()
143 .map(OrderFill::from_proto)
144 .collect())
145}