nautilus_model/accounts/
any.rs
1use 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> {
90 if events.is_empty() {
91 anyhow::bail!("No order events provided to create `AccountAny`");
92 }
93
94 let init_event = events.first().unwrap();
95 let mut account = Self::from(init_event.clone());
96 for event in events.iter().skip(1) {
97 account.apply(event.clone());
98 }
99 Ok(account)
100 }
101
102 pub fn calculate_pnls(
103 &self,
104 instrument: InstrumentAny,
105 fill: OrderFilled,
106 position: Option<Position>,
107 ) -> anyhow::Result<Vec<Money>> {
108 match self {
109 AccountAny::Margin(margin) => margin.calculate_pnls(instrument, fill, position),
110 AccountAny::Cash(cash) => cash.calculate_pnls(instrument, fill, position),
111 }
112 }
113
114 pub fn calculate_commission(
115 &self,
116 instrument: InstrumentAny,
117 last_qty: Quantity,
118 last_px: Price,
119 liquidity_side: LiquiditySide,
120 use_quote_for_inverse: Option<bool>,
121 ) -> anyhow::Result<Money> {
122 match self {
123 AccountAny::Margin(margin) => margin.calculate_commission(
124 instrument,
125 last_qty,
126 last_px,
127 liquidity_side,
128 use_quote_for_inverse,
129 ),
130 AccountAny::Cash(cash) => cash.calculate_commission(
131 instrument,
132 last_qty,
133 last_px,
134 liquidity_side,
135 use_quote_for_inverse,
136 ),
137 }
138 }
139
140 pub fn balance(&self, currency: Option<Currency>) -> Option<&AccountBalance> {
141 match self {
142 AccountAny::Margin(margin) => margin.balance(currency),
143 AccountAny::Cash(cash) => cash.balance(currency),
144 }
145 }
146}
147
148impl From<AccountState> for AccountAny {
149 fn from(event: AccountState) -> Self {
150 match event.account_type {
151 AccountType::Margin => AccountAny::Margin(MarginAccount::new(event, false)),
152 AccountType::Cash => AccountAny::Cash(CashAccount::new(event, false)),
153 AccountType::Betting => todo!("Betting account not implemented"),
154 }
155 }
156}
157
158impl PartialEq for AccountAny {
159 fn eq(&self, other: &Self) -> bool {
160 self.id() == other.id()
161 }
162}