Skip to main content

nautilus_model/python/account/
transformer.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 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
16use nautilus_core::python::{to_pyruntime_err, to_pyvalue_err};
17use pyo3::{prelude::*, types::PyDict};
18
19use crate::{
20    accounts::{Account, BettingAccount, CashAccount, MarginAccount},
21    events::AccountState,
22};
23
24/// Constructs a `CashAccount` from a list of Python dict events.
25///
26/// # Errors
27///
28/// Returns a `PyErr` if the input `events` list is empty.
29///
30/// # Panics
31///
32/// Panics if event conversion (`py_from_dict`) unwrap fails.
33#[pyfunction]
34#[pyo3_stub_gen::derive::gen_stub_pyfunction(module = "nautilus_trader.model")]
35#[pyo3(signature = (events, calculate_account_state, allow_borrowing = false))]
36pub fn cash_account_from_account_events(
37    events: Vec<Bound<'_, PyDict>>,
38    calculate_account_state: bool,
39    allow_borrowing: bool,
40) -> PyResult<CashAccount> {
41    let account_events = events
42        .into_iter()
43        .map(|obj| AccountState::py_from_dict(&obj))
44        .collect::<PyResult<Vec<AccountState>>>()
45        .unwrap();
46
47    if account_events.is_empty() {
48        return Err(to_pyvalue_err("No account events"));
49    }
50    let init_event = account_events[0].clone();
51    let mut cash_account = CashAccount::new(init_event, calculate_account_state, allow_borrowing);
52    for event in account_events.iter().skip(1) {
53        cash_account
54            .apply(event.clone())
55            .map_err(to_pyruntime_err)?;
56    }
57    Ok(cash_account)
58}
59
60/// Constructs a `BettingAccount` from a list of Python dict events.
61///
62/// # Errors
63///
64/// Returns a `PyErr` if the input `events` list is empty.
65#[pyfunction]
66#[pyo3_stub_gen::derive::gen_stub_pyfunction(module = "nautilus_trader.model")]
67pub fn betting_account_from_account_events(
68    events: Vec<Bound<'_, PyDict>>,
69    calculate_account_state: bool,
70) -> PyResult<BettingAccount> {
71    let account_events = events
72        .into_iter()
73        .map(|obj| AccountState::py_from_dict(&obj))
74        .collect::<PyResult<Vec<AccountState>>>()?;
75
76    if account_events.is_empty() {
77        return Err(to_pyvalue_err("No account events"));
78    }
79    let init_event = account_events[0].clone();
80    let mut betting_account = BettingAccount::new(init_event, calculate_account_state);
81    for event in account_events.iter().skip(1) {
82        betting_account
83            .apply(event.clone())
84            .map_err(to_pyruntime_err)?;
85    }
86    Ok(betting_account)
87}
88
89/// Constructs a `MarginAccount` from a list of Python dict events.
90///
91/// # Errors
92///
93/// Returns a `PyErr` if the input `events` list is empty.
94///
95/// # Panics
96///
97/// Panics if event conversion (`py_from_dict`) unwrap fails.
98#[pyfunction]
99#[pyo3_stub_gen::derive::gen_stub_pyfunction(module = "nautilus_trader.model")]
100pub fn margin_account_from_account_events(
101    events: Vec<Bound<'_, PyDict>>,
102    calculate_account_state: bool,
103) -> PyResult<MarginAccount> {
104    let account_events = events
105        .into_iter()
106        .map(|obj| AccountState::py_from_dict(&obj))
107        .collect::<PyResult<Vec<AccountState>>>()
108        .unwrap();
109
110    if account_events.is_empty() {
111        return Err(to_pyvalue_err("No account events"));
112    }
113    let init_event = account_events[0].clone();
114    let mut margin_account = MarginAccount::new(init_event, calculate_account_state);
115    for event in account_events.iter().skip(1) {
116        margin_account
117            .apply(event.clone())
118            .map_err(to_pyruntime_err)?;
119    }
120    Ok(margin_account)
121}