Skip to main content

futucli/cmd/trade_ext/
max_qtys.rs

1use anyhow::Result;
2use serde::Serialize;
3use tabled::Tabled;
4
5use crate::cmd::account::{parse_trd_env, parse_trd_market_for_write};
6use crate::common::connect_gateway;
7use crate::output::OutputFormat;
8use futu_trd::misc::{MaxTrdQtysParams, get_max_trd_qtys};
9use futu_trd::types::TrdHeader;
10
11use super::parsers::parse_order_type;
12
13// v1.4.98 eli BUG-005 fix (P2, 2026-04-27): _output 之前 unused, 用户传
14// `-o json` 仍打文本. 加 format-aware output.
15#[derive(Serialize, Tabled)]
16struct MaxQtysRow {
17    field: String,
18    value: String,
19}
20
21#[derive(Serialize)]
22struct MaxQtysJson {
23    code: String,
24    price: f64,
25    max_cash_buy: f64,
26    max_cash_and_margin_buy: f64,
27    max_position_sell: f64,
28    max_sell_short: f64,
29    max_buy_back: f64,
30}
31
32pub struct MaxQtysCommand<'a> {
33    pub gateway: &'a str,
34    pub env: &'a str,
35    pub acc_id: u64,
36    pub market: &'a str,
37    pub order_type: &'a str,
38    pub code: &'a str,
39    pub price: f64,
40    pub output: OutputFormat,
41}
42
43pub async fn run_max_qtys(input: MaxQtysCommand<'_>) -> Result<()> {
44    let env_p = parse_trd_env(input.env)?;
45    let market_p = parse_trd_market_for_write(input.market)?;
46    let ot_p = parse_order_type(input.order_type)?;
47    let params = MaxTrdQtysParams {
48        header: TrdHeader {
49            trd_env: env_p,
50            acc_id: input.acc_id,
51            trd_market: market_p,
52            jp_acc_type: None,
53        },
54        order_type: ot_p as i32,
55        code: input.code.to_string(),
56        price: input.price,
57        order_id: None,
58    };
59    let (client, _push_rx) = connect_gateway(input.gateway, "futucli-trade-ext").await?;
60    let s2c = get_max_trd_qtys(&client, &params).await?;
61    let q = s2c
62        .max_trd_qtys
63        .ok_or_else(|| anyhow::anyhow!("missing max_trd_qtys"))?;
64    let max_cash_buy = q.max_cash_buy;
65    let max_cash_and_margin = q.max_cash_and_margin_buy.unwrap_or(0.0);
66    let max_position_sell = q.max_position_sell;
67    let max_sell_short = q.max_sell_short.unwrap_or(0.0);
68    let max_buy_back = q.max_buy_back.unwrap_or(0.0);
69    let rows = vec![
70        MaxQtysRow {
71            field: "max_cash_buy".into(),
72            value: max_cash_buy.to_string(),
73        },
74        MaxQtysRow {
75            field: "max_cash_and_margin_buy".into(),
76            value: max_cash_and_margin.to_string(),
77        },
78        MaxQtysRow {
79            field: "max_position_sell".into(),
80            value: max_position_sell.to_string(),
81        },
82        MaxQtysRow {
83            field: "max_sell_short".into(),
84            value: max_sell_short.to_string(),
85        },
86        MaxQtysRow {
87            field: "max_buy_back".into(),
88            value: max_buy_back.to_string(),
89        },
90    ];
91    let json = MaxQtysJson {
92        code: input.code.to_string(),
93        price: input.price,
94        max_cash_buy,
95        max_cash_and_margin_buy: max_cash_and_margin,
96        max_position_sell,
97        max_sell_short,
98        max_buy_back,
99    };
100    if matches!(input.output, OutputFormat::Table) {
101        println!("max trd qtys for {} @ {}:", input.code, input.price);
102    }
103    input.output.print_rows(&rows, &[json])?;
104    Ok(())
105}