Skip to main content

futucli/cli/dispatch/
qot.rs

1use anyhow::Result;
2
3use super::super::commands::{
4    BrokerArgs, CapitalFlowArgs, CompanyExecutiveBackgroundArgs, CompanyExecutivesArgs,
5    CompanyOperationalEfficiencyArgs, CompanyProfileArgs, CorporateActionsBuybacksArgs,
6    CorporateActionsDividendsArgs, CorporateActionsStockSplitsArgs, DailyShortVolumeArgs,
7    DerivativeUnusualArgs, FinancialCalendarArgs, FinancialCalendarTargetArgs,
8    FinancialUnusualArgs, FinancialsEarningsPriceHistoryArgs, FinancialsEarningsPriceMoveArgs,
9    FinancialsRevenueBreakdownArgs, FinancialsStatementsArgs, InsiderHolderListArgs,
10    InsiderTradeListArgs, IpoCalendarArgs, KlineArgs, OptionExerciseProbabilityArgs,
11    OptionScreenArgs, OptionVolatilityArgs, OrderbookArgs, PlateListArgs, PlateStocksArgs,
12    ProtoJsonArgs, QuoteArgs, ReferenceArgs, ResearchAnalystConsensusArgs,
13    ResearchMorningstarReportArgs, ResearchRatingSummaryArgs, RtArgs, ShareholdersHolderDetailArgs,
14    ShareholdersHoldingChangesArgs, ShareholdersInstitutionalArgs, ShareholdersOverviewArgs,
15    ShortInterestArgs, SnapshotArgs, StaticArgs, StockScreenArgs, SubArgs, TechnicalUnusualArgs,
16    TickerArgs, TopTenBuySellBrokersArgs, ValuationDetailArgs, ValuationPlateStockListArgs,
17    WarrantScreenArgs,
18};
19use crate::cmd;
20use crate::output::OutputFormat;
21
22pub(super) async fn dispatch_quote(
23    gateway: &str,
24    output: OutputFormat,
25    args: QuoteArgs,
26) -> Result<()> {
27    cmd::quote::run(gateway, &args.symbols, output).await
28}
29
30pub(super) async fn dispatch_snapshot(
31    gateway: &str,
32    output: OutputFormat,
33    args: SnapshotArgs,
34) -> Result<()> {
35    cmd::snapshot::run(gateway, &args.symbols, output).await
36}
37
38pub(super) async fn dispatch_sub(gateway: &str, output: OutputFormat, args: SubArgs) -> Result<()> {
39    cmd::sub::run(
40        gateway,
41        &args.symbols,
42        &args.r#type,
43        args.extended_time,
44        args.session.as_deref(),
45        args.orderbook_detail,
46        output,
47    )
48    .await
49}
50
51pub(super) async fn dispatch_kline(
52    gateway: &str,
53    output: OutputFormat,
54    args: KlineArgs,
55) -> Result<()> {
56    // v1.4.83 §10: positional 或 --symbol/--code/--stock flag 二选一
57    let symbol = args.symbol_positional.or(args.symbol_arg).ok_or_else(|| {
58        anyhow::anyhow!(
59            "kline: 需要 positional <SYMBOL> 或 --symbol/--code/--stock \
60             (如 `futucli kline US.AAPL` 或 `futucli kline --code US.AAPL`)"
61        )
62    })?;
63    cmd::kline::run_with_format(
64        gateway,
65        &symbol,
66        &args.r#type,
67        args.count,
68        &args.rehab_type,
69        args.page_size,
70        args.next_req_key.as_deref(),
71        args.need_kl_fields_flag,
72        args.extended_time,
73        args.session.as_deref(),
74        args.begin.as_deref(),
75        args.end.as_deref(),
76        output,
77    )
78    .await
79}
80
81pub(super) async fn dispatch_orderbook(
82    gateway: &str,
83    output: OutputFormat,
84    args: OrderbookArgs,
85) -> Result<()> {
86    let symbol = args.symbol_positional.or(args.symbol_arg).ok_or_else(|| {
87        anyhow::anyhow!("orderbook: 需要 positional <SYMBOL> 或 --symbol/--code/--stock")
88    })?;
89    cmd::orderbook::run(gateway, &symbol, args.depth, args.odd_lot, output).await
90}
91
92pub(super) async fn dispatch_ticker(
93    gateway: &str,
94    output: OutputFormat,
95    args: TickerArgs,
96) -> Result<()> {
97    let symbol = args.symbol_positional.or(args.symbol_arg).ok_or_else(|| {
98        anyhow::anyhow!("ticker: 需要 positional <SYMBOL> 或 --symbol/--code/--stock")
99    })?;
100    cmd::ticker::run(gateway, &symbol, args.count, output).await
101}
102
103pub(super) async fn dispatch_rt(gateway: &str, output: OutputFormat, args: RtArgs) -> Result<()> {
104    let symbol = args.symbol_positional.or(args.symbol_arg).ok_or_else(|| {
105        anyhow::anyhow!("rt: 需要 positional <SYMBOL> 或 --symbol/--code/--stock")
106    })?;
107    cmd::rt::run(gateway, &symbol, output).await
108}
109
110pub(super) async fn dispatch_static(
111    gateway: &str,
112    output: OutputFormat,
113    args: StaticArgs,
114) -> Result<()> {
115    cmd::static_info::run(gateway, &args.symbols, output).await
116}
117
118pub(super) async fn dispatch_broker(
119    gateway: &str,
120    output: OutputFormat,
121    args: BrokerArgs,
122) -> Result<()> {
123    let symbol = args.symbol_positional.or(args.symbol_arg).ok_or_else(|| {
124        anyhow::anyhow!("broker: 需要 positional <SYMBOL> 或 --symbol/--code/--stock")
125    })?;
126    cmd::broker::run(gateway, &symbol, output).await
127}
128
129pub(super) async fn dispatch_plate_list(
130    gateway: &str,
131    output: OutputFormat,
132    args: PlateListArgs,
133) -> Result<()> {
134    cmd::plate::list(gateway, &args.market, &args.set, output).await
135}
136
137pub(super) async fn dispatch_plate_stocks(
138    gateway: &str,
139    output: OutputFormat,
140    args: PlateStocksArgs,
141) -> Result<()> {
142    let plate = args
143        .plate
144        .or(args.plate_arg)
145        .ok_or_else(|| anyhow::anyhow!("plate-stocks: 需要位置参数 <PLATE> 或 --plate"))?;
146    cmd::plate::stocks(gateway, &plate, output).await
147}
148
149pub(super) async fn dispatch_reference(
150    gateway: &str,
151    output: OutputFormat,
152    args: ReferenceArgs,
153) -> Result<()> {
154    let symbol = args.symbol_positional.or(args.symbol_arg).ok_or_else(|| {
155        anyhow::anyhow!("reference: 需要位置参数 <SYMBOL> 或 --symbol/--code/--stock")
156    })?;
157    cmd::analysis::run_reference(gateway, &symbol, &args.reference_type, output).await
158}
159
160pub(super) async fn dispatch_option_quote(
161    gateway: &str,
162    output: OutputFormat,
163    args: ProtoJsonArgs,
164) -> Result<()> {
165    cmd::proto_json::run_option_quote(gateway, &args.c2s_json, output).await
166}
167
168pub(super) async fn dispatch_option_strategy(
169    gateway: &str,
170    output: OutputFormat,
171    args: ProtoJsonArgs,
172) -> Result<()> {
173    cmd::proto_json::run_option_strategy(gateway, &args.c2s_json, output).await
174}
175
176pub(super) async fn dispatch_option_strategy_analysis(
177    gateway: &str,
178    output: OutputFormat,
179    args: ProtoJsonArgs,
180) -> Result<()> {
181    cmd::proto_json::run_option_strategy_analysis(gateway, &args.c2s_json, output).await
182}
183
184pub(super) async fn dispatch_option_strategy_spread(
185    gateway: &str,
186    output: OutputFormat,
187    args: ProtoJsonArgs,
188) -> Result<()> {
189    cmd::proto_json::run_option_strategy_spread(gateway, &args.c2s_json, output).await
190}
191
192macro_rules! qot_proto_json_dispatch {
193    ($fn_name:ident, $runner:ident) => {
194        pub(super) async fn $fn_name(
195            gateway: &str,
196            output: OutputFormat,
197            args: ProtoJsonArgs,
198        ) -> Result<()> {
199            cmd::proto_json::$runner(gateway, &args.c2s_json, output).await
200        }
201    };
202}
203
204qot_proto_json_dispatch!(dispatch_earnings_calendar, run_earnings_calendar);
205qot_proto_json_dispatch!(dispatch_macro_indicator_list, run_macro_indicator_list);
206qot_proto_json_dispatch!(
207    dispatch_macro_indicator_history,
208    run_macro_indicator_history
209);
210qot_proto_json_dispatch!(dispatch_fed_watch_target_rate, run_fed_watch_target_rate);
211qot_proto_json_dispatch!(dispatch_fed_watch_dot_plot, run_fed_watch_dot_plot);
212qot_proto_json_dispatch!(dispatch_earnings_beat_rank, run_earnings_beat_rank);
213qot_proto_json_dispatch!(dispatch_dividend_rank, run_dividend_rank);
214qot_proto_json_dispatch!(dispatch_dividend_calendar, run_dividend_calendar);
215qot_proto_json_dispatch!(dispatch_economic_calendar, run_economic_calendar);
216qot_proto_json_dispatch!(dispatch_us_pre_market_rank, run_us_pre_market_rank);
217qot_proto_json_dispatch!(dispatch_us_after_hours_rank, run_us_after_hours_rank);
218qot_proto_json_dispatch!(dispatch_us_overnight_rank, run_us_overnight_rank);
219qot_proto_json_dispatch!(dispatch_top_movers_rank, run_top_movers_rank);
220qot_proto_json_dispatch!(dispatch_hot_list, run_hot_list);
221qot_proto_json_dispatch!(dispatch_short_selling_rank, run_short_selling_rank);
222qot_proto_json_dispatch!(dispatch_period_change_rank, run_period_change_rank);
223qot_proto_json_dispatch!(dispatch_high_dividend_soe_rank, run_high_dividend_soe_rank);
224qot_proto_json_dispatch!(dispatch_institution_list, run_institution_list);
225qot_proto_json_dispatch!(dispatch_institution_profile, run_institution_profile);
226qot_proto_json_dispatch!(
227    dispatch_institution_distribution,
228    run_institution_distribution
229);
230qot_proto_json_dispatch!(
231    dispatch_institution_holding_change,
232    run_institution_holding_change
233);
234qot_proto_json_dispatch!(
235    dispatch_institution_holding_list,
236    run_institution_holding_list
237);
238qot_proto_json_dispatch!(dispatch_ark_fund_holding, run_ark_fund_holding);
239qot_proto_json_dispatch!(dispatch_ark_stock_dynamic, run_ark_stock_dynamic);
240qot_proto_json_dispatch!(dispatch_ark_active_transaction, run_ark_active_transaction);
241qot_proto_json_dispatch!(dispatch_rating_change, run_rating_change);
242qot_proto_json_dispatch!(dispatch_industrial_chain_list, run_industrial_chain_list);
243qot_proto_json_dispatch!(
244    dispatch_industrial_chain_detail,
245    run_industrial_chain_detail
246);
247qot_proto_json_dispatch!(
248    dispatch_industrial_chain_by_plate,
249    run_industrial_chain_by_plate
250);
251qot_proto_json_dispatch!(dispatch_industrial_plate_info, run_industrial_plate_info);
252qot_proto_json_dispatch!(dispatch_industrial_plate_stock, run_industrial_plate_stock);
253qot_proto_json_dispatch!(dispatch_heat_map_data, run_heat_map_data);
254qot_proto_json_dispatch!(dispatch_rise_fall_distribution, run_rise_fall_distribution);
255
256pub(super) async fn dispatch_capital_flow(
257    gateway: &str,
258    output: OutputFormat,
259    args: CapitalFlowArgs,
260) -> Result<()> {
261    cmd::analysis::run_capital_flow(
262        gateway,
263        &args.symbol,
264        args.period_type,
265        args.begin.as_deref(),
266        args.end.as_deref(),
267        output,
268    )
269    .await
270}
271
272pub(super) async fn dispatch_company_profile(
273    gateway: &str,
274    output: OutputFormat,
275    args: CompanyProfileArgs,
276) -> Result<()> {
277    cmd::analysis::run_company_profile(gateway, &args.symbol, output).await
278}
279
280pub(super) async fn dispatch_company_executives(
281    gateway: &str,
282    output: OutputFormat,
283    args: CompanyExecutivesArgs,
284) -> Result<()> {
285    cmd::analysis::run_company_executives(gateway, &args.symbol, output).await
286}
287
288pub(super) async fn dispatch_company_executive_background(
289    gateway: &str,
290    output: OutputFormat,
291    args: CompanyExecutiveBackgroundArgs,
292) -> Result<()> {
293    cmd::analysis::run_company_executive_background(
294        gateway,
295        &args.symbol,
296        &args.leader_name,
297        output,
298    )
299    .await
300}
301
302pub(super) async fn dispatch_company_operational_efficiency(
303    gateway: &str,
304    output: OutputFormat,
305    args: CompanyOperationalEfficiencyArgs,
306) -> Result<()> {
307    cmd::analysis::run_company_operational_efficiency(
308        gateway,
309        &args.symbol,
310        args.next_key.as_deref(),
311        args.num,
312        args.currency_code.as_deref(),
313        args.financial_type,
314        output,
315    )
316    .await
317}
318
319pub(super) async fn dispatch_financials_earnings_price_move(
320    gateway: &str,
321    output: OutputFormat,
322    args: FinancialsEarningsPriceMoveArgs,
323) -> Result<()> {
324    cmd::analysis::run_financials_earnings_price_move(
325        gateway,
326        &args.symbol,
327        args.period_count,
328        output,
329    )
330    .await
331}
332
333pub(super) async fn dispatch_financials_earnings_price_history(
334    gateway: &str,
335    output: OutputFormat,
336    args: FinancialsEarningsPriceHistoryArgs,
337) -> Result<()> {
338    cmd::analysis::run_financials_earnings_price_history(gateway, &args.symbol, output).await
339}
340
341pub(super) async fn dispatch_financial_calendar(
342    gateway: &str,
343    output: OutputFormat,
344    args: FinancialCalendarArgs,
345) -> Result<()> {
346    cmd::analysis::run_financial_calendar(
347        gateway,
348        cmd::analysis::FinancialCalendarCommand {
349            begin_date: &args.begin_date,
350            end_date: &args.end_date,
351            markets: &args.markets,
352            pub_types: &args.pub_types,
353            stock_types: &args.stock_types,
354            count: Some(args.count),
355            ranking_type: args.ranking_type,
356            estimate_types: &args.estimate_types,
357            custom_filters: &args.custom_filters,
358            watchlist_only: args.watchlist_only,
359            positions_only: args.positions_only,
360            watchlist_stock_ids: &args.watchlist_stock_ids,
361            holding_stock_ids: &args.holding_stock_ids,
362        },
363        output,
364    )
365    .await
366}
367
368pub(super) async fn dispatch_financial_calendar_target(
369    gateway: &str,
370    output: OutputFormat,
371    args: FinancialCalendarTargetArgs,
372) -> Result<()> {
373    cmd::analysis::run_financial_calendar_target(
374        gateway,
375        cmd::analysis::FinancialCalendarTargetCommand {
376            stock_ids: &args.stock_ids,
377            markets: &args.markets,
378            size: args.size,
379            start: args.start,
380        },
381        output,
382    )
383    .await
384}
385
386pub(super) async fn dispatch_ipo_calendar(
387    gateway: &str,
388    output: OutputFormat,
389    args: IpoCalendarArgs,
390) -> Result<()> {
391    cmd::analysis::run_ipo_calendar(
392        gateway,
393        &args.market,
394        &args.events,
395        args.begin_date.as_deref(),
396        args.end_date.as_deref(),
397        output,
398    )
399    .await
400}
401
402pub(super) async fn dispatch_financials_statements(
403    gateway: &str,
404    output: OutputFormat,
405    args: FinancialsStatementsArgs,
406) -> Result<()> {
407    cmd::analysis::run_financials_statements(
408        gateway,
409        &args.symbol,
410        args.statement_type,
411        args.financial_type,
412        args.currency_code.as_deref(),
413        args.next_key.as_deref(),
414        args.num,
415        output,
416    )
417    .await
418}
419
420pub(super) async fn dispatch_financials_revenue_breakdown(
421    gateway: &str,
422    output: OutputFormat,
423    args: FinancialsRevenueBreakdownArgs,
424) -> Result<()> {
425    cmd::analysis::run_financials_revenue_breakdown(
426        gateway,
427        &args.symbol,
428        args.date,
429        args.financial_type,
430        args.currency_code.as_deref(),
431        output,
432    )
433    .await
434}
435
436pub(super) async fn dispatch_research_analyst_consensus(
437    gateway: &str,
438    output: OutputFormat,
439    args: ResearchAnalystConsensusArgs,
440) -> Result<()> {
441    cmd::analysis::run_research_analyst_consensus(gateway, &args.symbol, output).await
442}
443
444pub(super) async fn dispatch_research_rating_summary(
445    gateway: &str,
446    output: OutputFormat,
447    args: ResearchRatingSummaryArgs,
448) -> Result<()> {
449    cmd::analysis::run_research_rating_summary(
450        gateway,
451        &args.symbol,
452        args.rating_dimension_type,
453        args.uid.as_deref(),
454        args.next_key.as_deref(),
455        args.num,
456        output,
457    )
458    .await
459}
460
461pub(super) async fn dispatch_research_morningstar_report(
462    gateway: &str,
463    output: OutputFormat,
464    args: ResearchMorningstarReportArgs,
465) -> Result<()> {
466    cmd::analysis::run_research_morningstar_report(gateway, &args.symbol, output).await
467}
468
469pub(super) async fn dispatch_valuation_detail(
470    gateway: &str,
471    output: OutputFormat,
472    args: ValuationDetailArgs,
473) -> Result<()> {
474    cmd::analysis::run_valuation_detail(
475        gateway,
476        &args.symbol,
477        args.valuation_type,
478        args.interval_type,
479        output,
480    )
481    .await
482}
483
484pub(super) async fn dispatch_valuation_plate_stock_list(
485    gateway: &str,
486    output: OutputFormat,
487    args: ValuationPlateStockListArgs,
488) -> Result<()> {
489    cmd::analysis::run_valuation_plate_stock_list(
490        gateway,
491        &args.symbol,
492        args.valuation_type,
493        args.next_key.as_deref(),
494        args.num,
495        args.sort_type,
496        args.sort_id,
497        args.filter_security.as_deref(),
498        output,
499    )
500    .await
501}
502
503pub(super) async fn dispatch_stock_screen(
504    gateway: &str,
505    output: OutputFormat,
506    args: StockScreenArgs,
507) -> Result<()> {
508    cmd::analysis::run_stock_screen(gateway, &args.c2s_json, output).await
509}
510
511pub(super) async fn dispatch_option_screen(
512    gateway: &str,
513    output: OutputFormat,
514    args: OptionScreenArgs,
515) -> Result<()> {
516    cmd::analysis::run_option_screen(gateway, &args.c2s_json, output).await
517}
518
519pub(super) async fn dispatch_warrant_screen(
520    gateway: &str,
521    output: OutputFormat,
522    args: WarrantScreenArgs,
523) -> Result<()> {
524    cmd::analysis::run_warrant_screen(gateway, &args.c2s_json, output).await
525}
526
527pub(super) async fn dispatch_technical_unusual(
528    gateway: &str,
529    output: OutputFormat,
530    args: TechnicalUnusualArgs,
531) -> Result<()> {
532    cmd::analysis::run_technical_unusual(
533        gateway,
534        &args.stock_symbol,
535        args.time_range,
536        args.indicator_filters,
537        args.language_id,
538        output,
539    )
540    .await
541}
542
543pub(super) async fn dispatch_financial_unusual(
544    gateway: &str,
545    output: OutputFormat,
546    args: FinancialUnusualArgs,
547) -> Result<()> {
548    cmd::analysis::run_financial_unusual(
549        gateway,
550        &args.stock_symbol,
551        args.time_range,
552        args.analysis_dimensions,
553        args.language_id,
554        output,
555    )
556    .await
557}
558
559pub(super) async fn dispatch_derivative_unusual(
560    gateway: &str,
561    output: OutputFormat,
562    args: DerivativeUnusualArgs,
563) -> Result<()> {
564    cmd::analysis::run_derivative_unusual(
565        gateway,
566        &args.stock_symbol,
567        args.time_range,
568        args.analysis_dimensions,
569        args.language_id,
570        output,
571    )
572    .await
573}
574
575pub(super) async fn dispatch_corporate_actions_buybacks(
576    gateway: &str,
577    output: OutputFormat,
578    args: CorporateActionsBuybacksArgs,
579) -> Result<()> {
580    cmd::analysis::run_corporate_actions_buybacks(
581        gateway,
582        &args.symbol,
583        args.next_key.as_deref(),
584        args.num,
585        output,
586    )
587    .await
588}
589
590pub(super) async fn dispatch_corporate_actions_dividends(
591    gateway: &str,
592    output: OutputFormat,
593    args: CorporateActionsDividendsArgs,
594) -> Result<()> {
595    cmd::analysis::run_corporate_actions_dividends(gateway, &args.symbol, output).await
596}
597
598pub(super) async fn dispatch_corporate_actions_stock_splits(
599    gateway: &str,
600    output: OutputFormat,
601    args: CorporateActionsStockSplitsArgs,
602) -> Result<()> {
603    cmd::analysis::run_corporate_actions_stock_splits(
604        gateway,
605        &args.symbol,
606        args.next_key.as_deref(),
607        args.num,
608        output,
609    )
610    .await
611}
612
613pub(super) async fn dispatch_daily_short_volume(
614    gateway: &str,
615    output: OutputFormat,
616    args: DailyShortVolumeArgs,
617) -> Result<()> {
618    cmd::analysis::run_daily_short_volume(
619        gateway,
620        &args.symbol,
621        args.next_key.as_deref(),
622        args.num,
623        output,
624    )
625    .await
626}
627
628pub(super) async fn dispatch_short_interest(
629    gateway: &str,
630    output: OutputFormat,
631    args: ShortInterestArgs,
632) -> Result<()> {
633    cmd::analysis::run_short_interest(
634        gateway,
635        &args.symbol,
636        args.next_key.as_deref(),
637        args.num,
638        output,
639    )
640    .await
641}
642
643pub(super) async fn dispatch_top_ten_buy_sell_brokers(
644    gateway: &str,
645    output: OutputFormat,
646    args: TopTenBuySellBrokersArgs,
647) -> Result<()> {
648    cmd::analysis::run_top_ten_buy_sell_brokers(gateway, &args.symbol, args.days_before, output)
649        .await
650}
651
652pub(super) async fn dispatch_shareholders_overview(
653    gateway: &str,
654    output: OutputFormat,
655    args: ShareholdersOverviewArgs,
656) -> Result<()> {
657    cmd::analysis::run_shareholders_overview(gateway, &args.symbol, args.period_id, output).await
658}
659
660pub(super) async fn dispatch_shareholders_holding_changes(
661    gateway: &str,
662    output: OutputFormat,
663    args: ShareholdersHoldingChangesArgs,
664) -> Result<()> {
665    cmd::analysis::run_shareholders_holding_changes(
666        cmd::analysis::ShareholdersHoldingChangesCommand {
667            gateway,
668            symbol: &args.symbol,
669            next_key: args.next_key,
670            num: args.num,
671            sort_type: args.sort_type,
672            sort_column: args.sort_column,
673            filter_type: args.filter_type,
674            format: output,
675        },
676    )
677    .await
678}
679
680pub(super) async fn dispatch_shareholders_holder_detail(
681    gateway: &str,
682    output: OutputFormat,
683    args: ShareholdersHolderDetailArgs,
684) -> Result<()> {
685    cmd::analysis::run_shareholders_holder_detail(cmd::analysis::ShareholdersHolderDetailCommand {
686        gateway,
687        symbol: &args.symbol,
688        request_type: args.request_type,
689        next_key: args.next_key,
690        num: args.num,
691        sort_column: args.sort_column,
692        sort_type: args.sort_type,
693        period_id: args.period_id,
694        holder_id: args.holder_id,
695        format: output,
696    })
697    .await
698}
699
700pub(super) async fn dispatch_shareholders_institutional(
701    gateway: &str,
702    output: OutputFormat,
703    args: ShareholdersInstitutionalArgs,
704) -> Result<()> {
705    cmd::analysis::run_shareholders_institutional(
706        gateway,
707        &args.symbol,
708        args.next_key,
709        args.num,
710        output,
711    )
712    .await
713}
714
715pub(super) async fn dispatch_insider_holder_list(
716    gateway: &str,
717    output: OutputFormat,
718    args: InsiderHolderListArgs,
719) -> Result<()> {
720    cmd::analysis::run_insider_holder_list(gateway, &args.symbol, args.next_key, args.num, output)
721        .await
722}
723
724pub(super) async fn dispatch_insider_trade_list(
725    gateway: &str,
726    output: OutputFormat,
727    args: InsiderTradeListArgs,
728) -> Result<()> {
729    cmd::analysis::run_insider_trade_list(
730        gateway,
731        &args.symbol,
732        args.holder_id,
733        args.next_key,
734        args.num,
735        output,
736    )
737    .await
738}
739
740pub(super) async fn dispatch_option_volatility(
741    gateway: &str,
742    output: OutputFormat,
743    args: OptionVolatilityArgs,
744) -> Result<()> {
745    cmd::analysis::run_option_volatility(
746        gateway,
747        &args.symbol,
748        args.query_time_period,
749        args.hv_time_period,
750        output,
751    )
752    .await
753}
754
755pub(super) async fn dispatch_option_exercise_probability(
756    gateway: &str,
757    output: OutputFormat,
758    args: OptionExerciseProbabilityArgs,
759) -> Result<()> {
760    cmd::analysis::run_option_exercise_probability(gateway, &args.symbol, output).await
761}