nautilus_model/accounts/
stubs.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Lightweight stub implementations useful in unit tests where a full account object is
17//! unnecessary.
18
19use rstest::fixture;
20
21use crate::{
22    accounts::{Account, AccountAny, CashAccount, MarginAccount},
23    enums::{AccountType, LiquiditySide},
24    events::account::{state::AccountState, stubs::*},
25    identifiers::stubs::{account_id, uuid4},
26    instruments::InstrumentAny,
27    types::{AccountBalance, Currency, Money, Price, Quantity},
28};
29
30impl Default for CashAccount {
31    /// Creates a new default [`CashAccount`] instance.
32    fn default() -> Self {
33        // million dollar account
34        let init_event = AccountState::new(
35            account_id(),
36            AccountType::Cash,
37            vec![AccountBalance::new(
38                Money::from("1000000 USD"),
39                Money::from("0 USD"),
40                Money::from("1000000 USD"),
41            )],
42            vec![],
43            true,
44            uuid4(),
45            0.into(),
46            0.into(),
47            Some(Currency::USD()),
48        );
49        Self::new(init_event, false)
50    }
51}
52
53impl Default for AccountAny {
54    /// Creates a new default [`AccountAny`] instance.
55    fn default() -> Self {
56        AccountAny::Cash(CashAccount::default())
57    }
58}
59
60#[fixture]
61pub fn margin_account(margin_account_state: AccountState) -> MarginAccount {
62    MarginAccount::new(margin_account_state, true)
63}
64
65#[fixture]
66pub fn cash_account(cash_account_state: AccountState) -> CashAccount {
67    CashAccount::new(cash_account_state, true)
68}
69
70#[fixture]
71pub fn cash_account_million_usd(cash_account_state_million_usd: AccountState) -> CashAccount {
72    CashAccount::new(cash_account_state_million_usd, true)
73}
74
75#[fixture]
76pub fn cash_account_multi(cash_account_state_multi: AccountState) -> CashAccount {
77    CashAccount::new(cash_account_state_multi, true)
78}
79
80/// Helper to calculate commission in test fixtures.
81///
82/// # Panics
83///
84/// Panics if the underlying `calculate_commission` returns an error.
85#[must_use]
86pub fn calculate_commission(
87    instrument: InstrumentAny,
88    quantity: Quantity,
89    price: Price,
90    currency: Option<Currency>,
91) -> Money {
92    let account_state = if Some(Currency::USDT()) == currency {
93        cash_account_state_million_usdt()
94    } else {
95        cash_account_state_million_usd("1000000 USD", "0 USD", "1000000 USD")
96    };
97    let account = cash_account_million_usd(account_state);
98    account
99        .calculate_commission(instrument, quantity, price, LiquiditySide::Taker, None)
100        .unwrap()
101}