1use num_enum::{FromPrimitive, IntoPrimitive};
2use rust_decimal::Decimal;
3use serde::{Deserialize, Deserializer, Serialize, Serializer};
4use strum_macros::{Display, EnumString};
5use time::{Date, OffsetDateTime};
6
7use crate::{Market, serde_utils};
8
9#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, EnumString, Display)]
11#[allow(clippy::upper_case_acronyms)]
12pub enum OrderType {
13 Unknown,
15 #[strum(serialize = "LO")]
17 LO,
18 #[strum(serialize = "ELO")]
20 ELO,
21 #[strum(serialize = "MO")]
23 MO,
24 #[strum(serialize = "AO")]
26 AO,
27 #[strum(serialize = "ALO")]
29 ALO,
30 #[strum(serialize = "ODD")]
32 ODD,
33 #[strum(serialize = "LIT")]
35 LIT,
36 #[strum(serialize = "MIT")]
38 MIT,
39 #[strum(serialize = "TSLPAMT")]
41 TSLPAMT,
42 #[strum(serialize = "TSLPPCT")]
44 TSLPPCT,
45 #[strum(serialize = "TSMAMT")]
47 TSMAMT,
48 #[strum(serialize = "TSMPCT")]
50 TSMPCT,
51 #[strum(serialize = "SLO")]
53 SLO,
54}
55
56#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, EnumString, Display)]
58pub enum OrderStatus {
59 Unknown,
61 #[strum(serialize = "NotReported")]
63 NotReported,
64 #[strum(serialize = "ReplacedNotReported")]
66 ReplacedNotReported,
67 #[strum(serialize = "ProtectedNotReported")]
69 ProtectedNotReported,
70 #[strum(serialize = "VarietiesNotReported")]
72 VarietiesNotReported,
73 #[strum(serialize = "FilledStatus")]
75 Filled,
76 #[strum(serialize = "WaitToNew")]
78 WaitToNew,
79 #[strum(serialize = "NewStatus")]
81 New,
82 #[strum(serialize = "WaitToReplace")]
84 WaitToReplace,
85 #[strum(serialize = "PendingReplaceStatus")]
87 PendingReplace,
88 #[strum(serialize = "ReplacedStatus")]
90 Replaced,
91 #[strum(serialize = "PartialFilledStatus")]
93 PartialFilled,
94 #[strum(serialize = "WaitToCancel")]
96 WaitToCancel,
97 #[strum(serialize = "PendingCancelStatus")]
99 PendingCancel,
100 #[strum(serialize = "RejectedStatus")]
102 Rejected,
103 #[strum(serialize = "CanceledStatus")]
105 Canceled,
106 #[strum(serialize = "ExpiredStatus")]
108 Expired,
109 #[strum(serialize = "PartialWithdrawal")]
111 PartialWithdrawal,
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct Execution {
117 pub order_id: String,
119 pub trade_id: String,
121 pub symbol: String,
123 #[serde(
125 serialize_with = "time::serde::rfc3339::serialize",
126 deserialize_with = "serde_utils::timestamp::deserialize"
127 )]
128 pub trade_done_at: OffsetDateTime,
129 pub quantity: Decimal,
131 pub price: Decimal,
133 pub side: OrderSide,
135}
136
137#[derive(Debug, Clone, Serialize, Deserialize)]
139pub struct AllExecutionsResponse {
140 pub has_more: bool,
142 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
144 pub trades: Vec<Execution>,
145}
146
147#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, EnumString, Display)]
149pub enum OrderSide {
150 Unknown,
152 #[strum(serialize = "Buy")]
154 Buy,
155 #[strum(serialize = "Sell")]
157 Sell,
158}
159
160#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, EnumString, Display)]
162pub enum TriggerPriceType {
163 Unknown,
165 #[strum(serialize = "LIT")]
167 LimitIfTouched,
168 #[strum(serialize = "MIT")]
170 MarketIfTouched,
171}
172
173#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, EnumString, Display)]
175pub enum OrderTag {
176 Unknown,
178 #[strum(serialize = "Normal")]
180 Normal,
181 #[strum(serialize = "Gtc")]
183 LongTerm,
184 #[strum(serialize = "Grey")]
186 Grey,
187}
188
189#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, EnumString, Display)]
191pub enum TimeInForceType {
192 Unknown,
194 #[strum(serialize = "Day")]
196 Day,
197 #[strum(serialize = "GTC")]
199 GoodTilCanceled,
200 #[strum(serialize = "GTD")]
202 GoodTilDate,
203}
204
205#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, EnumString, Display)]
207pub enum TriggerStatus {
208 Unknown,
210 #[strum(serialize = "DEACTIVE")]
212 Deactive,
213 #[strum(serialize = "ACTIVE")]
215 Active,
216 #[strum(serialize = "RELEASED")]
218 Released,
219}
220
221#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, EnumString, Display)]
223pub enum OutsideRTH {
224 Unknown,
226 #[strum(serialize = "RTH_ONLY")]
228 RTHOnly,
229 #[strum(serialize = "ANY_TIME")]
231 AnyTime,
232 #[strum(serialize = "OVERNIGHT")]
234 Overnight,
235 #[strum(serialize = "OPTION_PRE_MARKET")]
237 OptionPreMarket,
238}
239
240#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, EnumString, Display)]
242pub enum AttachedOrderType {
243 Unknown,
245 #[strum(serialize = "PROFIT_TAKER")]
247 ProfitTaker,
248 #[strum(serialize = "STOP_LOSS")]
250 StopLoss,
251 #[strum(serialize = "BRACKET")]
253 Bracket,
254}
255
256#[derive(Debug, Clone, Serialize, Deserialize)]
258pub struct AttachedOrderDetail {
259 pub order_id: String,
261 pub attached_type_display: AttachedOrderType,
263 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
265 pub trigger_price: Option<Decimal>,
266 pub quantity: Decimal,
268 pub executed_qty: Decimal,
270 pub status: OrderStatus,
272 #[serde(
274 serialize_with = "time::serde::rfc3339::serialize",
275 deserialize_with = "serde_utils::timestamp::deserialize"
276 )]
277 pub updated_at: OffsetDateTime,
278 pub withdrawn: bool,
280 #[serde(with = "serde_utils::date_opt")]
282 pub gtd: Option<Date>,
283 pub time_in_force: TimeInForceType,
285 pub counter_id: String,
287 #[serde(with = "serde_utils::trigger_status")]
289 pub trigger_status: Option<TriggerStatus>,
290 pub executed_amount: Decimal,
292 pub tag: OrderTag,
294 #[serde(
296 serialize_with = "time::serde::rfc3339::serialize",
297 deserialize_with = "serde_utils::timestamp::deserialize"
298 )]
299 pub submitted_at: OffsetDateTime,
300 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
302 pub executed_price: Option<Decimal>,
303 #[serde(with = "serde_utils::outside_rth")]
305 pub force_only_rth: Option<OutsideRTH>,
306 pub reviewed: bool,
308 pub activate_order_type: OrderType,
310 #[serde(with = "serde_utils::outside_rth")]
312 pub activate_rth: Option<OutsideRTH>,
313 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
315 pub submit_price: Option<Decimal>,
316}
317
318#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, EnumString, Display)]
320pub enum MultiLegStrategy {
321 Unknown,
323 #[strum(to_string = "CoveredCall", serialize = "0")]
325 CoveredCall,
326 #[strum(to_string = "CoveredPut", serialize = "1")]
328 CoveredPut,
329 #[strum(to_string = "VerticalCallSpread", serialize = "2")]
331 VerticalCallSpread,
332 #[strum(to_string = "VerticalPutSpread", serialize = "3")]
334 VerticalPutSpread,
335 #[strum(to_string = "Collar", serialize = "4")]
337 Collar,
338 #[strum(to_string = "Straddle", serialize = "5")]
340 Straddle,
341 #[strum(to_string = "Strangle", serialize = "6")]
343 Strangle,
344 #[strum(to_string = "CalendarCallSpread", serialize = "7")]
346 CalendarCallSpread,
347 #[strum(to_string = "CalendarPutSpread", serialize = "8")]
349 CalendarPutSpread,
350}
351
352#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, EnumString, Display)]
354pub enum MultiLegPosition {
355 Unknown,
357 #[strum(serialize = "LONG")]
359 Long,
360 #[strum(serialize = "SHORT")]
362 Short,
363}
364
365#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, EnumString, Display)]
367pub enum ContractDirection {
368 Unknown,
370 #[strum(serialize = "C")]
372 Call,
373 #[strum(serialize = "P")]
375 Put,
376}
377
378#[derive(Debug, Clone, Serialize, Deserialize)]
380pub struct MultiLegOrderLeg {
381 pub symbol: String,
383 pub side: OrderSide,
385 pub position: MultiLegPosition,
387 #[serde(with = "serde_utils::decimal_empty_is_0")]
389 pub ratio_quantity: Decimal,
390 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
392 pub strike_price: Option<Decimal>,
393 #[serde(default, with = "serde_utils::date_ymd_opt")]
395 pub expire_date: Option<Date>,
396 pub contract_direction: ContractDirection,
398}
399
400#[derive(Debug, Clone, Serialize, Deserialize)]
402pub struct MultiLegInfo {
403 pub strategy: MultiLegStrategy,
405 pub strategy_name: String,
407 pub multileg_id: String,
409 pub code: String,
411 #[serde(default)]
413 pub legs: Vec<MultiLegOrderLeg>,
414}
415
416#[derive(Debug, Clone, Serialize, Deserialize)]
418pub struct Order {
419 pub order_id: String,
421 pub status: OrderStatus,
423 pub stock_name: String,
425 pub quantity: Decimal,
427 pub executed_quantity: Decimal,
429 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
431 pub price: Option<Decimal>,
432 #[serde(with = "serde_utils::decimal_opt_0_is_none")]
434 pub executed_price: Option<Decimal>,
435 #[serde(
437 serialize_with = "time::serde::rfc3339::serialize",
438 deserialize_with = "serde_utils::timestamp::deserialize"
439 )]
440 pub submitted_at: OffsetDateTime,
441 pub side: OrderSide,
443 pub symbol: String,
445 pub order_type: OrderType,
447 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
449 pub last_done: Option<Decimal>,
450 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
452 pub trigger_price: Option<Decimal>,
453 pub msg: String,
455 pub tag: OrderTag,
457 pub time_in_force: TimeInForceType,
459 #[serde(with = "serde_utils::date_opt")]
461 pub expire_date: Option<Date>,
462 #[serde(
464 deserialize_with = "serde_utils::timestamp_opt::deserialize",
465 serialize_with = "serde_utils::rfc3339_opt::serialize"
466 )]
467 pub updated_at: Option<OffsetDateTime>,
468 #[serde(
470 deserialize_with = "serde_utils::timestamp_opt::deserialize",
471 serialize_with = "serde_utils::rfc3339_opt::serialize"
472 )]
473 pub trigger_at: Option<OffsetDateTime>,
474 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
476 pub trailing_amount: Option<Decimal>,
477 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
479 pub trailing_percent: Option<Decimal>,
480 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
482 pub limit_offset: Option<Decimal>,
483 #[serde(with = "serde_utils::trigger_status")]
485 pub trigger_status: Option<TriggerStatus>,
486 pub currency: String,
488 #[serde(with = "serde_utils::outside_rth")]
490 pub outside_rth: Option<OutsideRTH>,
491 #[serde(with = "serde_utils::int32_opt_0_is_none")]
493 pub limit_depth_level: Option<i32>,
494 #[serde(with = "serde_utils::int32_opt_0_is_none")]
496 pub trigger_count: Option<i32>,
497 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
499 pub monitor_price: Option<Decimal>,
500 pub remark: String,
502 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
504 pub attached_orders: Vec<AttachedOrderDetail>,
505 #[serde(default)]
508 pub multi_leg: Option<MultiLegInfo>,
509}
510
511#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, EnumString, Display)]
513pub enum CommissionFreeStatus {
514 Unknown,
516 None,
518 Calculated,
520 Pending,
522 Ready,
524}
525
526#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, EnumString, Display)]
528pub enum DeductionStatus {
529 Unknown,
531 #[strum(serialize = "NONE")]
533 None,
534 #[strum(serialize = "NO_DATA")]
536 NoData,
537 #[strum(serialize = "PENDING")]
539 Pending,
540 #[strum(serialize = "DONE")]
542 Done,
543}
544
545#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, EnumString, Display)]
547pub enum ChargeCategoryCode {
548 Unknown,
550 #[strum(serialize = "BROKER_FEES")]
552 Broker,
553 #[strum(serialize = "THIRD_FEES")]
555 Third,
556}
557
558#[derive(Debug, Clone, Serialize, Deserialize)]
560pub struct OrderHistoryDetail {
561 #[serde(with = "serde_utils::decimal_empty_is_0")]
564 pub price: Decimal,
565 #[serde(with = "serde_utils::decimal_empty_is_0")]
568 pub quantity: Decimal,
569 pub status: OrderStatus,
571 pub msg: String,
573 #[serde(
575 serialize_with = "time::serde::rfc3339::serialize",
576 deserialize_with = "serde_utils::timestamp::deserialize"
577 )]
578 pub time: OffsetDateTime,
579}
580
581#[derive(Debug, Clone, Serialize, Deserialize)]
583pub struct OrderChargeFee {
584 pub code: String,
586 pub name: String,
588 #[serde(with = "serde_utils::decimal_empty_is_0")]
590 pub amount: Decimal,
591 pub currency: String,
593}
594
595#[derive(Debug, Clone, Serialize, Deserialize)]
597pub struct OrderChargeItem {
598 pub code: ChargeCategoryCode,
600 pub name: String,
602 pub fees: Vec<OrderChargeFee>,
604}
605
606#[derive(Debug, Clone, Serialize, Deserialize)]
608pub struct OrderChargeDetail {
609 pub total_amount: Decimal,
611 pub currency: String,
613 pub items: Vec<OrderChargeItem>,
615}
616
617#[derive(Debug, Clone, Serialize, Deserialize)]
619pub struct OrderDetail {
620 pub order_id: String,
622 pub status: OrderStatus,
624 pub stock_name: String,
626 pub quantity: Decimal,
628 pub executed_quantity: Decimal,
630 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
632 pub price: Option<Decimal>,
633 #[serde(with = "serde_utils::decimal_opt_0_is_none")]
635 pub executed_price: Option<Decimal>,
636 #[serde(
638 serialize_with = "time::serde::rfc3339::serialize",
639 deserialize_with = "serde_utils::timestamp::deserialize"
640 )]
641 pub submitted_at: OffsetDateTime,
642 pub side: OrderSide,
644 pub symbol: String,
646 pub order_type: OrderType,
648 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
650 pub last_done: Option<Decimal>,
651 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
653 pub trigger_price: Option<Decimal>,
654 pub msg: String,
656 pub tag: OrderTag,
658 pub time_in_force: TimeInForceType,
660 #[serde(with = "serde_utils::date_opt")]
662 pub expire_date: Option<Date>,
663 #[serde(
665 deserialize_with = "serde_utils::timestamp_opt::deserialize",
666 serialize_with = "serde_utils::rfc3339_opt::serialize"
667 )]
668 pub updated_at: Option<OffsetDateTime>,
669 #[serde(
671 deserialize_with = "serde_utils::timestamp_opt::deserialize",
672 serialize_with = "serde_utils::rfc3339_opt::serialize"
673 )]
674 pub trigger_at: Option<OffsetDateTime>,
675 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
677 pub trailing_amount: Option<Decimal>,
678 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
680 pub trailing_percent: Option<Decimal>,
681 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
683 pub limit_offset: Option<Decimal>,
684 #[serde(with = "serde_utils::trigger_status")]
686 pub trigger_status: Option<TriggerStatus>,
687 pub currency: String,
689 #[serde(with = "serde_utils::outside_rth")]
691 pub outside_rth: Option<OutsideRTH>,
692 #[serde(with = "serde_utils::int32_opt_0_is_none")]
694 pub limit_depth_level: Option<i32>,
695 #[serde(with = "serde_utils::int32_opt_0_is_none")]
697 pub trigger_count: Option<i32>,
698 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
700 pub monitor_price: Option<Decimal>,
701 pub remark: String,
703 pub free_status: CommissionFreeStatus,
705 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
707 pub free_amount: Option<Decimal>,
708 #[serde(with = "serde_utils::symbol_opt")]
710 pub free_currency: Option<String>,
711 pub deductions_status: DeductionStatus,
713 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
715 pub deductions_amount: Option<Decimal>,
716 #[serde(with = "serde_utils::symbol_opt")]
718 pub deductions_currency: Option<String>,
719 pub platform_deducted_status: DeductionStatus,
721 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
723 pub platform_deducted_amount: Option<Decimal>,
724 #[serde(with = "serde_utils::symbol_opt")]
726 pub platform_deducted_currency: Option<String>,
727 pub history: Vec<OrderHistoryDetail>,
729 pub charge_detail: Option<OrderChargeDetail>,
731 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
733 pub attached_orders: Vec<AttachedOrderDetail>,
734 #[serde(default)]
737 pub multi_leg: Option<MultiLegInfo>,
738}
739
740#[derive(Debug, Clone, Serialize, Deserialize)]
742pub struct CashInfo {
743 pub withdraw_cash: Decimal,
745 pub available_cash: Decimal,
747 pub frozen_cash: Decimal,
749 pub settling_cash: Decimal,
751 pub currency: String,
753}
754
755#[derive(Debug, Clone, Serialize, Deserialize)]
757pub struct FrozenTransactionFee {
758 pub currency: String,
760 pub frozen_transaction_fee: Decimal,
762}
763
764#[derive(Debug, Clone, Serialize, Deserialize)]
766pub struct AccountBalance {
767 pub total_cash: Decimal,
769 pub max_finance_amount: Decimal,
771 pub remaining_finance_amount: Decimal,
773 #[serde(with = "serde_utils::risk_level")]
775 pub risk_level: i32,
776 pub margin_call: Decimal,
778 pub currency: String,
780 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
782 pub cash_infos: Vec<CashInfo>,
783 #[serde(with = "serde_utils::decimal_empty_is_0")]
785 pub net_assets: Decimal,
786 #[serde(with = "serde_utils::decimal_empty_is_0")]
788 pub init_margin: Decimal,
789 #[serde(with = "serde_utils::decimal_empty_is_0")]
791 pub maintenance_margin: Decimal,
792 #[serde(with = "serde_utils::decimal_empty_is_0")]
794 pub buy_power: Decimal,
795 pub frozen_transaction_fees: Vec<FrozenTransactionFee>,
797}
798
799#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, FromPrimitive, IntoPrimitive)]
801#[repr(i32)]
802pub enum BalanceType {
803 #[num_enum(default)]
805 Unknown = 0,
806 Cash = 1,
808 Stock = 2,
810 Fund = 3,
812}
813
814impl Serialize for BalanceType {
815 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
816 let value: i32 = (*self).into();
817 value.serialize(serializer)
818 }
819}
820
821impl<'de> Deserialize<'de> for BalanceType {
822 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
823 let value = i32::deserialize(deserializer)?;
824 Ok(BalanceType::from(value))
825 }
826}
827
828#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, FromPrimitive, Serialize)]
830#[repr(i32)]
831pub enum CashFlowDirection {
832 #[num_enum(default)]
834 Unknown,
835 Out = 1,
837 In = 2,
839}
840
841impl<'de> Deserialize<'de> for CashFlowDirection {
842 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
843 let value = i32::deserialize(deserializer)?;
844 Ok(CashFlowDirection::from(value))
845 }
846}
847
848#[derive(Debug, Clone, Serialize, Deserialize)]
850pub struct CashFlow {
851 pub transaction_flow_name: String,
853 pub direction: CashFlowDirection,
855 pub business_type: BalanceType,
857 pub balance: Decimal,
859 pub currency: String,
861 #[serde(
863 serialize_with = "time::serde::rfc3339::serialize",
864 deserialize_with = "serde_utils::timestamp::deserialize"
865 )]
866 pub business_time: OffsetDateTime,
867 #[serde(with = "serde_utils::symbol_opt")]
869 pub symbol: Option<String>,
870 pub description: String,
872}
873
874#[derive(Debug, Clone, Serialize, Deserialize)]
876pub struct FundPositionsResponse {
877 #[serde(rename = "list")]
879 pub channels: Vec<FundPositionChannel>,
880}
881
882#[derive(Debug, Clone, Serialize, Deserialize)]
884pub struct FundPositionChannel {
885 pub account_channel: String,
887
888 #[serde(
890 default,
891 deserialize_with = "crate::serde_utils::null_as_default",
892 rename = "fund_info"
893 )]
894 pub positions: Vec<FundPosition>,
895}
896
897#[derive(Debug, Clone, Serialize, Deserialize)]
899pub struct FundPosition {
900 pub symbol: String,
902 #[serde(with = "serde_utils::decimal_empty_is_0")]
904 pub current_net_asset_value: Decimal,
905 #[serde(
907 serialize_with = "time::serde::rfc3339::serialize",
908 deserialize_with = "serde_utils::timestamp::deserialize"
909 )]
910 pub net_asset_value_day: OffsetDateTime,
911 pub symbol_name: String,
913 pub currency: String,
915 #[serde(with = "serde_utils::decimal_empty_is_0")]
917 pub cost_net_asset_value: Decimal,
918 #[serde(with = "serde_utils::decimal_empty_is_0")]
920 pub holding_units: Decimal,
921}
922
923#[derive(Debug, Clone, Serialize, Deserialize)]
925pub struct StockPositionsResponse {
926 #[serde(rename = "list")]
928 pub channels: Vec<StockPositionChannel>,
929}
930
931#[derive(Debug, Clone, Serialize, Deserialize)]
933pub struct StockPositionChannel {
934 pub account_channel: String,
936
937 #[serde(
939 default,
940 deserialize_with = "crate::serde_utils::null_as_default",
941 rename = "stock_info"
942 )]
943 pub positions: Vec<StockPosition>,
944}
945
946#[derive(Debug, Clone, Serialize, Deserialize)]
948pub struct StockPosition {
949 pub symbol: String,
951 pub symbol_name: String,
953 pub quantity: Decimal,
955 pub available_quantity: Decimal,
957 pub currency: String,
959 #[serde(with = "serde_utils::decimal_empty_is_0")]
962 pub cost_price: Decimal,
963 pub market: Market,
965 #[serde(with = "serde_utils::decimal_opt_empty_is_none")]
967 pub init_quantity: Option<Decimal>,
968}
969
970#[derive(Debug, Clone, Serialize, Deserialize)]
972pub struct MarginRatio {
973 pub im_factor: Decimal,
975 pub mm_factor: Decimal,
977 pub fm_factor: Decimal,
979}
980
981impl_serde_for_enum_string!(
982 OrderType,
983 OrderStatus,
984 OrderSide,
985 TriggerPriceType,
986 OrderTag,
987 TimeInForceType,
988 TriggerStatus,
989 OutsideRTH,
990 CommissionFreeStatus,
991 DeductionStatus,
992 ChargeCategoryCode
993);
994impl_serde_for_enum_string!(AttachedOrderType);
995impl_default_for_enum_string!(AttachedOrderType);
996impl_serde_for_enum_string!(MultiLegStrategy, MultiLegPosition, ContractDirection);
997impl_default_for_enum_string!(MultiLegStrategy, MultiLegPosition, ContractDirection);
998impl_default_for_enum_string!(
999 OrderType,
1000 OrderStatus,
1001 OrderSide,
1002 TriggerPriceType,
1003 OrderTag,
1004 TimeInForceType,
1005 TriggerStatus,
1006 OutsideRTH,
1007 CommissionFreeStatus,
1008 DeductionStatus,
1009 ChargeCategoryCode
1010);
1011
1012#[derive(Debug, Clone, Default)]
1024pub struct GetUSHistoryOrders {
1025 pub symbol: Option<String>,
1027 pub side: OrderSide,
1029 pub start_at: i64,
1031 pub end_at: i64,
1033 pub query_type: i32,
1035 pub page: i32,
1037 pub limit: i32,
1039}
1040
1041pub type QueryUSOrdersOptions = GetUSHistoryOrders;
1043
1044#[derive(Debug, Clone, Serialize)]
1046pub(crate) struct USQueryOrdersBody {
1047 pub account_channel: String,
1048 pub action: i32,
1049 pub start_at: f64,
1050 pub end_at: f64,
1051 pub symbols: Vec<String>,
1052 pub security_types: Vec<String>,
1053 pub query_type: i32,
1054 pub page: i32,
1055 pub limit: i32,
1056 pub query_version: f64,
1057}
1058
1059#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1061pub struct QueryUSOrdersResponse {
1062 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1065 pub orders: Vec<serde_json::Value>,
1066 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1068 pub total_count: i32,
1069}
1070
1071#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1073pub struct USOrderHistory {
1074 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1076 pub exec_type: i32,
1077 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1079 pub status: String,
1080 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1082 pub price: String,
1083 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1085 pub qty: String,
1086 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1088 pub time: String,
1089 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1091 pub msg: String,
1092 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1094 pub is_manually: bool,
1095 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1097 pub opp_party_id: String,
1098 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1100 pub trd_match_id: String,
1101 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1103 pub operator: String,
1104 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1106 pub op_entrust_way: String,
1107 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1109 pub cxl_rej_response_to: i32,
1110 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1112 pub withdrawal_reason: String,
1113 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1115 pub opp_name: String,
1116 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1118 pub exec_id: String,
1119}
1120
1121#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1123pub struct USButtonControl {
1124 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1126 pub withdraw: i32,
1127 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1129 pub replace: i32,
1130 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1132 pub exceptionable: Vec<String>,
1133}
1134
1135#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1137pub struct USChargeItem {
1138 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1140 pub code: i32,
1141 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1143 pub name: String,
1144 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1146 pub fees: Vec<String>,
1147}
1148
1149#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1151pub struct USChargeDetail {
1152 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1154 pub currency: String,
1155 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1157 pub total_amount: String,
1158 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1160 pub items: Vec<USChargeItem>,
1161}
1162
1163#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1165pub struct USAttachedOrder {
1166 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1168 pub attached_type_display: i32,
1169 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1171 pub executed_qty: String,
1172 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1174 pub quantity: String,
1175 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1177 pub status: String,
1178 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1180 pub trigger_price: String,
1181 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1183 pub order_id: String,
1184 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1186 pub gtd: String,
1187 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1189 pub time_in_force: i32,
1190 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1192 pub tag: i32,
1193 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1195 pub activate_order_type: String,
1196 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1198 pub activate_rth: i32,
1199 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1201 pub submit_price: String,
1202 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1204 pub symbol: String,
1205 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1207 pub withdrawn: bool,
1208}
1209
1210#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1215pub struct USOrderDetail {
1216 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1218 pub id: String,
1219 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1221 pub aaid: String,
1222 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1224 pub account_channel: String,
1225 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1227 pub action: i32,
1228 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1230 pub symbol: String,
1231 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1233 pub underlying_symbol: String,
1234 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1236 pub security_type: String,
1237 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1239 pub name: String,
1240 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1242 pub currency: String,
1243 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1245 pub trade_currency: String,
1246 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1248 pub order_type: String,
1249 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1251 pub status: String,
1252 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1254 pub price: String,
1255 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1257 pub quantity: String,
1258 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1260 pub executed_qty: String,
1261 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1263 pub executed_price: String,
1264 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1266 pub executed_amount: String,
1267 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1269 pub operate_direction: String,
1270 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1272 pub time_in_force: i32,
1273 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1275 pub gtd: String,
1276 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1278 pub tag: i32,
1279 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1281 pub msg: String,
1282 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1284 pub force_only_rth: i32,
1285 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1287 pub submitted_at: String,
1288 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1290 pub done_at: String,
1291 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1293 pub trigger_price: String,
1294 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1296 pub trigger_at: String,
1297 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1299 pub trigger_status: i32,
1300 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1302 pub trigger_exchange: String,
1303 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1305 pub trigger_last_done: String,
1306 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1308 pub trigger_count: i32,
1309 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1311 pub tailing_amount: String,
1312 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1314 pub tailing_percent: String,
1315 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1317 pub limit_offset: String,
1318 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1320 pub limit_depth_level: i32,
1321 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1323 pub market_price: String,
1324 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1326 pub submitted_amount: String,
1327 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1329 pub estimated_fee: String,
1330 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1332 pub free_status: i32,
1333 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1335 pub free_amount: String,
1336 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1338 pub free_currency: String,
1339 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1341 pub deductions_status: i32,
1342 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1344 pub deductions_amount: String,
1345 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1347 pub deductions_currency: String,
1348 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1350 pub platform_deductions_status: i32,
1351 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1353 pub platform_deductions_amount: String,
1354 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1356 pub platform_deductions_currency: String,
1357 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1359 pub display_account: String,
1360 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1362 pub settlement_account: String,
1363 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1365 pub settlement_channel: String,
1366 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1368 pub customer_name: String,
1369 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1371 pub real_name: String,
1372 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1374 pub en_name: String,
1375 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1377 pub joint_real_name: String,
1378 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1380 pub joint_en_name: String,
1381 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1383 pub org_id: String,
1384 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1386 pub bcan: String,
1387 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1389 pub op_entrust_way: i32,
1390 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1392 pub op_entrust_way_name: String,
1393 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1395 pub remark: String,
1396 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1398 pub notice: String,
1399 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1401 pub short_sell_type: i32,
1402 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1404 pub ploy_type: String,
1405 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1407 pub ploy_id: String,
1408 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1410 pub ploy_status: String,
1411 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1413 pub trend: i32,
1414 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1416 pub withdrawal_reason: String,
1417 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1419 pub activate_order_type: String,
1420 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1422 pub activate_rth: i32,
1423 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1425 pub submit_price: String,
1426 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1428 pub contract_direction: String,
1429 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1431 pub strike_price: String,
1432 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1434 pub contract_size: String,
1435 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1437 pub monitor_price: String,
1438 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1440 pub button_control: USButtonControl,
1441 pub charge_detail: Option<USChargeDetail>,
1443 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1445 pub attached_orders: Vec<USAttachedOrder>,
1446 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1448 pub order_histories: Vec<USOrderHistory>,
1449}
1450
1451#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1454pub struct USOrderDetailResponse {
1455 pub order: Option<USOrderDetail>,
1457 pub current_attached_order: Option<USOrderDetail>,
1459 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1461 pub current_millisecond: String,
1462}
1463
1464#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1466pub struct USCashEntry {
1467 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1469 pub currency: String,
1470 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1472 pub frozen_buy_cash: String,
1473 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1475 pub outstanding: String,
1476 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1478 pub settled_cash: String,
1479 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1481 pub total_amount: String,
1482 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1484 pub total_cash: String,
1485}
1486
1487#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1489pub struct USCryptoEntry {
1490 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1492 pub asset_type: String,
1493 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1495 pub average_cost: String,
1496 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1498 pub symbol: String,
1499 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1501 pub currency: String,
1502 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1504 pub industry_name: String,
1505}
1506
1507#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1509pub struct USStockEntry {
1510 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1513 pub symbol: String,
1514 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1516 pub full_symbol: String,
1517 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1519 pub asset_type: String,
1520 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1522 pub quantity: String,
1523 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1525 pub currency: String,
1526 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1528 pub average_cost: String,
1529 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1531 pub market: String,
1532 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1534 pub trade_status: String,
1535 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1537 pub prev_close: String,
1538 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1540 pub last_done: String,
1541 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1543 pub market_price: String,
1544 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1546 pub pretrade_close: String,
1547 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1549 pub stock_invest_of_today: String,
1550 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1552 pub today_pl: String,
1553 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1555 pub pretrade_stock_invest_of_today: String,
1556 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1558 pub pretrade_today_pl: String,
1559 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1561 pub night_last_done: String,
1562 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1564 pub night_prev_close: String,
1565 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1567 pub position_side: String,
1568 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1570 pub open_position_time: String,
1571 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1573 pub name: String,
1574 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1576 pub industry_counter_id: String,
1577 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1579 pub industry_name: String,
1580}
1581
1582#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1585pub struct USAssetOverview {
1586 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1588 pub account_type: String,
1589 #[serde(default, with = "crate::serde_utils::timestamp_opt")]
1591 pub asset_timestamp: Option<time::OffsetDateTime>,
1592 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1594 pub cash_buy_power: String,
1595 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1597 pub overnight_buy_power: String,
1598 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1600 pub currency: String,
1601 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1603 pub cash_list: Vec<USCashEntry>,
1604 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1606 pub stock_list: Vec<USStockEntry>,
1607 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1609 pub option_list: Vec<serde_json::Value>,
1610 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1612 pub crypto_list: Vec<USCryptoEntry>,
1613 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1615 pub multi_leg: serde_json::Value,
1616}
1617
1618#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1620pub struct USRealizedPLMetric {
1621 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1623 pub amount: String,
1624 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1626 pub period: i32,
1627 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1629 pub rate: String,
1630}
1631
1632#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1635pub struct USRealizedPLEntry {
1636 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1638 pub category: i32,
1639 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1641 pub currency: String,
1642 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1644 pub metrics: Vec<USRealizedPLMetric>,
1645}
1646
1647#[derive(Debug, Clone, Default)]
1650pub struct GetUSRealizedPLOptions {
1651 pub currency: String,
1653 pub category: String,
1655}
1656
1657#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1661pub struct USRealizedPL {
1662 #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
1664 pub realized_pl_list: Vec<USRealizedPLEntry>,
1665}
1666
1667#[cfg(test)]
1668mod tests {
1669 use time::macros::datetime;
1670
1671 use super::*;
1672
1673 #[test]
1674 fn fund_position_response() {
1675 let data = r#"
1676 {
1677 "list": [{
1678 "account_channel": "lb",
1679 "fund_info": [{
1680 "symbol": "HK0000447943",
1681 "symbol_name": "高腾亚洲收益基金",
1682 "currency": "USD",
1683 "holding_units": "5.000",
1684 "current_net_asset_value": "0",
1685 "cost_net_asset_value": "0.00",
1686 "net_asset_value_day": "1649865600"
1687 }]
1688 }]
1689 }
1690 "#;
1691
1692 let resp: FundPositionsResponse = serde_json::from_str(data).unwrap();
1693 assert_eq!(resp.channels.len(), 1);
1694
1695 let channel = &resp.channels[0];
1696 assert_eq!(channel.account_channel, "lb");
1697 assert_eq!(channel.positions.len(), 1);
1698
1699 let position = &channel.positions[0];
1700 assert_eq!(position.symbol, "HK0000447943");
1701 assert_eq!(position.symbol_name, "高腾亚洲收益基金");
1702 assert_eq!(position.currency, "USD");
1703 assert_eq!(position.current_net_asset_value, decimal!(0i32));
1704 assert_eq!(position.cost_net_asset_value, decimal!(0i32));
1705 assert_eq!(position.holding_units, decimal!(5i32));
1706 assert_eq!(position.net_asset_value_day, datetime!(2022-4-14 0:00 +8));
1707 }
1708
1709 #[test]
1710 fn stock_position_response() {
1711 let data = r#"
1712 {
1713 "list": [
1714 {
1715 "account_channel": "lb",
1716 "stock_info": [
1717 {
1718 "symbol": "700.HK",
1719 "symbol_name": "腾讯控股",
1720 "currency": "HK",
1721 "quantity": "650",
1722 "available_quantity": "-450",
1723 "cost_price": "457.53",
1724 "market": "HK",
1725 "init_quantity": "2000"
1726 },
1727 {
1728 "symbol": "9991.HK",
1729 "symbol_name": "宝尊电商-SW",
1730 "currency": "HK",
1731 "quantity": "200",
1732 "available_quantity": "0",
1733 "cost_price": "32.25",
1734 "market": "HK",
1735 "init_quantity": ""
1736 }
1737 ]
1738 }
1739 ]
1740 }
1741 "#;
1742
1743 let resp: StockPositionsResponse = serde_json::from_str(data).unwrap();
1744 assert_eq!(resp.channels.len(), 1);
1745
1746 let channel = &resp.channels[0];
1747 assert_eq!(channel.account_channel, "lb");
1748 assert_eq!(channel.positions.len(), 2);
1749
1750 let position = &channel.positions[0];
1751 assert_eq!(position.symbol, "700.HK");
1752 assert_eq!(position.symbol_name, "腾讯控股");
1753 assert_eq!(position.currency, "HK");
1754 assert_eq!(position.quantity, decimal!(650));
1755 assert_eq!(position.available_quantity, decimal!(-450));
1756 assert_eq!(position.cost_price, decimal!(457.53f32));
1757 assert_eq!(position.market, Market::HK);
1758 assert_eq!(position.init_quantity, Some(decimal!(2000)));
1759
1760 let position = &channel.positions[0];
1761 assert_eq!(position.symbol, "700.HK");
1762 assert_eq!(position.symbol_name, "腾讯控股");
1763 assert_eq!(position.currency, "HK");
1764 assert_eq!(position.quantity, decimal!(650));
1765 assert_eq!(position.available_quantity, decimal!(-450));
1766 assert_eq!(position.cost_price, decimal!(457.53f32));
1767 assert_eq!(position.market, Market::HK);
1768
1769 let position = &channel.positions[1];
1770 assert_eq!(position.symbol, "9991.HK");
1771 assert_eq!(position.symbol_name, "宝尊电商-SW");
1772 assert_eq!(position.currency, "HK");
1773 assert_eq!(position.quantity, decimal!(200));
1774 assert_eq!(position.available_quantity, decimal!(0));
1775 assert_eq!(position.cost_price, decimal!(32.25f32));
1776 assert_eq!(position.init_quantity, None);
1777 }
1778
1779 #[test]
1780 fn cash_flow() {
1781 let data = r#"
1782 {
1783 "list": [
1784 {
1785 "transaction_flow_name": "BuyContract-Stocks",
1786 "direction": 1,
1787 "balance": "-248.60",
1788 "currency": "USD",
1789 "business_type": 1,
1790 "business_time": "1621507957",
1791 "symbol": "AAPL.US",
1792 "description": "AAPL"
1793 },
1794 {
1795 "transaction_flow_name": "BuyContract-Stocks",
1796 "direction": 1,
1797 "balance": "-125.16",
1798 "currency": "USD",
1799 "business_type": 2,
1800 "business_time": "1621504824",
1801 "symbol": "AAPL.US",
1802 "description": "AAPL"
1803 }
1804 ]
1805 }
1806 "#;
1807
1808 #[derive(Debug, Deserialize)]
1809 struct Response {
1810 list: Vec<CashFlow>,
1811 }
1812
1813 let resp: Response = serde_json::from_str(data).unwrap();
1814 assert_eq!(resp.list.len(), 2);
1815
1816 let cashflow = &resp.list[0];
1817 assert_eq!(cashflow.transaction_flow_name, "BuyContract-Stocks");
1818 assert_eq!(cashflow.direction, CashFlowDirection::Out);
1819 assert_eq!(cashflow.balance, decimal!(-248.60f32));
1820 assert_eq!(cashflow.currency, "USD");
1821 assert_eq!(cashflow.business_type, BalanceType::Cash);
1822 assert_eq!(cashflow.business_time, datetime!(2021-05-20 18:52:37 +8));
1823 assert_eq!(cashflow.symbol.as_deref(), Some("AAPL.US"));
1824 assert_eq!(cashflow.description, "AAPL");
1825
1826 let cashflow = &resp.list[1];
1827 assert_eq!(cashflow.transaction_flow_name, "BuyContract-Stocks");
1828 assert_eq!(cashflow.direction, CashFlowDirection::Out);
1829 assert_eq!(cashflow.balance, decimal!(-125.16f32));
1830 assert_eq!(cashflow.currency, "USD");
1831 assert_eq!(cashflow.business_type, BalanceType::Stock);
1832 assert_eq!(cashflow.business_time, datetime!(2021-05-20 18:00:24 +8));
1833 assert_eq!(cashflow.symbol.as_deref(), Some("AAPL.US"));
1834 assert_eq!(cashflow.description, "AAPL");
1835 }
1836
1837 #[test]
1838 fn account_balance() {
1839 let data = r#"
1840 {
1841 "list": [
1842 {
1843 "total_cash": "1759070010.72",
1844 "max_finance_amount": "977582000",
1845 "remaining_finance_amount": "0",
1846 "risk_level": "1",
1847 "margin_call": "2598051051.50",
1848 "currency": "HKD",
1849 "cash_infos": [
1850 {
1851 "withdraw_cash": "97592.30",
1852 "available_cash": "195902464.37",
1853 "frozen_cash": "11579339.13",
1854 "settling_cash": "207288537.81",
1855 "currency": "HKD"
1856 },
1857 {
1858 "withdraw_cash": "199893416.74",
1859 "available_cash": "199893416.74",
1860 "frozen_cash": "28723.76",
1861 "settling_cash": "-276806.51",
1862 "currency": "USD"
1863 }
1864 ],
1865 "net_assets": "11111.12",
1866 "init_margin": "2222.23",
1867 "maintenance_margin": "3333.45",
1868 "buy_power": "1234.67",
1869 "frozen_transaction_fees": [
1870 {
1871 "currency": "HKD",
1872 "frozen_transaction_fee": "123"
1873 }
1874 ]
1875 }
1876 ]
1877 }"#;
1878
1879 #[derive(Debug, Deserialize)]
1880 struct Response {
1881 list: Vec<AccountBalance>,
1882 }
1883
1884 let resp: Response = serde_json::from_str(data).unwrap();
1885 assert_eq!(resp.list.len(), 1);
1886
1887 let balance = &resp.list[0];
1888 assert_eq!(balance.total_cash, "1759070010.72".parse().unwrap());
1889 assert_eq!(balance.max_finance_amount, "977582000".parse().unwrap());
1890 assert_eq!(balance.remaining_finance_amount, decimal!(0i32));
1891 assert_eq!(balance.risk_level, 1);
1892 assert_eq!(balance.margin_call, "2598051051.50".parse().unwrap());
1893 assert_eq!(balance.currency, "HKD");
1894 assert_eq!(balance.net_assets, "11111.12".parse().unwrap());
1895 assert_eq!(balance.init_margin, "2222.23".parse().unwrap());
1896 assert_eq!(balance.maintenance_margin, "3333.45".parse().unwrap());
1897 assert_eq!(balance.buy_power, "1234.67".parse().unwrap());
1898
1899 assert_eq!(balance.cash_infos.len(), 2);
1900
1901 let cash_info = &balance.cash_infos[0];
1902 assert_eq!(cash_info.withdraw_cash, "97592.30".parse().unwrap());
1903 assert_eq!(cash_info.available_cash, "195902464.37".parse().unwrap());
1904 assert_eq!(cash_info.frozen_cash, "11579339.13".parse().unwrap());
1905 assert_eq!(cash_info.settling_cash, "207288537.81".parse().unwrap());
1906 assert_eq!(cash_info.currency, "HKD");
1907
1908 let cash_info = &balance.cash_infos[1];
1909 assert_eq!(cash_info.withdraw_cash, "199893416.74".parse().unwrap());
1910 assert_eq!(cash_info.available_cash, "199893416.74".parse().unwrap());
1911 assert_eq!(cash_info.frozen_cash, "28723.76".parse().unwrap());
1912 assert_eq!(cash_info.settling_cash, "-276806.51".parse().unwrap());
1913 assert_eq!(cash_info.currency, "USD");
1914
1915 assert_eq!(balance.frozen_transaction_fees.len(), 1);
1916
1917 let frozen_transaction_fee = &balance.frozen_transaction_fees[0];
1918 assert_eq!(frozen_transaction_fee.currency, "HKD");
1919 assert_eq!(
1920 frozen_transaction_fee.frozen_transaction_fee,
1921 "123".parse().unwrap()
1922 );
1923 }
1924
1925 #[test]
1926 fn history_orders() {
1927 let data = r#"
1928 {
1929 "orders": [
1930 {
1931 "currency": "HKD",
1932 "executed_price": "0.000",
1933 "executed_quantity": "0",
1934 "expire_date": "",
1935 "last_done": "",
1936 "limit_offset": "",
1937 "msg": "",
1938 "order_id": "706388312699592704",
1939 "order_type": "ELO",
1940 "outside_rth": "UnknownOutsideRth",
1941 "price": "11.900",
1942 "quantity": "200",
1943 "side": "Buy",
1944 "status": "RejectedStatus",
1945 "stock_name": "Bank of East Asia Ltd/The",
1946 "submitted_at": "1651644897",
1947 "symbol": "23.HK",
1948 "tag": "Normal",
1949 "time_in_force": "Day",
1950 "trailing_amount": "",
1951 "trailing_percent": "",
1952 "trigger_at": "0",
1953 "trigger_price": "",
1954 "trigger_status": "NOT_USED",
1955 "updated_at": "1651644898",
1956 "limit_depth_level": 0,
1957 "trigger_count": 0,
1958 "monitor_price": "",
1959 "remark": "abc"
1960 }
1961 ]
1962 }
1963 "#;
1964
1965 #[derive(Deserialize)]
1966 struct Response {
1967 orders: Vec<Order>,
1968 }
1969
1970 let resp: Response = serde_json::from_str(data).unwrap();
1971 assert_eq!(resp.orders.len(), 1);
1972
1973 let order = &resp.orders[0];
1974 assert_eq!(order.currency, "HKD");
1975 assert!(order.executed_price.is_none());
1976 assert_eq!(order.executed_quantity, decimal!(0));
1977 assert!(order.expire_date.is_none());
1978 assert!(order.last_done.is_none());
1979 assert!(order.limit_offset.is_none());
1980 assert_eq!(order.msg, "");
1981 assert_eq!(order.order_id, "706388312699592704");
1982 assert_eq!(order.order_type, OrderType::ELO);
1983 assert!(order.outside_rth.is_none());
1984 assert_eq!(order.price, Some("11.900".parse().unwrap()));
1985 assert_eq!(order.quantity, decimal!(200));
1986 assert_eq!(order.side, OrderSide::Buy);
1987 assert_eq!(order.status, OrderStatus::Rejected);
1988 assert_eq!(order.stock_name, "Bank of East Asia Ltd/The");
1989 assert_eq!(order.submitted_at, datetime!(2022-05-04 14:14:57 +8));
1990 assert_eq!(order.symbol, "23.HK");
1991 assert_eq!(order.tag, OrderTag::Normal);
1992 assert_eq!(order.time_in_force, TimeInForceType::Day);
1993 assert!(order.trailing_amount.is_none());
1994 assert!(order.trailing_percent.is_none());
1995 assert!(order.trigger_at.is_none());
1996 assert!(order.trigger_price.is_none());
1997 assert!(order.trigger_status.is_none());
1998 assert_eq!(order.updated_at, Some(datetime!(2022-05-04 14:14:58 +8)));
1999 assert_eq!(order.remark, "abc");
2000 }
2001
2002 #[test]
2003 fn today_orders() {
2004 let data = r#"
2005 {
2006 "orders": [
2007 {
2008 "currency": "HKD",
2009 "executed_price": "0.000",
2010 "executed_quantity": "0",
2011 "expire_date": "",
2012 "last_done": "",
2013 "limit_offset": "",
2014 "msg": "",
2015 "order_id": "706388312699592704",
2016 "order_type": "ELO",
2017 "outside_rth": "UnknownOutsideRth",
2018 "price": "11.900",
2019 "quantity": "200",
2020 "side": "Buy",
2021 "status": "RejectedStatus",
2022 "stock_name": "Bank of East Asia Ltd/The",
2023 "submitted_at": "1651644897",
2024 "symbol": "23.HK",
2025 "tag": "Normal",
2026 "time_in_force": "Day",
2027 "trailing_amount": "",
2028 "trailing_percent": "",
2029 "trigger_at": "0",
2030 "trigger_price": "",
2031 "trigger_status": "NOT_USED",
2032 "updated_at": "1651644898",
2033 "limit_depth_level": 0,
2034 "trigger_count": 0,
2035 "monitor_price": "",
2036 "remark": "abc"
2037 }
2038 ]
2039 }
2040 "#;
2041
2042 #[derive(Deserialize)]
2043 struct Response {
2044 orders: Vec<Order>,
2045 }
2046
2047 let resp: Response = serde_json::from_str(data).unwrap();
2048 assert_eq!(resp.orders.len(), 1);
2049
2050 let order = &resp.orders[0];
2051 assert_eq!(order.currency, "HKD");
2052 assert!(order.executed_price.is_none());
2053 assert_eq!(order.executed_quantity, decimal!(0));
2054 assert!(order.expire_date.is_none());
2055 assert!(order.last_done.is_none());
2056 assert!(order.limit_offset.is_none());
2057 assert_eq!(order.msg, "");
2058 assert_eq!(order.order_id, "706388312699592704");
2059 assert_eq!(order.order_type, OrderType::ELO);
2060 assert!(order.outside_rth.is_none());
2061 assert_eq!(order.price, Some("11.900".parse().unwrap()));
2062 assert_eq!(order.quantity, decimal!(200));
2063 assert_eq!(order.side, OrderSide::Buy);
2064 assert_eq!(order.status, OrderStatus::Rejected);
2065 assert_eq!(order.stock_name, "Bank of East Asia Ltd/The");
2066 assert_eq!(order.submitted_at, datetime!(2022-05-04 14:14:57 +8));
2067 assert_eq!(order.symbol, "23.HK");
2068 assert_eq!(order.tag, OrderTag::Normal);
2069 assert_eq!(order.time_in_force, TimeInForceType::Day);
2070 assert!(order.trailing_amount.is_none());
2071 assert!(order.trailing_percent.is_none());
2072 assert!(order.trigger_at.is_none());
2073 assert!(order.trigger_price.is_none());
2074 assert!(order.trigger_status.is_none());
2075 assert_eq!(order.updated_at, Some(datetime!(2022-05-04 14:14:58 +8)));
2076 assert_eq!(order.remark, "abc");
2077 }
2078
2079 #[test]
2080 fn history_executions() {
2081 let data = r#"
2082 {
2083 "has_more": false,
2084 "trades": [
2085 {
2086 "order_id": "693664675163312128",
2087 "price": "388",
2088 "quantity": "100",
2089 "symbol": "700.HK",
2090 "trade_done_at": "1648611351",
2091 "trade_id": "693664675163312128-1648611351433741210",
2092 "side": "Buy"
2093 }
2094 ]
2095 }
2096 "#;
2097
2098 #[derive(Deserialize)]
2099 struct Response {
2100 trades: Vec<Execution>,
2101 }
2102
2103 let resp: Response = serde_json::from_str(data).unwrap();
2104 assert_eq!(resp.trades.len(), 1);
2105
2106 let execution = &resp.trades[0];
2107 assert_eq!(execution.order_id, "693664675163312128");
2108 assert_eq!(execution.price, "388".parse().unwrap());
2109 assert_eq!(execution.quantity, decimal!(100));
2110 assert_eq!(execution.symbol, "700.HK");
2111 assert_eq!(execution.trade_done_at, datetime!(2022-03-30 11:35:51 +8));
2112 assert_eq!(execution.trade_id, "693664675163312128-1648611351433741210");
2113 assert_eq!(execution.side, OrderSide::Buy);
2114 }
2115
2116 #[test]
2117 fn order_detail() {
2118 let data = r#"
2119 {
2120 "order_id": "828940451093708800",
2121 "status": "FilledStatus",
2122 "stock_name": "Apple",
2123 "quantity": "10",
2124 "executed_quantity": "10",
2125 "price": "200.000",
2126 "executed_price": "164.660",
2127 "submitted_at": "1680863604",
2128 "side": "Buy",
2129 "symbol": "AAPL.US",
2130 "order_type": "LO",
2131 "last_done": "164.660",
2132 "trigger_price": "0.0000",
2133 "msg": "",
2134 "tag": "Normal",
2135 "time_in_force": "Day",
2136 "expire_date": "2023-04-10",
2137 "updated_at": "1681113000",
2138 "trigger_at": "0",
2139 "trailing_amount": "",
2140 "trailing_percent": "",
2141 "limit_offset": "",
2142 "trigger_status": "NOT_USED",
2143 "outside_rth": "ANY_TIME",
2144 "currency": "USD",
2145 "limit_depth_level": 0,
2146 "trigger_count": 0,
2147 "monitor_price": "",
2148 "remark": "1680863603.927165",
2149 "free_status": "None",
2150 "free_amount": "",
2151 "free_currency": "",
2152 "deductions_status": "NONE",
2153 "deductions_amount": "",
2154 "deductions_currency": "",
2155 "platform_deducted_status": "NONE",
2156 "platform_deducted_amount": "",
2157 "platform_deducted_currency": "",
2158 "history": [{
2159 "price": "164.6600",
2160 "quantity": "10",
2161 "status": "FilledStatus",
2162 "msg": "Execution of 10",
2163 "time": "1681113000"
2164 }, {
2165 "price": "200.0000",
2166 "quantity": "10",
2167 "status": "NewStatus",
2168 "msg": "",
2169 "time": "1681113000"
2170 }],
2171 "charge_detail": {
2172 "items": [{
2173 "code": "BROKER_FEES",
2174 "name": "Broker Fees",
2175 "fees": []
2176 }, {
2177 "code": "THIRD_FEES",
2178 "name": "Third-party Fees",
2179 "fees": []
2180 }],
2181 "total_amount": "0",
2182 "currency": "USD"
2183 }
2184 }
2185 "#;
2186
2187 _ = serde_json::from_str::<OrderDetail>(data).unwrap();
2188 }
2189}