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