1use super::super::commands::*;
4use super::{daemon, trade_write};
5use crate::cmd;
6use crate::common::parse_symbol_csv;
7use crate::output::OutputFormat;
8use anyhow::Result;
9pub(super) async fn dispatch_verification(
10 gateway: &str,
11 output: OutputFormat,
12 args: VerificationArgs,
13) -> Result<()> {
14 cmd::proto_json::run_verification(gateway, args.verification_type, args.op, args.code, output)
15 .await
16}
17pub(super) async fn dispatch_indicator_calc(
18 gateway: &str,
19 output: OutputFormat,
20 args: IndicatorCalcArgs,
21) -> Result<()> {
22 cmd::indicator::calculate(gateway, &args.c2s_json, args.timeout_secs, output).await
23}
24pub(super) async fn dispatch_commands(
25 gateway: &str,
26 output: OutputFormat,
27 args: CommandsArgs,
28) -> Result<()> {
29 let _ = (gateway, &output);
30 cmd::command_catalog::run(args.group.as_deref(), args.search.as_deref(), output)
31}
32pub(super) async fn dispatch_version(
33 gateway: &str,
34 output: OutputFormat,
35 args: VersionArgs,
36) -> Result<()> {
37 let _ = (gateway, &output);
38 {
39 cmd::version_check::run_version(args.check, args.url.as_deref(), args.timeout_ms, output)
40 .await
41 }
42}
43pub(super) async fn dispatch_lang_pack(
44 gateway: &str,
45 output: OutputFormat,
46 args: LanguagePackArgs,
47) -> Result<()> {
48 let _ = (gateway, &output);
49 cmd::lang_pack::run(args.command, output).await
50}
51pub(super) async fn dispatch_push_subscriber_info(
52 gateway: &str,
53 output: OutputFormat,
54 args: PushSubscriberInfoArgs,
55) -> Result<()> {
56 let _ = (gateway, &output);
57 daemon::dispatch_push_sub_info(args, output).await
58}
59pub(super) async fn dispatch_static_status(
60 gateway: &str,
61 output: OutputFormat,
62 args: StaticStatusArgs,
63) -> Result<()> {
64 let _ = (gateway, &output);
65 {
66 let rest_url = args
67 .rest_url
68 .or_else(|| args.rest_port.map(|p| format!("http://127.0.0.1:{p}")));
69 cmd::static_diag::run_static_status(rest_url.as_deref(), args.api_key.as_deref(), output)
70 .await
71 }
72}
73pub(super) async fn dispatch_static_warmup(
74 gateway: &str,
75 output: OutputFormat,
76 args: StaticWarmupArgs,
77) -> Result<()> {
78 let _ = (gateway, &output);
79 cmd::static_info::run(gateway, &args.symbols, output).await
80}
81pub(super) async fn dispatch_unlock_trade(
82 gateway: &str,
83 output: OutputFormat,
84 args: UnlockTradeArgs,
85) -> Result<()> {
86 let _ = (gateway, &output);
87 {
88 cmd::unlock::run(
89 gateway,
90 args.lock,
91 args.from_stdin,
92 args.trade_pwd_account.as_deref(),
93 args.otp,
94 args.security_firm,
95 args.acc_ids,
96 output,
97 )
98 .await
99 }
100}
101pub(super) async fn dispatch_set_trade_pwd(
102 gateway: &str,
103 output: OutputFormat,
104 args: SetTradePwdArgs,
105) -> Result<()> {
106 let _ = (gateway, &output);
107 cmd::unlock::set_trade_pwd(&args.account, args.from_stdin).await
108}
109pub(super) async fn dispatch_clear_trade_pwd(
110 gateway: &str,
111 output: OutputFormat,
112 args: ClearTradePwdArgs,
113) -> Result<()> {
114 let _ = (gateway, &output);
115 cmd::unlock::clear_trade_pwd(&args.account).await
116}
117pub(super) async fn dispatch_set_login_pwd(
118 gateway: &str,
119 output: OutputFormat,
120 args: SetLoginPwdArgs,
121) -> Result<()> {
122 let _ = (gateway, &output);
123 cmd::unlock::set_login_pwd(&args.account, args.from_stdin).await
124}
125pub(super) async fn dispatch_clear_login_pwd(
126 gateway: &str,
127 output: OutputFormat,
128 args: ClearLoginPwdArgs,
129) -> Result<()> {
130 let _ = (gateway, &output);
131 cmd::unlock::clear_login_pwd(&args.account).await
132}
133pub(super) async fn dispatch_repl(gateway: &str, output: OutputFormat) -> Result<()> {
134 let _ = (gateway, &output);
135 {
136 anyhow::bail!(
137 "cannot enter REPL from this context (already nested / not a top-level invocation)"
138 )
139 }
140}
141pub(super) async fn dispatch_gen_key(
142 gateway: &str,
143 output: OutputFormat,
144 args: GenKeyArgs,
145) -> Result<()> {
146 let _ = gateway;
147 {
148 cmd::gen_key::run(cmd::gen_key::GenKeyCommand {
149 id: args.id,
150 scopes: args.scopes,
151 keys_file: args.keys_file,
152 expires: args.expires,
153 note: args.note,
154 allowed_markets: args.allowed_markets,
155 allowed_symbols: args.allowed_symbols,
156 max_order_value: args.max_order_value,
157 max_daily_value: args.max_daily_value,
158 hours_window: args.hours_window,
159 max_orders_per_minute: args.max_orders_per_minute,
160 allowed_trd_sides: args.allowed_trd_sides,
161 allowed_acc_ids: args.allowed_acc_ids,
162 allowed_card_nums: args.allowed_card_nums,
163 bind_this_machine: args.bind_this_machine,
164 bind_machines: args.bind_machines,
165 output,
166 })
167 .await
168 }
169}
170pub(super) async fn dispatch_bind_key(
171 gateway: &str,
172 output: OutputFormat,
173 args: BindKeyArgs,
174) -> Result<()> {
175 let _ = (gateway, &output);
176 {
177 cmd::bind_key::run(cmd::bind_key::BindKeyCommand {
178 id: args.id,
179 keys_file: args.keys_file,
180 this_machine: args.this_machine,
181 machines: args.machines,
182 replace: args.replace,
183 clear: args.clear,
184 freeze: args.freeze,
185 })
186 .await
187 }
188}
189pub(super) async fn dispatch_machine_id(
190 gateway: &str,
191 output: OutputFormat,
192 args: MachineIdArgs,
193) -> Result<()> {
194 let _ = (gateway, &output);
195 cmd::machine::run(args.for_key).await
196}
197pub(super) async fn dispatch_list_keys(
198 gateway: &str,
199 output: OutputFormat,
200 args: ListKeysArgs,
201) -> Result<()> {
202 let _ = (gateway, &output);
203 cmd::keys::list(args.keys_file, args.json).await
204}
205pub(super) async fn dispatch_revoke_key(
206 gateway: &str,
207 output: OutputFormat,
208 args: RevokeKeyArgs,
209) -> Result<()> {
210 let _ = (gateway, &output);
211 cmd::keys::revoke(args.id, args.keys_file, args.yes).await
212}
213pub(super) async fn dispatch_combo_order(
214 gateway: &str,
215 output: OutputFormat,
216 args: ComboOrderArgs,
217) -> Result<()> {
218 let _ = (gateway, &output);
219 {
220 cmd::proto_json::run_place_combo_order(
221 gateway,
222 &args.c2s_json,
223 args.confirm,
224 args.idempotency_key,
225 output,
226 )
227 .await
228 }
229}
230pub(super) async fn dispatch_capital_distribution(
231 gateway: &str,
232 output: OutputFormat,
233 args: CapitalDistributionArgs,
234) -> Result<()> {
235 let _ = (gateway, &output);
236 let CapitalDistributionArgs { symbol } = args;
237 cmd::analysis::run_capital_distribution(gateway, &symbol, output).await
238}
239pub(super) async fn dispatch_market_state(
240 gateway: &str,
241 output: OutputFormat,
242 args: MarketStateArgs,
243) -> Result<()> {
244 let _ = (gateway, &output);
245 let MarketStateArgs { symbols } = args;
246 {
247 let list = parse_symbol_csv(&symbols)?;
248 cmd::analysis::run_market_state(gateway, &list, output).await
249 }
250}
251pub(super) async fn dispatch_owner_plate(
252 gateway: &str,
253 output: OutputFormat,
254 args: OwnerPlateArgs,
255) -> Result<()> {
256 let _ = (gateway, &output);
257 let OwnerPlateArgs { symbols } = args;
258 {
259 let list = parse_symbol_csv(&symbols)?;
260 cmd::analysis::run_owner_plate(gateway, &list, output).await
261 }
262}
263pub(super) async fn dispatch_option_chain(
264 gateway: &str,
265 output: OutputFormat,
266 args: OptionChainArgs,
267) -> Result<()> {
268 let _ = (gateway, &output);
269 let OptionChainArgs {
270 owner,
271 owner_arg,
272 begin,
273 end,
274 option_type,
275 delta_min,
276 delta_max,
277 iv_min,
278 iv_max,
279 oi_min,
280 oi_max,
281 gamma_min,
282 gamma_max,
283 vega_min,
284 vega_max,
285 theta_min,
286 theta_max,
287 } = args;
288 {
289 let owner = owner.or(owner_arg).ok_or_else(|| {
290 anyhow::anyhow!("option-chain: 需要位置参数 <OWNER> 或 --owner / --code")
291 })?;
292 cmd::analysis::run_option_chain(
293 gateway,
294 &owner,
295 &begin,
296 &end,
297 &option_type,
298 cmd::analysis::OptionChainGreekFilterArgs {
299 delta_min,
300 delta_max,
301 iv_min,
302 iv_max,
303 oi_min,
304 oi_max,
305 gamma_min,
306 gamma_max,
307 vega_min,
308 vega_max,
309 theta_min,
310 theta_max,
311 },
312 output,
313 )
314 .await
315 }
316}
317pub(super) async fn dispatch_trading_days(
318 gateway: &str,
319 output: OutputFormat,
320 args: TradingDaysArgs,
321) -> Result<()> {
322 let _ = (gateway, &output);
323 let TradingDaysArgs { market, begin, end } = args;
324 cmd::analysis::run_trading_days(gateway, &market, &begin, &end, output).await
325}
326pub(super) async fn dispatch_rehab(
327 gateway: &str,
328 output: OutputFormat,
329 args: RehabArgs,
330) -> Result<()> {
331 let _ = (gateway, &output);
332 let RehabArgs { symbol } = args;
333 cmd::analysis::run_rehab(gateway, &symbol, output).await
334}
335pub(super) async fn dispatch_suspend(
336 gateway: &str,
337 output: OutputFormat,
338 args: SuspendArgs,
339) -> Result<()> {
340 let _ = (gateway, &output);
341 let SuspendArgs {
342 symbols,
343 symbols_arg,
344 begin,
345 end,
346 } = args;
347 {
348 let symbols = symbols.or(symbols_arg).ok_or_else(|| {
349 anyhow::anyhow!("suspend: 需要位置参数 <SYMBOLS> 或 --code / --symbols")
350 })?;
351 let syms = parse_symbol_csv(&symbols)?;
352 cmd::analysis::run_suspend(gateway, &syms, &begin, &end, output).await
353 }
354}
355pub(super) async fn dispatch_user_security(
356 gateway: &str,
357 output: OutputFormat,
358 args: UserSecurityArgs,
359) -> Result<()> {
360 let _ = (gateway, &output);
361 let UserSecurityArgs { group, group_arg } = args;
362 {
363 let group = group
364 .or(group_arg)
365 .ok_or_else(|| anyhow::anyhow!("user-security: 需要位置参数 <GROUP> 或 --group"))?;
366 cmd::analysis::run_user_security(gateway, &group, output).await
367 }
368}
369pub(super) async fn dispatch_user_security_groups(
370 gateway: &str,
371 output: OutputFormat,
372 args: UserSecurityGroupsArgs,
373) -> Result<()> {
374 let _ = (gateway, &output);
375 let UserSecurityGroupsArgs { group_type } = args;
376 cmd::analysis::run_user_security_groups(gateway, group_type, output).await
377}
378pub(super) async fn dispatch_warrant(
379 gateway: &str,
380 output: OutputFormat,
381 args: WarrantArgs,
382) -> Result<()> {
383 let _ = (gateway, &output);
384 let WarrantArgs { owner, begin, num } = args;
385 cmd::analysis::run_warrant(gateway, owner.as_deref(), begin, num, output).await
386}
387pub(super) async fn dispatch_ipo_list(
388 gateway: &str,
389 output: OutputFormat,
390 args: IpoListArgs,
391) -> Result<()> {
392 let _ = (gateway, &output);
393 let IpoListArgs { market } = args;
394 cmd::analysis::run_ipo_list(gateway, &market, output).await
395}
396pub(super) async fn dispatch_future_info(
397 gateway: &str,
398 output: OutputFormat,
399 args: FutureInfoArgs,
400) -> Result<()> {
401 let _ = (gateway, &output);
402 let FutureInfoArgs { symbols } = args;
403 {
404 let syms = parse_symbol_csv(&symbols)?;
405 cmd::analysis::run_future_info(gateway, &syms, output).await
406 }
407}
408pub(super) async fn dispatch_stock_filter(
409 gateway: &str,
410 output: OutputFormat,
411 args: StockFilterArgs,
412) -> Result<()> {
413 let _ = (gateway, &output);
414 let StockFilterArgs { market, begin, num } = args;
415 cmd::analysis::run_stock_filter(gateway, &market, begin, num, output).await
416}
417pub(super) async fn dispatch_cancel_all_order(
418 gateway: &str,
419 output: OutputFormat,
420 args: CancelAllOrderArgs,
421) -> Result<()> {
422 let _ = (gateway, &output);
423 let CancelAllOrderArgs {
424 acc_id,
425 card_num,
426 acc_id_file,
427 env,
428 market,
429 jp_acc_type,
430 confirm,
431 } = args;
432 {
433 trade_write::dispatch_cancel_all_order(
434 gateway,
435 output,
436 trade_write::CancelAllOrderDispatchArgs {
437 acc_id,
438 acc_id_file,
439 card_num,
440 env,
441 market,
442 jp_acc_type,
443 confirm,
444 },
445 )
446 .await
447 }
448}
449pub(super) async fn dispatch_quote_rights(
450 gateway: &str,
451 output: OutputFormat,
452 args: QuoteRightsArgs,
453) -> Result<()> {
454 let _ = (gateway, &output);
455 cmd::sys::run_quote_rights(gateway, args.refresh, output).await
456}
457pub(super) async fn dispatch_quote_capability(
458 gateway: &str,
459 output: OutputFormat,
460 args: QuoteCapabilityArgs,
461) -> Result<()> {
462 let _ = (gateway, &output);
463 {
464 let symbol = args.symbol_positional.or(args.symbol_arg).ok_or_else(|| {
465 anyhow::anyhow!("quote-capability: 需要 positional <SYMBOL> 或 --symbol/--code/--stock")
466 })?;
467 cmd::sys::run_quote_capability(gateway, &symbol, output).await
468 }
469}
470pub(super) async fn dispatch_ticker_statistic(
471 gateway: &str,
472 output: OutputFormat,
473 args: TickerStatisticArgs,
474) -> Result<()> {
475 let _ = (gateway, &output);
476 {
477 let sym = args.symbol_pos.or(args.symbol).ok_or_else(|| {
478 anyhow::anyhow!("ticker-statistic: SYMBOL or --symbol required (e.g. HK.00700)")
479 })?;
480 cmd::sys::run_ticker_statistic(gateway, &sym, args.ticker_type, args.stat_type, output)
481 .await
482 }
483}
484pub(super) async fn dispatch_ticker_statistic_detail(
485 gateway: &str,
486 output: OutputFormat,
487 args: TickerStatisticDetailArgs,
488) -> Result<()> {
489 let _ = (gateway, &output);
490 {
491 let sym = args.symbol_pos.or(args.symbol).ok_or_else(|| {
492 anyhow::anyhow!("ticker-statistic-detail: SYMBOL or --symbol required (e.g. HK.00700)")
493 })?;
494 cmd::sys::run_ticker_statistic_detail(cmd::sys::TickerStatisticDetailCommand {
495 gateway,
496 symbol: &sym,
497 ticker_type: args.ticker_type,
498 ticker_time: args.ticker_time,
499 select_num: args.select_num,
500 data_from: args.data_from,
501 data_max_count: args.data_max_count,
502 stat_type: args.stat_type,
503 format: output,
504 })
505 .await
506 }
507}
508pub(super) async fn dispatch_query_subscription(
509 gateway: &str,
510 output: OutputFormat,
511 args: QuerySubscriptionArgs,
512) -> Result<()> {
513 let _ = (gateway, &output);
514 cmd::sys::run_query_subscription(gateway, args.all_conn, output).await
515}
516pub(super) async fn dispatch_unsubscribe(
517 gateway: &str,
518 output: OutputFormat,
519 args: UnsubscribeArgs,
520) -> Result<()> {
521 let _ = (gateway, &output);
522 {
523 let syms: Vec<String> = if args.symbols.trim().is_empty() {
524 vec![]
525 } else {
526 args.symbols
527 .split(',')
528 .map(|s| s.trim().to_string())
529 .collect()
530 };
531 let types: Vec<i32> = if args.sub_types.trim().is_empty() {
532 vec![]
533 } else {
534 args.sub_types
535 .split(',')
536 .map(|s| s.trim().parse::<i32>())
537 .collect::<std::result::Result<Vec<_>, _>>()
538 .map_err(|e| anyhow::anyhow!("invalid sub-type: {e}"))?
539 };
540 cmd::sys::run_unsubscribe(gateway, &syms, &types, args.all, output).await
541 }
542}
543pub(super) async fn dispatch_surface(
544 gateway: &str,
545 output: OutputFormat,
546 args: SurfaceArgs,
547) -> Result<()> {
548 let _ = (gateway, &output);
549 cmd::surface::run(args.gaps, args.checklist.as_deref(), output)
550}
551pub(super) async fn dispatch_history_kl_quota(
552 gateway: &str,
553 output: OutputFormat,
554 args: HistoryKlQuotaArgs,
555) -> Result<()> {
556 let _ = (gateway, &output);
557 cmd::analysis::run_history_kl_quota(gateway, args.detail, output).await
558}
559pub(super) async fn dispatch_holding_change(
560 gateway: &str,
561 output: OutputFormat,
562 args: HoldingChangeArgs,
563) -> Result<()> {
564 let _ = (gateway, &output);
565 let HoldingChangeArgs {
566 symbol,
567 category,
568 begin,
569 end,
570 } = args;
571 {
572 cmd::analysis::run_holding_change(
573 gateway,
574 &symbol,
575 category,
576 begin.as_deref(),
577 end.as_deref(),
578 output,
579 )
580 .await
581 }
582}
583pub(super) async fn dispatch_modify_user_security(
584 gateway: &str,
585 output: OutputFormat,
586 args: ModifyUserSecurityArgs,
587) -> Result<()> {
588 let _ = (gateway, &output);
589 let ModifyUserSecurityArgs { group, op, symbols } = args;
590 {
591 let syms: Vec<String> = symbols.split(',').map(|s| s.trim().to_string()).collect();
592 cmd::analysis::run_modify_user_security(gateway, &group, op, &syms, output).await
593 }
594}
595pub(super) async fn dispatch_code_change(
596 gateway: &str,
597 output: OutputFormat,
598 args: CodeChangeArgs,
599) -> Result<()> {
600 let _ = (gateway, &output);
601 let CodeChangeArgs { symbols } = args;
602 {
603 let syms: Vec<String> = symbols.split(',').map(|s| s.trim().to_string()).collect();
604 cmd::analysis::run_code_change(gateway, &syms, output).await
605 }
606}
607pub(super) async fn dispatch_set_price_reminder(
608 gateway: &str,
609 output: OutputFormat,
610 args: SetPriceReminderArgs,
611) -> Result<()> {
612 let _ = (gateway, &output);
613 let SetPriceReminderArgs {
614 symbol,
615 op,
616 key,
617 r#type,
618 freq,
619 value,
620 note,
621 session,
622 } = args;
623 {
624 cmd::analysis::run_set_price_reminder(cmd::analysis::SetPriceReminderCommand {
625 gateway,
626 symbol: &symbol,
627 op,
628 key,
629 reminder_type: r#type,
630 freq,
631 value,
632 note: note.as_deref(),
633 reminder_session_list: &session,
634 })
635 .await
636 }
637}
638pub(super) async fn dispatch_price_reminder(
639 gateway: &str,
640 output: OutputFormat,
641 args: PriceReminderArgs,
642) -> Result<()> {
643 let _ = (gateway, &output);
644 let PriceReminderArgs { symbol, market } = args;
645 {
646 cmd::analysis::run_get_price_reminder(gateway, symbol.as_deref(), market.as_deref(), output)
647 .await
648 }
649}
650pub(super) async fn dispatch_option_expiration_date(
651 gateway: &str,
652 output: OutputFormat,
653 args: OptionExpirationDateArgs,
654) -> Result<()> {
655 let _ = (gateway, &output);
656 let OptionExpirationDateArgs {
657 owner,
658 owner_arg,
659 index_type,
660 } = args;
661 {
662 let owner = owner.or(owner_arg).ok_or_else(|| {
663 anyhow::anyhow!("option-expiration-date: 需要位置参数 <OWNER> 或 --owner")
664 })?;
665 cmd::analysis::run_option_expiration_date(gateway, &owner, index_type, output).await
666 }
667}
668pub(super) async fn dispatch_sub_acc_push(
669 gateway: &str,
670 output: OutputFormat,
671 args: SubAccPushArgs,
672) -> Result<()> {
673 let _ = (gateway, &output);
674 let SubAccPushArgs { acc_ids } = args;
675 cmd::trade_ext::run_sub_acc_push(gateway, &acc_ids, output).await
676}
677pub(super) async fn dispatch_unsub_acc_push(
678 gateway: &str,
679 output: OutputFormat,
680 args: UnsubAccPushArgs,
681) -> Result<()> {
682 let _ = (gateway, &output);
683 let UnsubAccPushArgs { acc_ids } = args;
684 cmd::trade_ext::run_unsub_acc_push(gateway, &acc_ids, output).await
685}
686pub(super) async fn dispatch_daemon_status(
687 gateway: &str,
688 output: OutputFormat,
689 args: DaemonStatusArgs,
690) -> Result<()> {
691 let _ = (gateway, &output);
692 daemon::dispatch_status(args.rest_url, args.rest_port, args.api_key, output).await
693}
694pub(super) async fn dispatch_doctor(
695 gateway: &str,
696 output: OutputFormat,
697 args: DoctorArgs,
698) -> Result<()> {
699 let _ = (gateway, &output);
700 daemon::dispatch_doctor(args, output).await
701}
702pub(super) async fn dispatch_daemon_shutdown(
703 gateway: &str,
704 output: OutputFormat,
705 args: DaemonShutdownArgs,
706) -> Result<()> {
707 let _ = (gateway, &output);
708 daemon::dispatch_shutdown(args.rest_url, args.rest_port, args.api_key).await
709}
710pub(super) async fn dispatch_daemon_reload(
711 gateway: &str,
712 output: OutputFormat,
713 args: DaemonReloadArgs,
714) -> Result<()> {
715 let _ = (gateway, &output);
716 daemon::dispatch_reload(args.rest_url, args.rest_port, args.api_key).await
717}