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 jp_acc_type: Option<i32>,
126 pub order_id: Option<u64>,
127}
128
129pub async fn get_max_trd_qtys(
130 client: &Arc<FutuClient>,
131 input: MaxTrdQtysInput<'_>,
132) -> Result<String> {
133 let header = build_header_strict_no_fund_with_jp_acc_type(
134 input.env,
135 input.acc_id,
136 input.market,
137 input.jp_acc_type,
138 )?;
139 let params = futu_trd::misc::MaxTrdQtysParams {
140 header,
141 order_type: input.order_type,
142 code: input.code.to_string(),
143 price: input.price,
144 order_id: input.order_id,
145 };
146 let s2c = futu_trd::misc::get_max_trd_qtys(client, ¶ms).await?;
147 let q = s2c
148 .max_trd_qtys
149 .ok_or_else(|| anyhow::anyhow!("missing max_trd_qtys in response"))?;
150 let out = MaxQtysOut {
151 max_cash_buy: q.max_cash_buy,
152 max_cash_and_margin_buy: q.max_cash_and_margin_buy.unwrap_or(0.0),
153 max_position_sell: q.max_position_sell,
154 max_sell_short: q.max_sell_short.unwrap_or(0.0),
155 max_buy_back: q.max_buy_back.unwrap_or(0.0),
156 long_required_im: q.long_required_im.unwrap_or(0.0),
157 short_required_im: q.short_required_im.unwrap_or(0.0),
158 };
159 Ok(serde_json::to_string_pretty(&out)?)
160}
161
162#[derive(Serialize)]
163struct OrderFeeItemOut {
164 title: String,
165 value: f64,
166}
167
168#[derive(Serialize)]
169struct OrderFeeOut {
170 order_id_ex: String,
171 fee_amount: f64,
172 fee_list: Vec<OrderFeeItemOut>,
173}
174
175pub async fn get_order_fee(
179 client: &Arc<FutuClient>,
180 env: &str,
181 acc_id: u64,
182 market: &str,
183 order_id_ex_list: &[String],
184) -> Result<String> {
185 let header = build_header_strict_no_fund(env, acc_id, market)?;
186 let list = futu_trd::misc::get_order_fee(client, &header, order_id_ex_list).await?;
187 let out: Vec<OrderFeeOut> = list
188 .into_iter()
189 .map(|f| OrderFeeOut {
190 order_id_ex: f.order_id_ex,
191 fee_amount: f.fee_amount,
192 fee_list: f
193 .fee_list
194 .into_iter()
195 .map(|i| OrderFeeItemOut {
196 title: i.title,
197 value: i.value,
198 })
199 .collect(),
200 })
201 .collect();
202 Ok(serde_json::to_string_pretty(&out)?)
203}
204
205#[derive(Serialize)]
206struct HistoryOrderOut {
207 order_id: u64,
208 order_id_ex: String,
209 trd_side: i32,
210 order_type: i32,
211 order_status: i32,
212 code: String,
213 name: String,
214 qty: f64,
215 price: f64,
216 fill_qty: f64,
217 fill_avg_price: f64,
218 create_time: String,
219 update_time: String,
220}
221
222pub struct HistoryQueryInput<'a> {
225 pub env: &'a str,
226 pub acc_id: u64,
227 pub market: &'a str,
228 pub code_list: Vec<String>,
229 pub begin_time: Option<String>,
230 pub end_time: Option<String>,
231}
232
233pub async fn get_history_orders(
234 client: &Arc<FutuClient>,
235 input: HistoryQueryInput<'_>,
236) -> Result<String> {
237 let header = build_header(input.env, input.acc_id, input.market)?;
238 let filter = futu_trd::misc::HistoryFilterConditions {
239 code_list: input.code_list,
240 id_list: vec![],
241 begin_time: input.begin_time,
242 end_time: input.end_time,
243 filter_market: Some(header.trd_market as i32),
244 };
245 let list = futu_trd::misc::get_history_order_list(client, &header, &filter).await?;
246 let out: Vec<HistoryOrderOut> = list
247 .iter()
248 .map(|o| HistoryOrderOut {
249 order_id: o.order_id,
250 order_id_ex: o.order_id_ex.clone(),
251 trd_side: o.trd_side,
252 order_type: o.order_type,
253 order_status: o.order_status,
254 code: o.code.clone(),
255 name: o.name.clone(),
256 qty: o.qty,
257 price: o.price,
258 fill_qty: o.fill_qty,
259 fill_avg_price: o.fill_avg_price,
260 create_time: o.create_time.clone(),
261 update_time: o.update_time.clone(),
262 })
263 .collect();
264 Ok(serde_json::to_string_pretty(&out)?)
265}