1use std::sync::Arc;
5
6use anyhow::Result;
7use futu_net::client::FutuClient;
8use serde::Serialize;
9
10use super::helpers::*;
11
12#[derive(Serialize)]
13struct OrderOut {
14 order_id: u64,
15 order_id_ex: String,
16 trd_side: i32,
17 order_type: i32,
18 order_status: i32,
19 code: String,
20 name: String,
21 qty: f64,
22 price: f64,
23 fill_qty: f64,
24 fill_avg_price: f64,
25 create_time: String,
26 update_time: String,
27 last_err_msg: String,
28}
29
30pub async fn get_orders(
31 client: &Arc<FutuClient>,
32 env: &str,
33 acc_id: u64,
34 market: &str,
35) -> Result<String> {
36 let header = build_header_strict_no_fund(env, acc_id, market)?;
37 let list = futu_trd::query::get_order_list(client, &header).await?;
38 let out: Vec<OrderOut> = list
39 .iter()
40 .map(|o| OrderOut {
41 order_id: o.order_id,
42 order_id_ex: o.order_id_ex.clone(),
43 trd_side: o.trd_side,
44 order_type: o.order_type,
45 order_status: o.order_status,
46 code: o.code.clone(),
47 name: o.name.clone(),
48 qty: o.qty,
49 price: o.price,
50 fill_qty: o.fill_qty,
51 fill_avg_price: o.fill_avg_price,
52 create_time: o.create_time.clone(),
53 update_time: o.update_time.clone(),
54 last_err_msg: o.last_err_msg.clone(),
55 })
56 .collect();
57 Ok(serde_json::to_string_pretty(&out)?)
58}
59
60#[derive(Serialize)]
61struct DealOut {
62 fill_id: u64,
63 fill_id_ex: String,
64 order_id: u64,
65 trd_side: i32,
66 code: String,
67 name: String,
68 qty: f64,
69 price: f64,
70 create_time: String,
71}
72
73pub async fn get_deals(
74 client: &Arc<FutuClient>,
75 env: &str,
76 acc_id: u64,
77 market: &str,
78) -> Result<String> {
79 let header = build_header_strict_no_fund(env, acc_id, market)?;
80 let list = futu_trd::query::get_order_fill_list(client, &header).await?;
81 let out: Vec<DealOut> = list
82 .iter()
83 .map(|f| DealOut {
84 fill_id: f.fill_id,
85 fill_id_ex: f.fill_id_ex.clone(),
86 order_id: f.order_id,
87 trd_side: f.trd_side,
88 code: f.code.clone(),
89 name: f.name.clone(),
90 qty: f.qty,
91 price: f.price,
92 create_time: f.create_time.clone(),
93 })
94 .collect();
95 Ok(serde_json::to_string_pretty(&out)?)
96}
97
98#[derive(Serialize)]
101struct MaxQtysOut {
102 max_cash_buy: f64,
103 max_cash_and_margin_buy: f64,
104 max_position_sell: f64,
105 max_sell_short: f64,
106 max_buy_back: f64,
107 long_required_im: f64,
109 short_required_im: f64,
111}
112
113pub struct MaxTrdQtysInput<'a> {
119 pub env: &'a str,
120 pub acc_id: u64,
121 pub market: &'a str,
122 pub order_type: i32,
123 pub code: &'a str,
124 pub price: f64,
125 pub order_id: Option<u64>,
126}
127
128pub async fn get_max_trd_qtys(
129 client: &Arc<FutuClient>,
130 input: MaxTrdQtysInput<'_>,
131) -> Result<String> {
132 let header = build_header_strict_no_fund(input.env, input.acc_id, input.market)?;
133 let params = futu_trd::misc::MaxTrdQtysParams {
134 header,
135 order_type: input.order_type,
136 code: input.code.to_string(),
137 price: input.price,
138 order_id: input.order_id,
139 };
140 let s2c = futu_trd::misc::get_max_trd_qtys(client, ¶ms).await?;
141 let q = s2c
142 .max_trd_qtys
143 .ok_or_else(|| anyhow::anyhow!("missing max_trd_qtys in response"))?;
144 let out = MaxQtysOut {
145 max_cash_buy: q.max_cash_buy,
146 max_cash_and_margin_buy: q.max_cash_and_margin_buy.unwrap_or(0.0),
147 max_position_sell: q.max_position_sell,
148 max_sell_short: q.max_sell_short.unwrap_or(0.0),
149 max_buy_back: q.max_buy_back.unwrap_or(0.0),
150 long_required_im: q.long_required_im.unwrap_or(0.0),
151 short_required_im: q.short_required_im.unwrap_or(0.0),
152 };
153 Ok(serde_json::to_string_pretty(&out)?)
154}
155
156#[derive(Serialize)]
157struct OrderFeeItemOut {
158 title: String,
159 value: f64,
160}
161
162#[derive(Serialize)]
163struct OrderFeeOut {
164 order_id_ex: String,
165 fee_amount: f64,
166 fee_list: Vec<OrderFeeItemOut>,
167}
168
169pub async fn get_order_fee(
173 client: &Arc<FutuClient>,
174 env: &str,
175 acc_id: u64,
176 market: &str,
177 order_id_ex_list: &[String],
178) -> Result<String> {
179 let header = build_header_strict_no_fund(env, acc_id, market)?;
180 let list = futu_trd::misc::get_order_fee(client, &header, order_id_ex_list).await?;
181 let out: Vec<OrderFeeOut> = list
182 .into_iter()
183 .map(|f| OrderFeeOut {
184 order_id_ex: f.order_id_ex,
185 fee_amount: f.fee_amount,
186 fee_list: f
187 .fee_list
188 .into_iter()
189 .map(|i| OrderFeeItemOut {
190 title: i.title,
191 value: i.value,
192 })
193 .collect(),
194 })
195 .collect();
196 Ok(serde_json::to_string_pretty(&out)?)
197}
198
199#[derive(Serialize)]
200struct HistoryOrderOut {
201 order_id: u64,
202 order_id_ex: String,
203 trd_side: i32,
204 order_type: i32,
205 order_status: i32,
206 code: String,
207 name: String,
208 qty: f64,
209 price: f64,
210 fill_qty: f64,
211 fill_avg_price: f64,
212 create_time: String,
213 update_time: String,
214}
215
216pub struct HistoryQueryInput<'a> {
219 pub env: &'a str,
220 pub acc_id: u64,
221 pub market: &'a str,
222 pub code_list: Vec<String>,
223 pub begin_time: Option<String>,
224 pub end_time: Option<String>,
225}
226
227pub async fn get_history_orders(
228 client: &Arc<FutuClient>,
229 input: HistoryQueryInput<'_>,
230) -> Result<String> {
231 let header = build_header(input.env, input.acc_id, input.market)?;
232 let filter = futu_trd::misc::HistoryFilterConditions {
233 code_list: input.code_list,
234 id_list: vec![],
235 begin_time: input.begin_time,
236 end_time: input.end_time,
237 filter_market: Some(header.trd_market as i32),
238 };
239 let list = futu_trd::misc::get_history_order_list(client, &header, &filter).await?;
240 let out: Vec<HistoryOrderOut> = list
241 .iter()
242 .map(|o| HistoryOrderOut {
243 order_id: o.order_id,
244 order_id_ex: o.order_id_ex.clone(),
245 trd_side: o.trd_side,
246 order_type: o.order_type,
247 order_status: o.order_status,
248 code: o.code.clone(),
249 name: o.name.clone(),
250 qty: o.qty,
251 price: o.price,
252 fill_qty: o.fill_qty,
253 fill_avg_price: o.fill_avg_price,
254 create_time: o.create_time.clone(),
255 update_time: o.update_time.clone(),
256 })
257 .collect();
258 Ok(serde_json::to_string_pretty(&out)?)
259}