1use std::sync::Arc;
5
6use anyhow::Result;
7use futu_net::client::FutuClient;
8use futu_trd::{currency, read_plan};
9use serde::Serialize;
10
11use super::helpers::*;
12
13#[derive(Serialize)]
14struct FundsOut {
15 power: f64,
17 total_assets: f64,
18 cash: f64,
26 market_val: f64,
27 frozen_cash: f64,
28 debt_cash: f64,
29 avl_withdrawal_cash: f64,
30
31 #[serde(skip_serializing_if = "Option::is_none")]
34 currency: Option<i32>,
35 #[serde(skip_serializing_if = "Option::is_none")]
37 available_funds: Option<f64>,
38 #[serde(skip_serializing_if = "Option::is_none")]
40 unrealized_pl: Option<f64>,
41 #[serde(skip_serializing_if = "Option::is_none")]
43 realized_pl: Option<f64>,
44 #[serde(skip_serializing_if = "Option::is_none")]
46 risk_level: Option<i32>,
47 #[serde(skip_serializing_if = "Option::is_none")]
49 risk_status: Option<i32>,
50 #[serde(skip_serializing_if = "Option::is_none")]
52 initial_margin: Option<f64>,
53 #[serde(skip_serializing_if = "Option::is_none")]
55 maintenance_margin: Option<f64>,
56 #[serde(skip_serializing_if = "Option::is_none")]
58 margin_call_margin: Option<f64>,
59 #[serde(skip_serializing_if = "Option::is_none")]
61 max_power_short: Option<f64>,
62 net_cash_power: Option<f64>,
67 #[serde(skip_serializing_if = "Option::is_none")]
69 long_mv: Option<f64>,
70 #[serde(skip_serializing_if = "Option::is_none")]
72 short_mv: Option<f64>,
73 #[serde(skip_serializing_if = "Option::is_none")]
75 pending_asset: Option<f64>,
76 #[serde(skip_serializing_if = "Option::is_none")]
78 max_withdrawal: Option<f64>,
79 is_pdt: Option<bool>,
86 pdt_seq: Option<String>,
88 beginning_dtbp: Option<f64>,
91 remaining_dtbp: Option<f64>,
93 dt_call_amount: Option<f64>,
95 dt_status: Option<i32>,
97 #[serde(skip_serializing_if = "Option::is_none")]
99 securities_assets: Option<f64>,
100 fund_assets: Option<f64>,
102 bond_assets: Option<f64>,
104
105 #[serde(skip_serializing_if = "Vec::is_empty")]
108 cash_info_list: Vec<CashInfoOut>,
109 #[serde(skip_serializing_if = "Vec::is_empty")]
111 market_info_list: Vec<MarketInfoOut>,
112
113 #[serde(skip_serializing_if = "Option::is_none")]
116 currency_warning: Option<String>,
117}
118
119#[derive(Serialize)]
121struct CashInfoOut {
122 #[serde(skip_serializing_if = "Option::is_none")]
124 currency: Option<i32>,
125 #[serde(skip_serializing_if = "Option::is_none")]
127 cash: Option<f64>,
128 #[serde(skip_serializing_if = "Option::is_none")]
130 available_balance: Option<f64>,
131 #[serde(skip_serializing_if = "Option::is_none")]
133 net_cash_power: Option<f64>,
134}
135
136#[derive(Serialize)]
138struct MarketInfoOut {
139 #[serde(skip_serializing_if = "Option::is_none")]
141 trd_market: Option<i32>,
142 #[serde(skip_serializing_if = "Option::is_none")]
144 assets: Option<f64>,
145}
146
147pub async fn get_funds_with_currency(
154 client: &Arc<FutuClient>,
155 env: &str,
156 acc_id: u64,
157 market: &str,
158 currency: Option<&str>,
159) -> Result<String> {
160 let header = build_header(env, acc_id, market)?;
161 let currency_int: Option<i32> = match currency {
162 Some(s) => Some(currency::parse_currency_label(s)?),
163 None => None,
164 };
165 let f = futu_trd::account::get_funds_with_currency(client, &header, currency_int).await?;
166 let currency_warning = read_plan::funds_currency_mismatch_warning(currency_int, f.currency);
167 let out = FundsOut {
168 power: f.power,
169 total_assets: f.total_assets,
170 cash: f.cash,
171 market_val: f.market_val,
172 frozen_cash: f.frozen_cash,
173 debt_cash: f.debt_cash,
174 avl_withdrawal_cash: f.avl_withdrawal_cash,
175 currency: f.currency,
177 available_funds: f.available_funds,
178 unrealized_pl: f.unrealized_pl,
179 realized_pl: f.realized_pl,
180 risk_level: f.risk_level,
181 risk_status: f.risk_status,
182 initial_margin: f.initial_margin,
183 maintenance_margin: f.maintenance_margin,
184 margin_call_margin: f.margin_call_margin,
185 max_power_short: f.max_power_short,
186 net_cash_power: f.net_cash_power,
187 long_mv: f.long_mv,
188 short_mv: f.short_mv,
189 pending_asset: f.pending_asset,
190 max_withdrawal: f.max_withdrawal,
191 is_pdt: f.is_pdt,
192 pdt_seq: f.pdt_seq.clone(),
193 beginning_dtbp: f.beginning_dtbp,
195 remaining_dtbp: f.remaining_dtbp,
196 dt_call_amount: f.dt_call_amount,
197 dt_status: f.dt_status,
198 securities_assets: f.securities_assets,
199 fund_assets: f.fund_assets,
200 bond_assets: f.bond_assets,
201 cash_info_list: f
203 .cash_info_list
204 .iter()
205 .map(|c| CashInfoOut {
206 currency: c.currency,
207 cash: c.cash,
208 available_balance: c.available_balance,
209 net_cash_power: c.net_cash_power,
210 })
211 .collect(),
212 market_info_list: f
213 .market_info_list
214 .iter()
215 .map(|m| MarketInfoOut {
216 trd_market: m.trd_market,
217 assets: m.assets,
218 })
219 .collect(),
220 currency_warning,
221 };
222 Ok(serde_json::to_string_pretty(&out)?)
223}