Skip to main content

futu_rest/routes/qot/
reference.rs

1//! Split from routes/qot.rs: reference.
2
3use axum::extract::{Json, State};
4use futu_qot::ipo_calendar::{
5    collect_ipo_calendar_events, is_supported_ipo_event_type, is_yyyymmdd,
6};
7use serde::Deserialize;
8use serde_json::Value;
9
10use futu_core::proto_id;
11
12use super::*;
13
14mod company;
15mod unusual;
16pub use company::{
17    get_company_executive_background, get_company_executives, get_company_operational_efficiency,
18    get_company_profile, get_financials_earnings_price_history, get_financials_earnings_price_move,
19    get_financials_revenue_breakdown, get_financials_statements, get_research_analyst_consensus,
20    get_research_morningstar_report, get_research_rating_summary, get_valuation_detail,
21    get_valuation_plate_stock_list,
22};
23pub use unusual::{get_derivative_unusual, get_financial_unusual, get_technical_unusual};
24
25#[cfg(test)]
26mod tests;
27
28pub async fn get_plate_set(
29    State(state): State<RestState>,
30    Json(body): Json<Value>,
31) -> RawApiResult {
32    adapter::proto_request_raw::<qot_get_plate_set::Request, qot_get_plate_set::Response>(
33        &state,
34        proto_id::QOT_GET_PLATE_SET,
35        Some(body),
36    )
37    .await
38}
39
40/// POST /api/plate-security — 获取板块内股票
41pub async fn get_plate_security(
42    State(state): State<RestState>,
43    Json(body): Json<Value>,
44) -> RawApiResult {
45    adapter::proto_request_raw::<qot_get_plate_security::Request, qot_get_plate_security::Response>(
46        &state,
47        proto_id::QOT_GET_PLATE_SECURITY,
48        Some(body),
49    )
50    .await
51}
52
53/// POST /api/reference — 获取关联数据
54pub async fn get_reference(
55    State(state): State<RestState>,
56    Json(body): Json<Value>,
57) -> RawApiResult {
58    adapter::proto_request_raw::<qot_get_reference::Request, qot_get_reference::Response>(
59        &state,
60        proto_id::QOT_GET_REFERENCE,
61        Some(body),
62    )
63    .await
64}
65
66/// POST /api/owner-plate — 获取所属板块
67pub async fn get_owner_plate(
68    State(state): State<RestState>,
69    Json(body): Json<Value>,
70) -> RawApiResult {
71    adapter::proto_request_raw::<qot_get_owner_plate::Request, qot_get_owner_plate::Response>(
72        &state,
73        proto_id::QOT_GET_OWNER_PLATE,
74        Some(body),
75    )
76    .await
77}
78
79/// POST /api/option-chain — 获取期权链
80pub async fn get_option_chain(
81    State(state): State<RestState>,
82    Json(body): Json<Value>,
83) -> RawApiResult {
84    adapter::proto_request_raw::<qot_get_option_chain::Request, qot_get_option_chain::Response>(
85        &state,
86        proto_id::QOT_GET_OPTION_CHAIN,
87        Some(body),
88    )
89    .await
90}
91
92/// POST /api/option-quote — 获取单腿/组合期权实时行情
93pub async fn get_option_quote(
94    State(state): State<RestState>,
95    Json(body): Json<Value>,
96) -> RawApiResult {
97    adapter::proto_request_raw::<qot_get_option_quote::Request, qot_get_option_quote::Response>(
98        &state,
99        proto_id::QOT_GET_OPTION_QUOTE,
100        Some(body),
101    )
102    .await
103}
104
105/// POST /api/option-strategy — 获取组合期权策略列表
106pub async fn get_option_strategy(
107    State(state): State<RestState>,
108    Json(body): Json<Value>,
109) -> RawApiResult {
110    adapter::proto_request_raw::<
111        qot_get_option_strategy::Request,
112        qot_get_option_strategy::Response,
113    >(&state, proto_id::QOT_GET_OPTION_STRATEGY, Some(body))
114    .await
115}
116
117/// POST /api/option-strategy-analysis — 获取组合期权策略分析
118pub async fn get_option_strategy_analysis(
119    State(state): State<RestState>,
120    Json(body): Json<Value>,
121) -> RawApiResult {
122    adapter::proto_request_raw::<
123        qot_get_option_strategy_analysis::Request,
124        qot_get_option_strategy_analysis::Response,
125    >(
126        &state,
127        proto_id::QOT_GET_OPTION_STRATEGY_ANALYSIS,
128        Some(body),
129    )
130    .await
131}
132
133/// POST /api/option-strategy-spread — 获取组合期权有效价差
134pub async fn get_option_strategy_spread(
135    State(state): State<RestState>,
136    Json(body): Json<Value>,
137) -> RawApiResult {
138    adapter::proto_request_raw::<
139        qot_get_option_strategy_spread::Request,
140        qot_get_option_strategy_spread::Response,
141    >(&state, proto_id::QOT_GET_OPTION_STRATEGY_SPREAD, Some(body))
142    .await
143}
144
145/// POST /api/warrant — 获取窝轮
146pub async fn get_warrant(State(state): State<RestState>, Json(body): Json<Value>) -> RawApiResult {
147    adapter::proto_request_raw::<qot_get_warrant::Request, qot_get_warrant::Response>(
148        &state,
149        proto_id::QOT_GET_WARRANT,
150        Some(body),
151    )
152    .await
153}
154
155/// POST /api/capital-flow — 获取资金流向
156pub async fn get_capital_flow(
157    State(state): State<RestState>,
158    Json(body): Json<Value>,
159) -> RawApiResult {
160    adapter::proto_request_raw::<qot_get_capital_flow::Request, qot_get_capital_flow::Response>(
161        &state,
162        proto_id::QOT_GET_CAPITAL_FLOW,
163        Some(body),
164    )
165    .await
166}
167
168/// POST /api/capital-distribution — 获取资金分布
169pub async fn get_capital_distribution(
170    State(state): State<RestState>,
171    Json(body): Json<Value>,
172) -> RawApiResult {
173    adapter::proto_request_raw::<
174        qot_get_capital_distribution::Request,
175        qot_get_capital_distribution::Response,
176    >(&state, proto_id::QOT_GET_CAPITAL_DISTRIBUTION, Some(body))
177    .await
178}
179
180/// POST /api/corporate-actions-buybacks — 获取回购记录
181pub async fn get_corporate_actions_buybacks(
182    State(state): State<RestState>,
183    Json(body): Json<Value>,
184) -> RawApiResult {
185    adapter::proto_request_raw::<
186        qot_get_corporate_actions_buybacks::Request,
187        qot_get_corporate_actions_buybacks::Response,
188    >(
189        &state,
190        proto_id::QOT_GET_CORPORATE_ACTIONS_BUYBACKS,
191        Some(body),
192    )
193    .await
194}
195
196/// POST /api/corporate-actions-dividends — 获取分红派息
197pub async fn get_corporate_actions_dividends(
198    State(state): State<RestState>,
199    Json(body): Json<Value>,
200) -> RawApiResult {
201    adapter::proto_request_raw::<
202        qot_get_corporate_actions_dividends::Request,
203        qot_get_corporate_actions_dividends::Response,
204    >(
205        &state,
206        proto_id::QOT_GET_CORPORATE_ACTIONS_DIVIDENDS,
207        Some(body),
208    )
209    .await
210}
211
212/// POST /api/corporate-actions-stock-splits — 获取拆合股
213pub async fn get_corporate_actions_stock_splits(
214    State(state): State<RestState>,
215    Json(body): Json<Value>,
216) -> RawApiResult {
217    adapter::proto_request_raw::<
218        qot_get_corporate_actions_stock_splits::Request,
219        qot_get_corporate_actions_stock_splits::Response,
220    >(
221        &state,
222        proto_id::QOT_GET_CORPORATE_ACTIONS_STOCK_SPLITS,
223        Some(body),
224    )
225    .await
226}
227
228/// POST /api/daily-short-volume — 获取每日卖空成交
229pub async fn get_daily_short_volume(
230    State(state): State<RestState>,
231    Json(body): Json<Value>,
232) -> RawApiResult {
233    adapter::proto_request_raw::<
234        qot_get_daily_short_volume::Request,
235        qot_get_daily_short_volume::Response,
236    >(&state, proto_id::QOT_GET_DAILY_SHORT_VOLUME, Some(body))
237    .await
238}
239
240/// POST /api/short-interest — 获取空头持仓
241pub async fn get_short_interest(
242    State(state): State<RestState>,
243    Json(body): Json<Value>,
244) -> RawApiResult {
245    adapter::proto_request_raw::<qot_get_short_interest::Request, qot_get_short_interest::Response>(
246        &state,
247        proto_id::QOT_GET_SHORT_INTEREST,
248        Some(body),
249    )
250    .await
251}
252
253/// POST /api/top-ten-buy-sell-brokers — 获取十大买卖经纪商
254pub async fn get_top_ten_buy_sell_brokers(
255    State(state): State<RestState>,
256    Json(body): Json<Value>,
257) -> RawApiResult {
258    adapter::proto_request_raw::<
259        qot_get_top_ten_buy_sell_brokers::Request,
260        qot_get_top_ten_buy_sell_brokers::Response,
261    >(
262        &state,
263        proto_id::QOT_GET_TOP_TEN_BUY_SELL_BROKERS,
264        Some(body),
265    )
266    .await
267}
268
269/// POST /api/shareholders-overview — 获取持股统计
270pub async fn get_shareholders_overview(
271    State(state): State<RestState>,
272    Json(body): Json<Value>,
273) -> RawApiResult {
274    adapter::proto_request_raw::<
275        qot_get_shareholders_overview::Request,
276        qot_get_shareholders_overview::Response,
277    >(&state, proto_id::QOT_GET_SHAREHOLDERS_OVERVIEW, Some(body))
278    .await
279}
280
281/// POST /api/shareholders-holding-changes — 获取股东持股变动
282pub async fn get_shareholders_holding_changes(
283    State(state): State<RestState>,
284    Json(body): Json<Value>,
285) -> RawApiResult {
286    adapter::proto_request_raw::<
287        qot_get_shareholders_holding_changes::Request,
288        qot_get_shareholders_holding_changes::Response,
289    >(
290        &state,
291        proto_id::QOT_GET_SHAREHOLDERS_HOLDING_CHANGES,
292        Some(body),
293    )
294    .await
295}
296
297/// POST /api/shareholders-holder-detail — 获取股东持股明细
298pub async fn get_shareholders_holder_detail(
299    State(state): State<RestState>,
300    Json(body): Json<Value>,
301) -> RawApiResult {
302    adapter::proto_request_raw::<
303        qot_get_shareholders_holder_detail::Request,
304        qot_get_shareholders_holder_detail::Response,
305    >(
306        &state,
307        proto_id::QOT_GET_SHAREHOLDERS_HOLDER_DETAIL,
308        Some(body),
309    )
310    .await
311}
312
313/// POST /api/shareholders-institutional — 获取机构持股统计
314pub async fn get_shareholders_institutional(
315    State(state): State<RestState>,
316    Json(body): Json<Value>,
317) -> RawApiResult {
318    adapter::proto_request_raw::<
319        qot_get_shareholders_institutional::Request,
320        qot_get_shareholders_institutional::Response,
321    >(
322        &state,
323        proto_id::QOT_GET_SHAREHOLDERS_INSTITUTIONAL,
324        Some(body),
325    )
326    .await
327}
328
329/// POST /api/insider-holder-list — 获取内部人持股列表
330pub async fn get_insider_holder_list(
331    State(state): State<RestState>,
332    Json(body): Json<Value>,
333) -> RawApiResult {
334    adapter::proto_request_raw::<
335        qot_get_insider_holder_list::Request,
336        qot_get_insider_holder_list::Response,
337    >(&state, proto_id::QOT_GET_INSIDER_HOLDER_LIST, Some(body))
338    .await
339}
340
341/// POST /api/insider-trade-list — 获取内部人交易列表
342pub async fn get_insider_trade_list(
343    State(state): State<RestState>,
344    Json(body): Json<Value>,
345) -> RawApiResult {
346    adapter::proto_request_raw::<
347        qot_get_insider_trade_list::Request,
348        qot_get_insider_trade_list::Response,
349    >(&state, proto_id::QOT_GET_INSIDER_TRADE_LIST, Some(body))
350    .await
351}
352
353/// POST /api/option-volatility — 获取期权波动率分析
354pub async fn get_option_volatility(
355    State(state): State<RestState>,
356    Json(body): Json<Value>,
357) -> RawApiResult {
358    adapter::proto_request_raw::<
359        qot_get_option_volatility::Request,
360        qot_get_option_volatility::Response,
361    >(&state, proto_id::QOT_GET_OPTION_VOLATILITY, Some(body))
362    .await
363}
364
365/// POST /api/option-exercise-probability — 获取期权行权概率
366pub async fn get_option_exercise_probability(
367    State(state): State<RestState>,
368    Json(body): Json<Value>,
369) -> RawApiResult {
370    adapter::proto_request_raw::<
371        qot_get_option_exercise_probability::Request,
372        qot_get_option_exercise_probability::Response,
373    >(
374        &state,
375        proto_id::QOT_GET_OPTION_EXERCISE_PROBABILITY,
376        Some(body),
377    )
378    .await
379}
380
381/// POST /api/stock-screen — 获取股票筛选结果
382pub async fn stock_screen(State(state): State<RestState>, Json(body): Json<Value>) -> RawApiResult {
383    adapter::proto_request_raw::<qot_stock_screen::Request, qot_stock_screen::Response>(
384        &state,
385        proto_id::QOT_STOCK_SCREEN,
386        Some(body),
387    )
388    .await
389}
390
391/// POST /api/option-screen — 获取期权筛选结果
392pub async fn option_screen(
393    State(state): State<RestState>,
394    Json(body): Json<Value>,
395) -> RawApiResult {
396    adapter::proto_request_raw::<qot_option_screen::Request, qot_option_screen::Response>(
397        &state,
398        proto_id::QOT_OPTION_SCREEN,
399        Some(body),
400    )
401    .await
402}
403
404/// POST /api/warrant-screen — 获取窝轮筛选结果
405pub async fn warrant_screen(
406    State(state): State<RestState>,
407    Json(body): Json<Value>,
408) -> RawApiResult {
409    adapter::proto_request_raw::<qot_warrant_screen::Request, qot_warrant_screen::Response>(
410        &state,
411        proto_id::QOT_WARRANT_SCREEN,
412        Some(body),
413    )
414    .await
415}
416
417/// POST /api/user-security — 获取自选股
418pub async fn get_user_security(
419    State(state): State<RestState>,
420    Json(body): Json<Value>,
421) -> RawApiResult {
422    adapter::proto_request_raw::<qot_get_user_security::Request, qot_get_user_security::Response>(
423        &state,
424        proto_id::QOT_GET_USER_SECURITY,
425        Some(body),
426    )
427    .await
428}
429
430/// POST /api/user-security-groups — 获取自选股分组列表
431pub async fn get_user_security_group(
432    State(state): State<RestState>,
433    Json(body): Json<Value>,
434) -> RawApiResult {
435    adapter::proto_request_raw::<
436        qot_get_user_security_group::Request,
437        qot_get_user_security_group::Response,
438    >(&state, proto_id::QOT_GET_USER_SECURITY_GROUP, Some(body))
439    .await
440}
441
442/// POST /api/stock-filter — 条件选股
443pub async fn stock_filter(State(state): State<RestState>, Json(body): Json<Value>) -> RawApiResult {
444    adapter::proto_request_raw::<qot_stock_filter::Request, qot_stock_filter::Response>(
445        &state,
446        proto_id::QOT_STOCK_FILTER,
447        Some(body),
448    )
449    .await
450}
451
452/// POST /api/ipo-list — 获取IPO列表
453pub async fn get_ipo_list(State(state): State<RestState>, Json(body): Json<Value>) -> RawApiResult {
454    adapter::proto_request_raw::<qot_get_ipo_list::Request, qot_get_ipo_list::Response>(
455        &state,
456        proto_id::QOT_GET_IPO_LIST,
457        Some(body),
458    )
459    .await
460}
461
462#[derive(Debug, Deserialize)]
463#[serde(deny_unknown_fields)]
464pub struct IpoCalendarRestReq {
465    market: i32,
466    #[serde(default, alias = "eventTypes")]
467    event_types: Vec<String>,
468    #[serde(default, alias = "beginDate")]
469    begin_date: Option<String>,
470    #[serde(default, alias = "endDate")]
471    end_date: Option<String>,
472}
473
474fn validate_ipo_calendar_req(req: &IpoCalendarRestReq) -> Result<(), (StatusCode, Json<Value>)> {
475    if !matches!(req.market, 1 | 2 | 11 | 21 | 22 | 31 | 41 | 61) {
476        return Err((
477            StatusCode::BAD_REQUEST,
478            Json(serde_json::json!({
479                "error": "market must be 1, 2, 11, 21, 22, 31, 41, or 61 (HK/HK_Future/US/SH/SZ/SG/JP/MY)"
480            })),
481        ));
482    }
483    for (field, value) in [
484        ("begin_date", req.begin_date.as_deref()),
485        ("end_date", req.end_date.as_deref()),
486    ] {
487        if let Some(value) = value
488            && !is_yyyymmdd(value)
489        {
490            return Err((
491                StatusCode::BAD_REQUEST,
492                Json(serde_json::json!({
493                    "error": format!("{field} must be YYYYMMDD")
494                })),
495            ));
496        }
497    }
498    if let (Some(begin), Some(end)) = (&req.begin_date, &req.end_date)
499        && begin > end
500    {
501        return Err((
502            StatusCode::BAD_REQUEST,
503            Json(serde_json::json!({
504                "error": "begin_date must be earlier than or equal to end_date"
505            })),
506        ));
507    }
508    if let Some(event) = req
509        .event_types
510        .iter()
511        .find(|event| !is_supported_ipo_event_type(event))
512    {
513        return Err((
514            StatusCode::BAD_REQUEST,
515            Json(serde_json::json!({
516                "error": format!("unsupported IPO calendar event_type {event:?}")
517            })),
518        ));
519    }
520    Ok(())
521}
522
523/// POST /api/ipo-calendar — IPO calendar projection over Qot_GetIpoList
524pub async fn get_ipo_calendar(
525    State(state): State<RestState>,
526    Json(req): Json<IpoCalendarRestReq>,
527) -> RawApiResult {
528    validate_ipo_calendar_req(&req)?;
529    let req_msg = futu_proto::qot_get_ipo_list::Request {
530        c2s: futu_proto::qot_get_ipo_list::C2s {
531            market: req.market,
532            header: None,
533        },
534    };
535    let conn_id = state.next_conn_id();
536    let serial_no = state.next_serial();
537    let incoming = IncomingRequest::builder(
538        conn_id,
539        proto_id::QOT_GET_IPO_LIST,
540        serial_no,
541        ProtoFmtType::Protobuf,
542        Bytes::from(req_msg.encode_to_vec()),
543    )
544    .build();
545    let resp_bytes = state
546        .router
547        .dispatch(incoming.conn_id, &incoming)
548        .await
549        .ok_or_else(|| {
550            (
551                StatusCode::INTERNAL_SERVER_ERROR,
552                Json(serde_json::json!({"error": "handler returned no response"})),
553            )
554        })?;
555    let resp =
556        futu_proto::qot_get_ipo_list::Response::decode(resp_bytes.as_slice()).map_err(|e| {
557            (
558                StatusCode::INTERNAL_SERVER_ERROR,
559                Json(serde_json::json!({"error": format!("failed to decode response: {e}")})),
560            )
561        })?;
562    if resp.ret_type != 0 {
563        let raw = serde_json::to_vec(&serde_json::json!({
564            "ret_type": resp.ret_type,
565            "ret_msg": resp.ret_msg,
566            "err_code": resp.err_code,
567            "events": []
568        }))
569        .map_err(|e| {
570            (
571                StatusCode::INTERNAL_SERVER_ERROR,
572                Json(serde_json::json!({"error": format!("failed to serialize response: {e}")})),
573            )
574        })?;
575        return Ok(adapter::RawJson::new(raw));
576    }
577    let s2c = resp.s2c.as_ref().ok_or_else(|| {
578        (
579            StatusCode::INTERNAL_SERVER_ERROR,
580            Json(serde_json::json!({"error": "missing s2c"})),
581        )
582    })?;
583    let events = collect_ipo_calendar_events(
584        s2c,
585        &req.event_types,
586        req.begin_date.as_deref(),
587        req.end_date.as_deref(),
588    );
589    let raw = serde_json::to_vec(&serde_json::json!({
590        "market": req.market,
591        "event_types": req.event_types,
592        "begin_date": req.begin_date,
593        "end_date": req.end_date,
594        "events": events
595    }))
596    .map_err(|e| {
597        (
598            StatusCode::INTERNAL_SERVER_ERROR,
599            Json(serde_json::json!({"error": format!("failed to serialize response: {e}")})),
600        )
601    })?;
602    Ok(adapter::RawJson::new(raw))
603}
604
605/// POST /api/future-info — 获取期货信息
606pub async fn get_future_info(
607    State(state): State<RestState>,
608    Json(body): Json<Value>,
609) -> RawApiResult {
610    adapter::proto_request_raw::<qot_get_future_info::Request, qot_get_future_info::Response>(
611        &state,
612        proto_id::QOT_GET_FUTURE_INFO,
613        Some(body),
614    )
615    .await
616}
617
618/// POST /api/market-state — 获取市场状态
619pub async fn get_market_state(
620    State(state): State<RestState>,
621    Json(body): Json<Value>,
622) -> RawApiResult {
623    adapter::proto_request_raw::<qot_get_market_state::Request, qot_get_market_state::Response>(
624        &state,
625        proto_id::QOT_GET_MARKET_STATE,
626        Some(body),
627    )
628    .await
629}
630
631/// POST /api/history-kline — 请求历史K线
632pub async fn request_history_kl(
633    State(state): State<RestState>,
634    Json(body): Json<Value>,
635) -> RawApiResult {
636    adapter::proto_request_raw::<qot_request_history_kl::Request, qot_request_history_kl::Response>(
637        &state,
638        proto_id::QOT_REQUEST_HISTORY_KL,
639        Some(body),
640    )
641    .await
642}
643
644// v1.4.30 新增
645
646/// POST /api/trading-days — 查询交易日(对齐 py-futu-api `request_trading_days`)
647pub async fn request_trading_days(
648    State(state): State<RestState>,
649    Json(body): Json<Value>,
650) -> RawApiResult {
651    adapter::proto_request_raw::<qot_request_trade_date::Request, qot_request_trade_date::Response>(
652        &state,
653        proto_id::QOT_REQUEST_TRADE_DATE,
654        Some(body),
655    )
656    .await
657}
658
659/// POST /api/rehab — 请求复权因子(对齐 py-futu-api `get_rehab`)
660pub async fn request_rehab(
661    State(state): State<RestState>,
662    Json(body): Json<Value>,
663) -> RawApiResult {
664    adapter::proto_request_raw::<qot_request_rehab::Request, qot_request_rehab::Response>(
665        &state,
666        proto_id::QOT_REQUEST_REHAB,
667        Some(body),
668    )
669    .await
670}
671
672/// POST /api/suspend — 获取停牌日(对齐 py-futu-api `get_suspend`)
673pub async fn get_suspend(State(state): State<RestState>, Json(body): Json<Value>) -> RawApiResult {
674    adapter::proto_request_raw::<qot_get_suspend::Request, qot_get_suspend::Response>(
675        &state,
676        proto_id::QOT_GET_SUSPEND,
677        Some(body),
678    )
679    .await
680}
681
682// v1.4.30 P2(100% 覆盖)
683
684/// POST /api/history-kl-quota — 历史 K 线配额
685pub async fn request_history_kl_quota(
686    State(state): State<RestState>,
687    Json(body): Json<Value>,
688) -> RawApiResult {
689    adapter::proto_request_raw::<
690        qot_request_history_kl_quota::Request,
691        qot_request_history_kl_quota::Response,
692    >(&state, proto_id::QOT_REQUEST_HISTORY_KL_QUOTA, Some(body))
693    .await
694}
695
696/// POST /api/used-quota — 当前 daemon 已用订阅额度与历史 K 线额度
697pub async fn get_used_quota(
698    State(state): State<RestState>,
699    Json(body): Json<Value>,
700) -> RawApiResult {
701    adapter::proto_request_raw::<used_quota::Request, used_quota::Response>(
702        &state,
703        proto_id::GET_USED_QUOTA,
704        Some(body),
705    )
706    .await
707}
708
709/// POST /api/holding-change — 持股变动
710pub async fn get_holding_change(
711    State(state): State<RestState>,
712    Json(body): Json<Value>,
713) -> RawApiResult {
714    adapter::proto_request_raw::<
715        qot_get_holding_change_list::Request,
716        qot_get_holding_change_list::Response,
717    >(&state, proto_id::QOT_GET_HOLDING_CHANGE_LIST, Some(body))
718    .await
719}
720
721/// POST /api/modify-user-security — 修改自选
722pub async fn modify_user_security(
723    State(state): State<RestState>,
724    Json(body): Json<Value>,
725) -> RawApiResult {
726    adapter::proto_request_raw::<
727        qot_modify_user_security::Request,
728        qot_modify_user_security::Response,
729    >(&state, proto_id::QOT_MODIFY_USER_SECURITY, Some(body))
730    .await
731}
732
733/// POST /api/code-change — 代码变更
734pub async fn get_code_change(
735    State(state): State<RestState>,
736    Json(body): Json<Value>,
737) -> RawApiResult {
738    adapter::proto_request_raw::<qot_get_code_change::Request, qot_get_code_change::Response>(
739        &state,
740        proto_id::QOT_GET_CODE_CHANGE,
741        Some(body),
742    )
743    .await
744}
745
746/// POST /api/set-price-reminder — 设置到价提醒
747pub async fn set_price_reminder(
748    State(state): State<RestState>,
749    Json(body): Json<Value>,
750) -> RawApiResult {
751    adapter::proto_request_raw::<qot_set_price_reminder::Request, qot_set_price_reminder::Response>(
752        &state,
753        proto_id::QOT_SET_PRICE_REMINDER,
754        Some(body),
755    )
756    .await
757}
758
759/// POST /api/price-reminder — 查询到价提醒
760pub async fn get_price_reminder(
761    State(state): State<RestState>,
762    Json(body): Json<Value>,
763) -> RawApiResult {
764    adapter::proto_request_raw::<qot_get_price_reminder::Request, qot_get_price_reminder::Response>(
765        &state,
766        proto_id::QOT_GET_PRICE_REMINDER,
767        Some(body),
768    )
769    .await
770}
771
772/// POST /api/option-expiration-date — 期权到期日
773pub async fn get_option_expiration_date(
774    State(state): State<RestState>,
775    Json(body): Json<Value>,
776) -> RawApiResult {
777    adapter::proto_request_raw::<
778        qot_get_option_expiration_date::Request,
779        qot_get_option_expiration_date::Response,
780    >(&state, proto_id::QOT_GET_OPTION_EXPIRATION_DATE, Some(body))
781    .await
782}