nautilus_model/accounts/
any.rs1use std::collections::HashMap;
17
18use enum_dispatch::enum_dispatch;
19use serde::{Deserialize, Serialize};
20
21use crate::{
22 accounts::{Account, CashAccount, MarginAccount},
23 enums::{AccountType, LiquiditySide},
24 events::{AccountState, OrderFilled},
25 identifiers::AccountId,
26 instruments::InstrumentAny,
27 position::Position,
28 types::{AccountBalance, Currency, Money, Price, Quantity},
29};
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
32#[enum_dispatch(Account)]
33pub enum AccountAny {
34 Margin(MarginAccount),
35 Cash(CashAccount),
36}
37
38impl AccountAny {
39 #[must_use]
40 pub fn id(&self) -> AccountId {
41 match self {
42 AccountAny::Margin(margin) => margin.id,
43 AccountAny::Cash(cash) => cash.id,
44 }
45 }
46
47 pub fn last_event(&self) -> Option<AccountState> {
48 match self {
49 AccountAny::Margin(margin) => margin.last_event(),
50 AccountAny::Cash(cash) => cash.last_event(),
51 }
52 }
53
54 pub fn events(&self) -> Vec<AccountState> {
55 match self {
56 AccountAny::Margin(margin) => margin.events(),
57 AccountAny::Cash(cash) => cash.events(),
58 }
59 }
60
61 pub fn apply(&mut self, event: AccountState) {
62 match self {
63 AccountAny::Margin(margin) => margin.apply(event),
64 AccountAny::Cash(cash) => cash.apply(event),
65 }
66 }
67
68 pub fn balances(&self) -> HashMap<Currency, AccountBalance> {
69 match self {
70 AccountAny::Margin(margin) => margin.balances(),
71 AccountAny::Cash(cash) => cash.balances(),
72 }
73 }
74
75 pub fn balances_locked(&self) -> HashMap<Currency, Money> {
76 match self {
77 AccountAny::Margin(margin) => margin.balances_locked(),
78 AccountAny::Cash(cash) => cash.balances_locked(),
79 }
80 }
81
82 pub fn base_currency(&self) -> Option<Currency> {
83 match self {
84 AccountAny::Margin(margin) => margin.base_currency(),
85 AccountAny::Cash(cash) => cash.base_currency(),
86 }
87 }
88
89 pub fn from_events(events: Vec<AccountState>) -> anyhow::Result<Self> {
97 if events.is_empty() {
98 anyhow::bail!("No order events provided to create `AccountAny`");
99 }
100
101 let init_event = events.first().unwrap();
102 let mut account = Self::from(init_event.clone());
103 for event in events.iter().skip(1) {
104 account.apply(event.clone());
105 }
106 Ok(account)
107 }
108
109 pub fn calculate_pnls(
113 &self,
114 instrument: InstrumentAny,
115 fill: OrderFilled,
116 position: Option<Position>,
117 ) -> anyhow::Result<Vec<Money>> {
118 match self {
119 AccountAny::Margin(margin) => margin.calculate_pnls(instrument, fill, position),
120 AccountAny::Cash(cash) => cash.calculate_pnls(instrument, fill, position),
121 }
122 }
123
124 pub fn calculate_commission(
128 &self,
129 instrument: InstrumentAny,
130 last_qty: Quantity,
131 last_px: Price,
132 liquidity_side: LiquiditySide,
133 use_quote_for_inverse: Option<bool>,
134 ) -> anyhow::Result<Money> {
135 match self {
136 AccountAny::Margin(margin) => margin.calculate_commission(
137 instrument,
138 last_qty,
139 last_px,
140 liquidity_side,
141 use_quote_for_inverse,
142 ),
143 AccountAny::Cash(cash) => cash.calculate_commission(
144 instrument,
145 last_qty,
146 last_px,
147 liquidity_side,
148 use_quote_for_inverse,
149 ),
150 }
151 }
152
153 pub fn balance(&self, currency: Option<Currency>) -> Option<&AccountBalance> {
154 match self {
155 AccountAny::Margin(margin) => margin.balance(currency),
156 AccountAny::Cash(cash) => cash.balance(currency),
157 }
158 }
159}
160
161impl From<AccountState> for AccountAny {
162 fn from(event: AccountState) -> Self {
163 match event.account_type {
164 AccountType::Margin => AccountAny::Margin(MarginAccount::new(event, false)),
165 AccountType::Cash => AccountAny::Cash(CashAccount::new(event, false)),
166 AccountType::Betting => todo!("Betting account not implemented"),
167 }
168 }
169}
170
171impl PartialEq for AccountAny {
172 fn eq(&self, other: &Self) -> bool {
173 self.id() == other.id()
174 }
175}