1use chrono::{DateTime, Utc};
2use rust_decimal::Decimal;
3use serde::{de, Deserialize, Serialize};
4use std::{cmp::Ordering, fmt};
5
6#[derive(Debug, Deserialize, Clone)]
7pub struct Account {
8 pub id: AccountId,
9 pub auto_balance_period: u32,
10 pub auto_balance_portfolio_id: Option<u32>,
11 pub auto_balance_currency_change_limit: Option<u32>,
12 pub autobalance_enabled: bool,
13 pub hedge_mode_available: bool,
14 pub hedge_mode_enabled: bool,
15 pub is_locked: bool,
16 pub smart_trading_supported: bool,
17 pub stats_supported: bool,
19 pub trading_supported: bool,
20 pub market_buy_supported: bool,
21 pub market_sell_supported: bool,
22 pub conditional_buy_supported: bool,
23 pub bots_allowed: bool,
24 pub bots_ttp_allowed: bool,
25 pub bots_tsl_allowed: bool,
26 pub gordon_bots_available: bool,
27 pub multi_bots_allowed: bool,
28 pub created_at: Option<DateTime<Utc>>,
29 pub updated_at: Option<DateTime<Utc>>,
30 pub last_auto_balance: Option<DateTime<Utc>>,
31 pub fast_convert_available: bool,
33 pub grid_bots_allowed: bool,
34 pub api_key_invalid: bool,
35 pub deposit_enabled: bool,
36 pub supported_market_types: Vec<String>,
37 pub api_key: Option<String>,
38 pub name: String,
39 pub auto_balance_method: Option<AutoBalanceMethod>,
40 pub auto_balance_error: Option<String>,
41 pub customer_id: Option<String>,
42 pub subaccount_name: Option<String>,
43 pub lock_reason: Option<String>,
44 pub btc_amount: Decimal,
45 pub usd_amount: Decimal,
46 pub day_profit_btc: Decimal,
47 pub day_profit_usd: Decimal,
48 pub day_profit_btc_percentage: Decimal,
49 pub day_profit_usd_percentage: Decimal,
50 pub btc_profit: Decimal,
52 pub usd_profit: Decimal,
54 pub usd_profit_percentage: Decimal,
56 pub btc_profit_percentage: Decimal,
58 pub total_btc_profit: Decimal,
59 pub total_usd_profit: Decimal,
60 pub pretty_display_type: String,
61 pub exchange_name: String,
62 pub market_code: String,
63 pub address: Option<String>,
64}
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
67pub enum AccountId {
68 Summary,
69
70 AccountId(u32),
71}
72
73#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
74pub enum AutoBalanceMethod {
75 #[serde(rename = "time")]
76 Time,
77
78 #[serde(rename = "currency_change")]
79 CurrencyChange,
80}
81
82#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
83pub enum MarketType {
84 #[serde(rename = "spot")]
85 Spot,
86
87 #[serde(rename = "futures")]
88 Futures,
89}
90
91impl PartialOrd for AccountId {
92 #[inline]
93 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
94 Some(self.cmp(other))
95 }
96}
97
98impl Ord for AccountId {
99 fn cmp(&self, other: &Self) -> Ordering {
100 match (self, other) {
101 (AccountId::Summary, AccountId::Summary) => Ordering::Equal,
102 (AccountId::Summary, _) => Ordering::Less,
103 (_, AccountId::Summary) => Ordering::Greater,
104 (AccountId::AccountId(l), AccountId::AccountId(r)) => Ord::cmp(l, r),
105 }
106 }
107}
108
109impl fmt::Display for AccountId {
110 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111 match self {
112 Self::Summary => f.write_str("summary"),
113 Self::AccountId(id) => fmt::Display::fmt(id, f),
114 }
115 }
116}
117
118impl Serialize for AccountId {
119 #[inline]
120 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
121 where
122 S: serde::Serializer,
123 {
124 match self {
125 Self::Summary => serializer.serialize_str("summary"),
126 Self::AccountId(id) => id.serialize(serializer),
127 }
128 }
129}
130
131struct AccountIdVisitor;
132impl<'de> de::Visitor<'de> for AccountIdVisitor {
133 type Value = AccountId;
134
135 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
136 formatter.write_str("account id string or number")
137 }
138
139 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
140 where
141 E: de::Error,
142 {
143 match v {
144 "summary" => Ok(AccountId::Summary),
145 _ => Err(E::invalid_value(de::Unexpected::Str(v), &self)),
146 }
147 }
148
149 fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
150 where
151 E: de::Error,
152 {
153 match u32::try_from(v) {
154 Ok(v) => self.visit_u32(v),
155 Err(_) => Err(E::invalid_value(de::Unexpected::Unsigned(v), &self)),
156 }
157 }
158
159 fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
160 where
161 E: de::Error,
162 {
163 Ok(AccountId::AccountId(v))
164 }
165
166 fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
167 where
168 E: de::Error,
169 {
170 match u32::try_from(v) {
171 Ok(v) => self.visit_u32(v),
172 Err(_) => Err(E::invalid_value(de::Unexpected::Signed(v as i64), &self)),
173 }
174 }
175
176 fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
177 where
178 E: de::Error,
179 {
180 match u32::try_from(v) {
181 Ok(v) => self.visit_u32(v),
182 Err(_) => Err(E::invalid_value(de::Unexpected::Signed(v), &self)),
183 }
184 }
185}
186
187impl<'de> Deserialize<'de> for AccountId {
188 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
189 where
190 D: serde::Deserializer<'de>,
191 {
192 deserializer.deserialize_any(AccountIdVisitor)
193 }
194}
195
196#[cfg(test)]
197mod tests {
198 use super::*;
199
200 #[test]
201 fn account_id_ord() {
202 assert!(AccountId::Summary < AccountId::AccountId(0));
203 assert!(AccountId::AccountId(0) > AccountId::Summary);
204 assert!(AccountId::AccountId(1) > AccountId::AccountId(0));
205 }
206}