1use anyhow::Result;
2
3use super::Command;
4use crate::cmd;
5use crate::common::parse_symbol_csv;
6use crate::output::OutputFormat;
7
8mod account;
9mod daemon;
10mod qot;
11mod tier_m;
12mod trade_read;
13
14pub async fn dispatch(gateway: &str, output: OutputFormat, command: Command) -> Result<()> {
19 match command {
20 Command::Ping => cmd::ping::run(gateway, output).await,
21 Command::Quote(args) => qot::dispatch_quote(gateway, output, args).await,
22 Command::Snapshot(args) => qot::dispatch_snapshot(gateway, output, args).await,
23 Command::Sub(args) => qot::dispatch_sub(gateway, output, args).await,
24 Command::Kline(args) => qot::dispatch_kline(gateway, output, args).await,
25 Command::Orderbook(args) => qot::dispatch_orderbook(gateway, output, args).await,
26 Command::Ticker(args) => qot::dispatch_ticker(gateway, output, args).await,
27 Command::Rt(args) => qot::dispatch_rt(gateway, output, args).await,
28 Command::Static(args) => qot::dispatch_static(gateway, output, args).await,
29 Command::Broker(args) => qot::dispatch_broker(gateway, output, args).await,
30 Command::PlateList(args) => qot::dispatch_plate_list(gateway, output, args).await,
31 Command::PlateStocks(args) => qot::dispatch_plate_stocks(gateway, output, args).await,
32 Command::OptionQuote(args) => qot::dispatch_option_quote(gateway, output, args).await,
33 Command::OptionStrategy(args) => qot::dispatch_option_strategy(gateway, output, args).await,
34 Command::OptionStrategyAnalysis(args) => {
35 qot::dispatch_option_strategy_analysis(gateway, output, args).await
36 }
37 Command::OptionStrategySpread(args) => {
38 qot::dispatch_option_strategy_spread(gateway, output, args).await
39 }
40 Command::Account {
41 market,
42 security_firm,
43 all,
44 } => account::dispatch_account(gateway, output, market, security_firm, all).await,
45 Command::Funds(args) => trade_read::dispatch_funds(gateway, output, args).await,
46 Command::Position(args) => trade_read::dispatch_position(gateway, output, args).await,
47 Command::Order(args) => trade_read::dispatch_order(gateway, output, args).await,
48 Command::Deal(args) => trade_read::dispatch_deal(gateway, output, args).await,
49 Command::ComboMaxTrdQtys(args) => {
50 trade_read::dispatch_combo_max_trd_qtys(gateway, output, args).await
51 }
52 Command::UnlockTrade {
53 lock,
54 from_stdin,
55 otp,
56 security_firm,
57 acc_ids,
58 } => {
59 cmd::unlock::run(
60 gateway,
61 lock,
62 from_stdin,
63 otp,
64 security_firm,
65 acc_ids,
66 output,
67 )
68 .await
69 }
70 Command::SetTradePwd {
71 account,
72 from_stdin,
73 } => cmd::unlock::set_trade_pwd(&account, from_stdin).await,
74 Command::ClearTradePwd { account } => cmd::unlock::clear_trade_pwd(&account).await,
75 Command::SetLoginPwd {
76 account,
77 from_stdin,
78 } => cmd::unlock::set_login_pwd(&account, from_stdin).await,
79 Command::ClearLoginPwd { account } => cmd::unlock::clear_login_pwd(&account).await,
80 Command::Repl => {
81 anyhow::bail!(
84 "cannot enter REPL from this context (already nested / not a top-level invocation)"
85 )
86 }
87 Command::GenKey(args) => {
88 cmd::gen_key::run(cmd::gen_key::GenKeyCommand {
89 id: args.id,
90 scopes: args.scopes,
91 keys_file: args.keys_file,
92 expires: args.expires,
93 note: args.note,
94 allowed_markets: args.allowed_markets,
95 allowed_symbols: args.allowed_symbols,
96 max_order_value: args.max_order_value,
97 max_daily_value: args.max_daily_value,
98 hours_window: args.hours_window,
99 max_orders_per_minute: args.max_orders_per_minute,
100 allowed_trd_sides: args.allowed_trd_sides,
101 allowed_acc_ids: args.allowed_acc_ids,
102 allowed_card_nums: args.allowed_card_nums,
103 bind_this_machine: args.bind_this_machine,
104 bind_machines: args.bind_machines,
105 })
106 .await
107 }
108 Command::BindKey(args) => {
109 cmd::bind_key::run(cmd::bind_key::BindKeyCommand {
110 id: args.id,
111 keys_file: args.keys_file,
112 this_machine: args.this_machine,
113 machines: args.machines,
114 replace: args.replace,
115 clear: args.clear,
116 freeze: args.freeze,
117 })
118 .await
119 }
120 Command::MachineId(args) => cmd::machine::run(args.for_key).await,
121 Command::ListKeys(args) => cmd::keys::list(args.keys_file, args.json).await,
122 Command::RevokeKey(args) => cmd::keys::revoke(args.id, args.keys_file, args.yes).await,
123
124 Command::PlaceOrder(args) => {
126 let acc_id = cmd::account::resolve_account_locator(
127 gateway,
128 args.acc_id,
129 args.card_num.as_deref(),
130 "place-order",
131 )
132 .await?;
133 cmd::trade_ext::run_place_order(cmd::trade_ext::PlaceOrderCommand {
134 gateway,
135 env: &args.env,
136 acc_id,
137 market: &args.market,
138 side: &args.side,
139 order_type: &args.order_type,
140 code: &args.code,
141 qty: args.qty,
142 price: args.price,
143 jp_acc_type: args.jp_acc_type,
144 confirm: args.confirm,
145 idempotency_key: args.idempotency_key,
146 stop_price: args.stop_price,
147 trail_type: args.trail_type,
148 trail_value: args.trail_value,
149 trail_spread: args.trail_spread,
150 output,
151 })
152 .await
153 }
154 Command::ModifyOrder(args) => {
155 let acc_id = cmd::account::resolve_account_locator(
156 gateway,
157 args.acc_id,
158 args.card_num.as_deref(),
159 "modify-order",
160 )
161 .await?;
162 cmd::trade_ext::run_modify_order(cmd::trade_ext::ModifyOrderCommand {
163 gateway,
164 env: &args.env,
165 acc_id,
166 market: &args.market,
167 order_id: args.order_id,
168 op: &args.op,
169 qty: args.qty,
170 price: args.price,
171 jp_acc_type: args.jp_acc_type,
172 confirm: args.confirm,
173 idempotency_key: args.idempotency_key,
174 output,
175 })
176 .await
177 }
178 Command::CancelOrder(args) => {
179 let acc_id = cmd::account::resolve_account_locator(
180 gateway,
181 args.acc_id,
182 args.card_num.as_deref(),
183 "cancel-order",
184 )
185 .await?;
186 cmd::trade_ext::run_cancel_order(cmd::trade_ext::CancelOrderCommand {
187 gateway,
188 env: &args.env,
189 acc_id,
190 market: &args.market,
191 order_id: args.order_id,
192 jp_acc_type: args.jp_acc_type,
193 confirm: args.confirm,
194 idempotency_key: args.idempotency_key,
195 output,
196 })
197 .await
198 }
199 Command::ReconfirmOrder(args) => {
200 let acc_id = cmd::account::resolve_account_locator(
201 gateway,
202 args.acc_id,
203 args.card_num.as_deref(),
204 "reconfirm-order",
205 )
206 .await?;
207 cmd::trade_ext::run_reconfirm_order(cmd::trade_ext::ReconfirmOrderCommand {
208 gateway,
209 env: &args.env,
210 acc_id,
211 market: &args.market,
212 order_id: args.order_id,
213 reason: args.reason,
214 jp_acc_type: args.jp_acc_type,
215 confirm: args.confirm,
216 output,
217 })
218 .await
219 }
220 Command::HistoryOrders(args) => {
221 let acc_id = cmd::account::resolve_account_locator(
222 gateway,
223 args.acc_id,
224 args.card_num.as_deref(),
225 "history-orders",
226 )
227 .await?;
228 let code_list = args
229 .codes
230 .map(|s| {
231 s.split(',')
232 .map(|x| x.trim().to_string())
233 .filter(|x| !x.is_empty())
234 .collect()
235 })
236 .unwrap_or_default();
237 cmd::trade_ext::run_history_orders(cmd::trade_ext::HistoryOrdersCommand {
238 gateway,
239 env: &args.env,
240 acc_id,
241 market: &args.market,
242 codes: code_list,
243 begin: args.begin,
244 end: args.end,
245 output,
246 })
247 .await
248 }
249 Command::HistoryDeals(args) => {
250 let acc_id = cmd::account::resolve_account_locator(
251 gateway,
252 args.acc_id,
253 args.card_num.as_deref(),
254 "history-deals",
255 )
256 .await?;
257 let code_list = args
258 .codes
259 .map(|s| {
260 s.split(',')
261 .map(|x| x.trim().to_string())
262 .filter(|x| !x.is_empty())
263 .collect()
264 })
265 .unwrap_or_default();
266 cmd::trade_ext::run_history_deals(cmd::trade_ext::HistoryDealsCommand {
267 gateway,
268 env: &args.env,
269 acc_id,
270 market: &args.market,
271 codes: code_list,
272 begin: args.begin,
273 end: args.end,
274 output,
275 })
276 .await
277 }
278 Command::MaxQtys(args) => {
279 let acc_id = cmd::account::resolve_account_locator(
280 gateway,
281 args.acc_id,
282 args.card_num.as_deref(),
283 "max-trd-qtys",
284 )
285 .await?;
286 cmd::trade_ext::run_max_qtys(cmd::trade_ext::MaxQtysCommand {
287 gateway,
288 env: &args.env,
289 acc_id,
290 market: &args.market,
291 order_type: &args.order_type,
292 code: &args.code,
293 price: args.price,
294 jp_acc_type: args.jp_acc_type,
295 output,
296 })
297 .await
298 }
299 Command::ComboOrder(args) => {
300 cmd::proto_json::run_place_combo_order(
301 gateway,
302 &args.c2s_json,
303 args.confirm,
304 args.idempotency_key,
305 output,
306 )
307 .await
308 }
309 Command::MarginRatio(args) => {
311 let acc_id = cmd::account::resolve_account_locator(
312 gateway,
313 args.acc_id,
314 args.card_num.as_deref(),
315 "margin-ratio",
316 )
317 .await?;
318 let symbols = args.symbols.or(args.symbols_arg).ok_or_else(|| {
319 anyhow::anyhow!("margin-ratio: 需要位置参数 <SYMBOLS> 或 --code / --symbols")
320 })?;
321 let syms: Vec<String> = symbols.split(',').map(|s| s.trim().to_string()).collect();
322 cmd::trade_ext::run_margin_ratio(
323 gateway,
324 &args.env,
325 acc_id,
326 &args.market,
327 &syms,
328 output,
329 )
330 .await
331 }
332 Command::OrderFee(args) => {
333 let acc_id = cmd::account::resolve_account_locator(
334 gateway,
335 args.acc_id,
336 args.card_num.as_deref(),
337 "order-fee",
338 )
339 .await?;
340 let ids: Vec<String> = args
341 .order_ids
342 .split(',')
343 .map(|s| s.trim().to_string())
344 .collect();
345 cmd::trade_ext::run_order_fee(gateway, &args.env, acc_id, &args.market, &ids, output)
346 .await
347 }
348 Command::CapitalFlow(args) => qot::dispatch_capital_flow(gateway, output, args).await,
349 Command::CapitalDistribution { symbol } => {
350 cmd::analysis::run_capital_distribution(gateway, &symbol, output).await
351 }
352 Command::CompanyProfile(args) => qot::dispatch_company_profile(gateway, output, args).await,
353 Command::CompanyExecutives(args) => {
354 qot::dispatch_company_executives(gateway, output, args).await
355 }
356 Command::CompanyExecutiveBackground(args) => {
357 qot::dispatch_company_executive_background(gateway, output, args).await
358 }
359 Command::CompanyOperationalEfficiency(args) => {
360 qot::dispatch_company_operational_efficiency(gateway, output, args).await
361 }
362 Command::FinancialsEarningsPriceMove(args) => {
363 qot::dispatch_financials_earnings_price_move(gateway, output, args).await
364 }
365 Command::FinancialsEarningsPriceHistory(args) => {
366 qot::dispatch_financials_earnings_price_history(gateway, output, args).await
367 }
368 Command::FinancialsStatements(args) => {
369 qot::dispatch_financials_statements(gateway, output, args).await
370 }
371 Command::FinancialsRevenueBreakdown(args) => {
372 qot::dispatch_financials_revenue_breakdown(gateway, output, args).await
373 }
374 Command::ResearchAnalystConsensus(args) => {
375 qot::dispatch_research_analyst_consensus(gateway, output, args).await
376 }
377 Command::ResearchRatingSummary(args) => {
378 qot::dispatch_research_rating_summary(gateway, output, args).await
379 }
380 Command::ResearchMorningstarReport(args) => {
381 qot::dispatch_research_morningstar_report(gateway, output, args).await
382 }
383 Command::ValuationDetail(args) => {
384 qot::dispatch_valuation_detail(gateway, output, args).await
385 }
386 Command::ValuationPlateStockList(args) => {
387 qot::dispatch_valuation_plate_stock_list(gateway, output, args).await
388 }
389 Command::StockScreen(args) => qot::dispatch_stock_screen(gateway, output, args).await,
390 Command::OptionScreen(args) => qot::dispatch_option_screen(gateway, output, args).await,
391 Command::WarrantScreen(args) => qot::dispatch_warrant_screen(gateway, output, args).await,
392 Command::TechnicalUnusual(args) => {
393 qot::dispatch_technical_unusual(gateway, output, args).await
394 }
395 Command::FinancialUnusual(args) => {
396 qot::dispatch_financial_unusual(gateway, output, args).await
397 }
398 Command::DerivativeUnusual(args) => {
399 qot::dispatch_derivative_unusual(gateway, output, args).await
400 }
401 Command::CorporateActionsBuybacks(args) => {
402 qot::dispatch_corporate_actions_buybacks(gateway, output, args).await
403 }
404 Command::CorporateActionsDividends(args) => {
405 qot::dispatch_corporate_actions_dividends(gateway, output, args).await
406 }
407 Command::CorporateActionsStockSplits(args) => {
408 qot::dispatch_corporate_actions_stock_splits(gateway, output, args).await
409 }
410 Command::DailyShortVolume(args) => {
411 qot::dispatch_daily_short_volume(gateway, output, args).await
412 }
413 Command::ShortInterest(args) => qot::dispatch_short_interest(gateway, output, args).await,
414 Command::TopTenBuySellBrokers(args) => {
415 qot::dispatch_top_ten_buy_sell_brokers(gateway, output, args).await
416 }
417 Command::ShareholdersOverview(args) => {
418 qot::dispatch_shareholders_overview(gateway, output, args).await
419 }
420 Command::ShareholdersHoldingChanges(args) => {
421 qot::dispatch_shareholders_holding_changes(gateway, output, args).await
422 }
423 Command::ShareholdersHolderDetail(args) => {
424 qot::dispatch_shareholders_holder_detail(gateway, output, args).await
425 }
426 Command::ShareholdersInstitutional(args) => {
427 qot::dispatch_shareholders_institutional(gateway, output, args).await
428 }
429 Command::InsiderHolderList(args) => {
430 qot::dispatch_insider_holder_list(gateway, output, args).await
431 }
432 Command::InsiderTradeList(args) => {
433 qot::dispatch_insider_trade_list(gateway, output, args).await
434 }
435 Command::OptionVolatility(args) => {
436 qot::dispatch_option_volatility(gateway, output, args).await
437 }
438 Command::OptionExerciseProbability(args) => {
439 qot::dispatch_option_exercise_probability(gateway, output, args).await
440 }
441 Command::MarketState { symbols } => {
442 let list = parse_symbol_csv(&symbols)?;
445 cmd::analysis::run_market_state(gateway, &list, output).await
446 }
447 Command::OwnerPlate { symbols } => {
448 let list = parse_symbol_csv(&symbols)?;
450 cmd::analysis::run_owner_plate(gateway, &list, output).await
451 }
452 Command::OptionChain {
453 owner,
454 owner_arg,
455 begin,
456 end,
457 option_type,
458 delta_min,
459 delta_max,
460 iv_min,
461 iv_max,
462 oi_min,
463 oi_max,
464 gamma_min,
465 gamma_max,
466 vega_min,
467 vega_max,
468 theta_min,
469 theta_max,
470 } => {
471 let owner = owner.or(owner_arg).ok_or_else(|| {
472 anyhow::anyhow!("option-chain: 需要位置参数 <OWNER> 或 --owner / --code")
473 })?;
474 cmd::analysis::run_option_chain(
475 gateway,
476 &owner,
477 &begin,
478 &end,
479 &option_type,
480 cmd::analysis::OptionChainGreekFilterArgs {
481 delta_min,
482 delta_max,
483 iv_min,
484 iv_max,
485 oi_min,
486 oi_max,
487 gamma_min,
488 gamma_max,
489 vega_min,
490 vega_max,
491 theta_min,
492 theta_max,
493 },
494 output,
495 )
496 .await
497 }
498
499 Command::TradingDays { market, begin, end } => {
501 cmd::analysis::run_trading_days(gateway, &market, &begin, &end, output).await
502 }
503 Command::Rehab { symbol } => cmd::analysis::run_rehab(gateway, &symbol, output).await,
504 Command::Suspend {
505 symbols,
506 symbols_arg,
507 begin,
508 end,
509 } => {
510 let symbols = symbols.or(symbols_arg).ok_or_else(|| {
511 anyhow::anyhow!("suspend: 需要位置参数 <SYMBOLS> 或 --code / --symbols")
512 })?;
513 let syms = parse_symbol_csv(&symbols)?;
515 cmd::analysis::run_suspend(gateway, &syms, &begin, &end, output).await
516 }
517 Command::UserSecurity { group, group_arg } => {
518 let group = group
519 .or(group_arg)
520 .ok_or_else(|| anyhow::anyhow!("user-security: 需要位置参数 <GROUP> 或 --group"))?;
521 cmd::analysis::run_user_security(gateway, &group, output).await
522 }
523 Command::UserSecurityGroups { group_type } => {
524 cmd::analysis::run_user_security_groups(gateway, group_type, output).await
525 }
526 Command::Warrant { owner, begin, num } => {
527 cmd::analysis::run_warrant(gateway, owner.as_deref(), begin, num, output).await
528 }
529 Command::IpoList { market } => cmd::analysis::run_ipo_list(gateway, &market, output).await,
530 Command::FutureInfo { symbols } => {
531 let syms = parse_symbol_csv(&symbols)?;
533 cmd::analysis::run_future_info(gateway, &syms, output).await
534 }
535 Command::StockFilter { market, begin, num } => {
536 cmd::analysis::run_stock_filter(gateway, &market, begin, num, output).await
537 }
538 Command::CancelAllOrder {
539 acc_id,
540 card_num,
541 env,
542 market,
543 jp_acc_type,
544 confirm,
545 } => {
546 let acc_id = cmd::account::resolve_account_locator(
547 gateway,
548 acc_id,
549 card_num.as_deref(),
550 "cancel-all-order",
551 )
552 .await?;
553 cmd::trade_ext::run_cancel_all_order(
554 gateway,
555 acc_id,
556 &env,
557 market.as_deref(),
558 jp_acc_type,
559 confirm,
560 output,
561 )
562 .await
563 }
564 Command::GlobalState => cmd::sys::run_global_state(gateway, output).await,
565 Command::UserInfo => cmd::sys::run_user_info(gateway, output).await,
566 Command::QuoteRights(args) => {
567 cmd::sys::run_quote_rights(gateway, args.refresh, output).await
568 }
569 Command::DelayStatistics => cmd::sys::run_delay_statistics(gateway, output).await,
570 Command::TokenState => cmd::sys::run_token_state(gateway, output).await,
571 Command::RiskFreeRate => cmd::sys::run_risk_free_rate(gateway, output).await,
572 Command::SpreadTable => cmd::sys::run_spread_table(gateway, output).await,
573 Command::TickerStatistic(args) => {
574 let sym = args.symbol_pos.or(args.symbol).ok_or_else(|| {
576 anyhow::anyhow!("ticker-statistic: SYMBOL or --symbol required (e.g. HK.00700)")
577 })?;
578 cmd::sys::run_ticker_statistic(gateway, &sym, args.ticker_type, args.stat_type, output)
579 .await
580 }
581 Command::TickerStatisticDetail(args) => {
583 let sym = args.symbol_pos.or(args.symbol).ok_or_else(|| {
584 anyhow::anyhow!(
585 "ticker-statistic-detail: SYMBOL or --symbol required (e.g. HK.00700)"
586 )
587 })?;
588 cmd::sys::run_ticker_statistic_detail(cmd::sys::TickerStatisticDetailCommand {
589 gateway,
590 symbol: &sym,
591 ticker_type: args.ticker_type,
592 ticker_time: args.ticker_time,
593 select_num: args.select_num,
594 data_from: args.data_from,
595 data_max_count: args.data_max_count,
596 stat_type: args.stat_type,
597 format: output,
598 })
599 .await
600 }
601
602 Command::QuerySubscription(args) => {
604 cmd::sys::run_query_subscription(gateway, args.all_conn, output).await
605 }
606 Command::UsedQuota => cmd::sys::run_used_quota(gateway, output).await,
607 Command::Unsubscribe(args) => {
608 let syms: Vec<String> = if args.symbols.trim().is_empty() {
609 vec![]
610 } else {
611 args.symbols
612 .split(',')
613 .map(|s| s.trim().to_string())
614 .collect()
615 };
616 let types: Vec<i32> = if args.sub_types.trim().is_empty() {
617 vec![]
618 } else {
619 args.sub_types
620 .split(',')
621 .map(|s| s.trim().parse::<i32>())
622 .collect::<std::result::Result<Vec<_>, _>>()
623 .map_err(|e| anyhow::anyhow!("invalid sub-type: {e}"))?
624 };
625 cmd::sys::run_unsubscribe(gateway, &syms, &types, args.all, output).await
626 }
627 Command::HistoryKlQuota(args) => {
628 cmd::analysis::run_history_kl_quota(gateway, args.detail, output).await
629 }
630 Command::HoldingChange {
631 symbol,
632 category,
633 begin,
634 end,
635 } => {
636 cmd::analysis::run_holding_change(
637 gateway,
638 &symbol,
639 category,
640 begin.as_deref(),
641 end.as_deref(),
642 output,
643 )
644 .await
645 }
646 Command::ModifyUserSecurity { group, op, symbols } => {
647 let syms: Vec<String> = symbols.split(',').map(|s| s.trim().to_string()).collect();
648 cmd::analysis::run_modify_user_security(gateway, &group, op, &syms, output).await
649 }
650 Command::CodeChange { symbols } => {
651 let syms: Vec<String> = symbols.split(',').map(|s| s.trim().to_string()).collect();
652 cmd::analysis::run_code_change(gateway, &syms, output).await
653 }
654 Command::SetPriceReminder {
655 symbol,
656 op,
657 key,
658 r#type,
659 freq,
660 value,
661 note,
662 session,
663 } => {
664 cmd::analysis::run_set_price_reminder(cmd::analysis::SetPriceReminderCommand {
665 gateway,
666 symbol: &symbol,
667 op,
668 key,
669 reminder_type: r#type,
670 freq,
671 value,
672 note: note.as_deref(),
673 reminder_session_list: &session,
674 })
675 .await
676 }
677 Command::PriceReminder { symbol, market } => {
678 cmd::analysis::run_get_price_reminder(
679 gateway,
680 symbol.as_deref(),
681 market.as_deref(),
682 output,
683 )
684 .await
685 }
686 Command::OptionExpirationDate {
687 owner,
688 owner_arg,
689 index_type,
690 } => {
691 let owner = owner.or(owner_arg).ok_or_else(|| {
692 anyhow::anyhow!("option-expiration-date: 需要位置参数 <OWNER> 或 --owner")
693 })?;
694 cmd::analysis::run_option_expiration_date(gateway, &owner, index_type, output).await
695 }
696 Command::SubAccPush { acc_ids } => {
697 let ids: Vec<u64> = acc_ids
698 .split(',')
699 .map(|s| s.trim().parse::<u64>())
700 .collect::<std::result::Result<Vec<_>, _>>()
701 .map_err(|e| anyhow::anyhow!("invalid acc id: {e}"))?;
702 cmd::trade_ext::run_sub_acc_push(gateway, &ids, output).await
703 }
704 Command::AccCashFlow(args) => {
705 let acc_id = cmd::account::resolve_account_locator(
706 gateway,
707 args.acc_id.or(args.acc_id_arg),
708 args.card_num.as_deref(),
709 "acc-cash-flow",
710 )
711 .await?;
712 if let Some(range) = args.date_range {
714 let (from_s, to_s) = range.split_once("..").ok_or_else(|| {
716 anyhow::anyhow!("--date-range 格式应为 `YYYY-MM-DD..YYYY-MM-DD`,当前:{range}")
717 })?;
718 let from = chrono::NaiveDate::parse_from_str(from_s, "%Y-%m-%d")
719 .map_err(|e| anyhow::anyhow!("start date parse: {e}"))?;
720 let to = chrono::NaiveDate::parse_from_str(to_s, "%Y-%m-%d")
721 .map_err(|e| anyhow::anyhow!("end date parse: {e}"))?;
722 cmd::trade_ext::run_acc_cash_flow_range(cmd::trade_ext::AccCashFlowRangeCommand {
723 gateway,
724 acc_id,
725 date_from: from,
726 date_to: to,
727 env: &args.env,
728 market: &args.market,
729 direction: args.direction,
730 })
731 .await
732 } else if let Some(d) = args.date {
733 cmd::trade_ext::run_acc_cash_flow(
734 gateway,
735 acc_id,
736 &d,
737 &args.env,
738 &args.market,
739 args.direction,
740 output,
741 )
742 .await
743 } else {
744 anyhow::bail!("需传 --date <YYYY-MM-DD> 或 --date-range <FROM..TO>")
745 }
746 }
747 Command::DaemonStatus(args) => {
748 daemon::dispatch_status(args.rest_url, args.rest_port, args.api_key, output).await
749 }
750 Command::DaemonShutdown(args) => {
751 daemon::dispatch_shutdown(args.rest_url, args.rest_port, args.api_key).await
752 }
753 Command::DaemonReload(args) => {
754 daemon::dispatch_reload(args.rest_url, args.rest_port, args.api_key).await
755 }
756
757 Command::CashLog(args) => tier_m::dispatch_cash_log(gateway, output, args).await,
761 Command::CashDetail(args) => tier_m::dispatch_cash_detail(gateway, output, args).await,
762 Command::BizGroup(args) => tier_m::dispatch_biz_group(gateway, output, args).await,
763 Command::MarginInfo(args) => tier_m::dispatch_margin_info(gateway, output, args).await,
764 Command::AccountFlag(args) => tier_m::dispatch_account_flag(gateway, output, args).await,
765 Command::BondTotalAsset(args) => {
766 tier_m::dispatch_bond_total_asset(gateway, output, args).await
767 }
768 Command::BondSingleAsset(args) => {
769 tier_m::dispatch_bond_single_asset(gateway, output, args).await
770 }
771 Command::BondPositionList(args) => {
772 tier_m::dispatch_bond_position_list(gateway, output, args).await
773 }
774 Command::BondAnswerState(args) => {
775 tier_m::dispatch_bond_answer_state(gateway, output, args).await
776 }
777 Command::BondTradeReminder(args) => {
778 tier_m::dispatch_bond_trade_reminder(gateway, output, args).await
779 }
780 }
781}