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