1use anyhow::Result;
2
3use super::super::commands::{
4 AccCashFlowArgs, CancelOrderArgs, HistoryDealsArgs, HistoryOrdersArgs, MarginRatioArgs,
5 MaxQtysArgs, ModifyOrderArgs, OrderFeeArgs, PlaceOrderArgs, ReconfirmOrderArgs,
6};
7use crate::cmd;
8use crate::output::OutputFormat;
9
10pub(super) struct CancelAllOrderDispatchArgs {
11 pub(super) acc_id: Option<u64>,
12 pub(super) card_num: Option<String>,
13 pub(super) env: String,
14 pub(super) market: Option<String>,
15 pub(super) jp_acc_type: Option<i32>,
16 pub(super) confirm: bool,
17}
18
19fn csv_list(value: Option<String>) -> Vec<String> {
20 value
21 .map(|s| {
22 s.split(',')
23 .map(|x| x.trim().to_string())
24 .filter(|x| !x.is_empty())
25 .collect()
26 })
27 .unwrap_or_default()
28}
29
30pub(super) async fn dispatch_place_order(
31 gateway: &str,
32 output: OutputFormat,
33 args: PlaceOrderArgs,
34) -> Result<()> {
35 let acc_id = cmd::account::resolve_account_locator(
36 gateway,
37 args.acc_id,
38 args.card_num.as_deref(),
39 "place-order",
40 )
41 .await?;
42 cmd::trade_ext::run_place_order(cmd::trade_ext::PlaceOrderCommand {
43 gateway,
44 env: &args.env,
45 acc_id,
46 market: &args.market,
47 side: &args.side,
48 order_type: &args.order_type,
49 code: &args.code,
50 qty: args.qty,
51 price: args.price,
52 time_in_force: args.time_in_force.as_deref(),
53 fill_outside_rth: args.fill_outside_rth,
54 session: args.session.as_deref(),
55 expire_time: args.expire_time.as_deref(),
56 jp_acc_type: args.jp_acc_type,
57 confirm: args.confirm,
58 idempotency_key: args.idempotency_key,
59 stop_price: args.stop_price,
60 trail_type: args.trail_type,
61 trail_value: args.trail_value,
62 trail_spread: args.trail_spread,
63 output,
64 })
65 .await
66}
67
68pub(super) async fn dispatch_modify_order(
69 gateway: &str,
70 output: OutputFormat,
71 args: ModifyOrderArgs,
72) -> Result<()> {
73 let acc_id = cmd::account::resolve_account_locator(
74 gateway,
75 args.acc_id,
76 args.card_num.as_deref(),
77 "modify-order",
78 )
79 .await?;
80 cmd::trade_ext::run_modify_order(cmd::trade_ext::ModifyOrderCommand {
81 gateway,
82 env: &args.env,
83 acc_id,
84 market: &args.market,
85 order_id: args.order_id,
86 op: &args.op,
87 qty: args.qty,
88 price: args.price,
89 jp_acc_type: args.jp_acc_type,
90 confirm: args.confirm,
91 idempotency_key: args.idempotency_key,
92 output,
93 })
94 .await
95}
96
97pub(super) async fn dispatch_cancel_order(
98 gateway: &str,
99 output: OutputFormat,
100 args: CancelOrderArgs,
101) -> Result<()> {
102 let acc_id = cmd::account::resolve_account_locator(
103 gateway,
104 args.acc_id,
105 args.card_num.as_deref(),
106 "cancel-order",
107 )
108 .await?;
109 cmd::trade_ext::run_cancel_order(cmd::trade_ext::CancelOrderCommand {
110 gateway,
111 env: &args.env,
112 acc_id,
113 market: &args.market,
114 order_id: args.order_id,
115 jp_acc_type: args.jp_acc_type,
116 confirm: args.confirm,
117 idempotency_key: args.idempotency_key,
118 output,
119 })
120 .await
121}
122
123pub(super) async fn dispatch_reconfirm_order(
124 gateway: &str,
125 output: OutputFormat,
126 args: ReconfirmOrderArgs,
127) -> Result<()> {
128 let acc_id = cmd::account::resolve_account_locator(
129 gateway,
130 args.acc_id,
131 args.card_num.as_deref(),
132 "reconfirm-order",
133 )
134 .await?;
135 cmd::trade_ext::run_reconfirm_order(cmd::trade_ext::ReconfirmOrderCommand {
136 gateway,
137 env: &args.env,
138 acc_id,
139 market: &args.market,
140 order_id: args.order_id,
141 reason: args.reason,
142 jp_acc_type: args.jp_acc_type,
143 confirm: args.confirm,
144 output,
145 })
146 .await
147}
148
149pub(super) async fn dispatch_history_orders(
150 gateway: &str,
151 output: OutputFormat,
152 args: HistoryOrdersArgs,
153) -> Result<()> {
154 let acc_id = cmd::account::resolve_account_locator(
155 gateway,
156 args.acc_id,
157 args.card_num.as_deref(),
158 "history-orders",
159 )
160 .await?;
161 cmd::trade_ext::run_history_orders(cmd::trade_ext::HistoryOrdersCommand {
162 gateway,
163 env: &args.env,
164 acc_id,
165 market: &args.market,
166 codes: csv_list(args.codes),
167 begin: args.begin,
168 end: args.end,
169 output,
170 })
171 .await
172}
173
174pub(super) async fn dispatch_history_deals(
175 gateway: &str,
176 output: OutputFormat,
177 args: HistoryDealsArgs,
178) -> Result<()> {
179 let acc_id = cmd::account::resolve_account_locator(
180 gateway,
181 args.acc_id,
182 args.card_num.as_deref(),
183 "history-deals",
184 )
185 .await?;
186 cmd::trade_ext::run_history_deals(cmd::trade_ext::HistoryDealsCommand {
187 gateway,
188 env: &args.env,
189 acc_id,
190 market: &args.market,
191 codes: csv_list(args.codes),
192 begin: args.begin,
193 end: args.end,
194 output,
195 })
196 .await
197}
198
199pub(super) async fn dispatch_max_qtys(
200 gateway: &str,
201 output: OutputFormat,
202 args: MaxQtysArgs,
203) -> Result<()> {
204 let acc_id = cmd::account::resolve_account_locator(
205 gateway,
206 args.acc_id,
207 args.card_num.as_deref(),
208 "max-trd-qtys",
209 )
210 .await?;
211 cmd::trade_ext::run_max_qtys(cmd::trade_ext::MaxQtysCommand {
212 gateway,
213 env: &args.env,
214 acc_id,
215 market: &args.market,
216 order_type: &args.order_type,
217 code: &args.code,
218 price: args.price,
219 jp_acc_type: args.jp_acc_type,
220 output,
221 })
222 .await
223}
224
225pub(super) async fn dispatch_margin_ratio(
226 gateway: &str,
227 output: OutputFormat,
228 args: MarginRatioArgs,
229) -> Result<()> {
230 let acc_id = cmd::account::resolve_account_locator(
231 gateway,
232 args.acc_id,
233 args.card_num.as_deref(),
234 "margin-ratio",
235 )
236 .await?;
237 let symbols = args.symbols.or(args.symbols_arg).ok_or_else(|| {
238 anyhow::anyhow!("margin-ratio: 需要位置参数 <SYMBOLS> 或 --code / --symbols")
239 })?;
240 let syms: Vec<String> = symbols.split(',').map(|s| s.trim().to_string()).collect();
241 cmd::trade_ext::run_margin_ratio(gateway, &args.env, acc_id, &args.market, &syms, output).await
242}
243
244pub(super) async fn dispatch_order_fee(
245 gateway: &str,
246 output: OutputFormat,
247 args: OrderFeeArgs,
248) -> Result<()> {
249 let acc_id = cmd::account::resolve_account_locator(
250 gateway,
251 args.acc_id,
252 args.card_num.as_deref(),
253 "order-fee",
254 )
255 .await?;
256 let ids: Vec<String> = args
257 .order_ids
258 .split(',')
259 .map(|s| s.trim().to_string())
260 .collect();
261 cmd::trade_ext::run_order_fee(gateway, &args.env, acc_id, &args.market, &ids, output).await
262}
263
264pub(super) async fn dispatch_cancel_all_order(
265 gateway: &str,
266 output: OutputFormat,
267 args: CancelAllOrderDispatchArgs,
268) -> Result<()> {
269 let acc_id = cmd::account::resolve_account_locator(
270 gateway,
271 args.acc_id,
272 args.card_num.as_deref(),
273 "cancel-all-order",
274 )
275 .await?;
276 cmd::trade_ext::run_cancel_all_order(
277 gateway,
278 acc_id,
279 &args.env,
280 args.market.as_deref(),
281 args.jp_acc_type,
282 args.confirm,
283 output,
284 )
285 .await
286}
287
288pub(super) async fn dispatch_acc_cash_flow(
289 gateway: &str,
290 output: OutputFormat,
291 args: AccCashFlowArgs,
292) -> Result<()> {
293 let acc_id = cmd::account::resolve_account_locator(
294 gateway,
295 args.acc_id.or(args.acc_id_arg),
296 args.card_num.as_deref(),
297 "acc-cash-flow",
298 )
299 .await?;
300 if let Some(range) = args.date_range {
302 let (from_s, to_s) = range.split_once("..").ok_or_else(|| {
304 anyhow::anyhow!("--date-range 格式应为 `YYYY-MM-DD..YYYY-MM-DD`,当前:{range}")
305 })?;
306 let from = chrono::NaiveDate::parse_from_str(from_s, "%Y-%m-%d")
307 .map_err(|e| anyhow::anyhow!("start date parse: {e}"))?;
308 let to = chrono::NaiveDate::parse_from_str(to_s, "%Y-%m-%d")
309 .map_err(|e| anyhow::anyhow!("end date parse: {e}"))?;
310 cmd::trade_ext::run_acc_cash_flow_range(cmd::trade_ext::AccCashFlowRangeCommand {
311 gateway,
312 acc_id,
313 date_from: from,
314 date_to: to,
315 env: &args.env,
316 market: &args.market,
317 direction: args.direction,
318 })
319 .await
320 } else if let Some(d) = args.date {
321 cmd::trade_ext::run_acc_cash_flow(
322 gateway,
323 acc_id,
324 &d,
325 &args.env,
326 &args.market,
327 args.direction,
328 output,
329 )
330 .await
331 } else {
332 anyhow::bail!("需传 --date <YYYY-MM-DD> 或 --date-range <FROM..TO>")
333 }
334}