Skip to main content

nautilus_sandbox/python/
config.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
16//! Python bindings for sandbox configuration.
17
18use nautilus_execution::{
19    models::fee::FeeModelAny,
20    python::fee::{fee_model_any_to_pyobject, pyobject_to_fee_model_any},
21};
22use nautilus_model::{
23    enums::{AccountType, BookType, OmsType},
24    identifiers::{AccountId, TraderId, Venue},
25    types::{Currency, Money},
26};
27use pyo3::{Py, PyAny, Python, prelude::*};
28use rust_decimal::Decimal;
29
30use crate::config::SandboxExecutionClientConfig;
31
32#[pymethods]
33#[pyo3_stub_gen::derive::gen_stub_pymethods]
34impl SandboxExecutionClientConfig {
35    /// Configuration for `SandboxExecutionClient` instances.
36    #[new]
37    #[pyo3(signature = (venue, starting_balances, trader_id=None, account_id=None, base_currency=None, oms_type=None, account_type=None, default_leverage=None, book_type=None, frozen_account=false, bar_execution=true, trade_execution=true, reject_stop_orders=true, support_gtd_orders=true, support_contingent_orders=true, use_position_ids=true, use_random_ids=false, use_reduce_only=true, fee_model=None))]
38    #[expect(clippy::too_many_arguments)]
39    fn py_new(
40        venue: Venue,
41        starting_balances: Vec<Money>,
42        trader_id: Option<TraderId>,
43        account_id: Option<AccountId>,
44        base_currency: Option<Currency>,
45        oms_type: Option<OmsType>,
46        account_type: Option<AccountType>,
47        default_leverage: Option<Decimal>,
48        book_type: Option<BookType>,
49        frozen_account: bool,
50        bar_execution: bool,
51        trade_execution: bool,
52        reject_stop_orders: bool,
53        support_gtd_orders: bool,
54        support_contingent_orders: bool,
55        use_position_ids: bool,
56        use_random_ids: bool,
57        use_reduce_only: bool,
58        fee_model: Option<Py<PyAny>>,
59    ) -> PyResult<Self> {
60        // Generate default IDs from venue if not provided
61        let trader_id =
62            trader_id.unwrap_or_else(|| TraderId::from(format!("{venue}-001").as_str()));
63        let account_id =
64            account_id.unwrap_or_else(|| AccountId::from(format!("{venue}-SANDBOX-001").as_str()));
65        let fee_model: Option<FeeModelAny> = fee_model
66            .map(|obj| Python::attach(|py| pyobject_to_fee_model_any(obj.bind(py))))
67            .transpose()?;
68
69        Ok(Self {
70            trader_id,
71            account_id,
72            venue,
73            starting_balances,
74            base_currency,
75            oms_type: oms_type.unwrap_or(OmsType::Netting),
76            account_type: account_type.unwrap_or(AccountType::Margin),
77            default_leverage: default_leverage.unwrap_or(Decimal::ONE),
78            leverages: ahash::AHashMap::new(),
79            book_type: book_type.unwrap_or(BookType::L1_MBP),
80            fee_model,
81            frozen_account,
82            bar_execution,
83            trade_execution,
84            reject_stop_orders,
85            support_gtd_orders,
86            support_contingent_orders,
87            use_position_ids,
88            use_random_ids,
89            use_reduce_only,
90        })
91    }
92
93    #[getter]
94    fn trader_id(&self) -> TraderId {
95        self.trader_id
96    }
97
98    #[getter]
99    fn account_id(&self) -> AccountId {
100        self.account_id
101    }
102
103    #[getter]
104    fn venue(&self) -> Venue {
105        self.venue
106    }
107
108    #[getter]
109    fn starting_balances(&self) -> Vec<Money> {
110        self.starting_balances.clone()
111    }
112
113    #[getter]
114    fn base_currency(&self) -> Option<Currency> {
115        self.base_currency
116    }
117
118    #[getter]
119    fn oms_type(&self) -> OmsType {
120        self.oms_type
121    }
122
123    #[getter]
124    fn account_type(&self) -> AccountType {
125        self.account_type
126    }
127
128    #[getter]
129    fn default_leverage(&self) -> Decimal {
130        self.default_leverage
131    }
132
133    #[getter]
134    fn book_type(&self) -> BookType {
135        self.book_type
136    }
137
138    #[getter]
139    fn fee_model(&self, py: Python<'_>) -> PyResult<Option<Py<PyAny>>> {
140        self.fee_model
141            .as_ref()
142            .map(|model| fee_model_any_to_pyobject(py, model))
143            .transpose()
144    }
145
146    #[getter]
147    fn frozen_account(&self) -> bool {
148        self.frozen_account
149    }
150
151    #[getter]
152    fn bar_execution(&self) -> bool {
153        self.bar_execution
154    }
155
156    #[getter]
157    fn trade_execution(&self) -> bool {
158        self.trade_execution
159    }
160
161    #[getter]
162    fn reject_stop_orders(&self) -> bool {
163        self.reject_stop_orders
164    }
165
166    #[getter]
167    fn support_gtd_orders(&self) -> bool {
168        self.support_gtd_orders
169    }
170
171    #[getter]
172    fn support_contingent_orders(&self) -> bool {
173        self.support_contingent_orders
174    }
175
176    #[getter]
177    fn use_position_ids(&self) -> bool {
178        self.use_position_ids
179    }
180
181    #[getter]
182    fn use_random_ids(&self) -> bool {
183        self.use_random_ids
184    }
185
186    #[getter]
187    fn use_reduce_only(&self) -> bool {
188        self.use_reduce_only
189    }
190}