1use nautilus_execution::{
19 models::{fee::FeeModelAny, fill::FillModelAny, latency::LatencyModelAny},
20 python::{
21 fee::{fee_model_any_to_pyobject, pyobject_to_fee_model_any},
22 fill::{fill_model_any_to_pyobject, pyobject_to_fill_model_any},
23 latency::{latency_model_any_to_pyobject, pyobject_to_latency_model_any},
24 },
25};
26use nautilus_model::{
27 enums::{AccountType, BookType, OmsType},
28 identifiers::{AccountId, Venue},
29 types::{Currency, Money},
30};
31use pyo3::{Py, PyAny, Python, prelude::*};
32use rust_decimal::Decimal;
33
34use crate::config::SandboxExecutionClientConfig;
35
36#[pymethods]
37#[pyo3_stub_gen::derive::gen_stub_pymethods]
38impl SandboxExecutionClientConfig {
39 #[new]
41 #[pyo3(signature = (venue, starting_balances, 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, fill_model=None, queue_position=false, liquidity_consumption=false, bar_adaptive_high_low_ordering=false, use_market_order_acks=false, oto_full_trigger=false, price_protection_points=None, latency_model=None))]
42 #[expect(clippy::too_many_arguments)]
43 fn py_new(
44 venue: Venue,
45 starting_balances: Vec<Money>,
46 account_id: Option<AccountId>,
47 base_currency: Option<Currency>,
48 oms_type: Option<OmsType>,
49 account_type: Option<AccountType>,
50 default_leverage: Option<Decimal>,
51 book_type: Option<BookType>,
52 frozen_account: bool,
53 bar_execution: bool,
54 trade_execution: bool,
55 reject_stop_orders: bool,
56 support_gtd_orders: bool,
57 support_contingent_orders: bool,
58 use_position_ids: bool,
59 use_random_ids: bool,
60 use_reduce_only: bool,
61 fee_model: Option<Py<PyAny>>,
62 fill_model: Option<Py<PyAny>>,
63 queue_position: bool,
64 liquidity_consumption: bool,
65 bar_adaptive_high_low_ordering: bool,
66 use_market_order_acks: bool,
67 oto_full_trigger: bool,
68 price_protection_points: Option<u32>,
69 latency_model: Option<Py<PyAny>>,
70 ) -> PyResult<Self> {
71 let account_id =
73 account_id.unwrap_or_else(|| AccountId::from(format!("{venue}-SANDBOX-001").as_str()));
74 let fee_model: Option<FeeModelAny> = fee_model
75 .map(|obj| Python::attach(|py| pyobject_to_fee_model_any(obj.bind(py))))
76 .transpose()?;
77 let fill_model: Option<FillModelAny> = fill_model
78 .map(|obj| Python::attach(|py| pyobject_to_fill_model_any(obj.bind(py))))
79 .transpose()?;
80 let latency_model: Option<LatencyModelAny> = latency_model
81 .map(|obj| Python::attach(|py| pyobject_to_latency_model_any(obj.bind(py))))
82 .transpose()?;
83
84 Ok(Self {
85 account_id,
86 venue,
87 starting_balances,
88 base_currency,
89 oms_type: oms_type.unwrap_or(OmsType::Netting),
90 account_type: account_type.unwrap_or(AccountType::Margin),
91 default_leverage: default_leverage.unwrap_or(Decimal::ONE),
92 leverages: ahash::AHashMap::new(),
93 book_type: book_type.unwrap_or(BookType::L1_MBP),
94 fee_model,
95 fill_model,
96 latency_model,
97 frozen_account,
98 bar_execution,
99 trade_execution,
100 reject_stop_orders,
101 support_gtd_orders,
102 support_contingent_orders,
103 use_position_ids,
104 use_random_ids,
105 use_reduce_only,
106 queue_position,
107 liquidity_consumption,
108 bar_adaptive_high_low_ordering,
109 use_market_order_acks,
110 oto_full_trigger,
111 price_protection_points: price_protection_points.unwrap_or(0),
112 })
113 }
114
115 #[getter]
116 fn account_id(&self) -> AccountId {
117 self.account_id
118 }
119
120 #[getter]
121 fn venue(&self) -> Venue {
122 self.venue
123 }
124
125 #[getter]
126 fn starting_balances(&self) -> Vec<Money> {
127 self.starting_balances.clone()
128 }
129
130 #[getter]
131 fn base_currency(&self) -> Option<Currency> {
132 self.base_currency
133 }
134
135 #[getter]
136 fn oms_type(&self) -> OmsType {
137 self.oms_type
138 }
139
140 #[getter]
141 fn account_type(&self) -> AccountType {
142 self.account_type
143 }
144
145 #[getter]
146 fn default_leverage(&self) -> Decimal {
147 self.default_leverage
148 }
149
150 #[getter]
151 fn book_type(&self) -> BookType {
152 self.book_type
153 }
154
155 #[getter]
156 fn fee_model(&self, py: Python<'_>) -> PyResult<Option<Py<PyAny>>> {
157 self.fee_model
158 .as_ref()
159 .map(|model| fee_model_any_to_pyobject(py, model))
160 .transpose()
161 }
162
163 #[getter]
164 fn fill_model(&self, py: Python<'_>) -> PyResult<Option<Py<PyAny>>> {
165 self.fill_model
166 .as_ref()
167 .map(|model| fill_model_any_to_pyobject(py, model))
168 .transpose()
169 }
170
171 #[getter]
172 fn latency_model(&self, py: Python<'_>) -> PyResult<Option<Py<PyAny>>> {
173 self.latency_model
174 .as_ref()
175 .map(|model| latency_model_any_to_pyobject(py, model))
176 .transpose()
177 }
178
179 #[getter]
180 fn frozen_account(&self) -> bool {
181 self.frozen_account
182 }
183
184 #[getter]
185 fn bar_execution(&self) -> bool {
186 self.bar_execution
187 }
188
189 #[getter]
190 fn trade_execution(&self) -> bool {
191 self.trade_execution
192 }
193
194 #[getter]
195 fn reject_stop_orders(&self) -> bool {
196 self.reject_stop_orders
197 }
198
199 #[getter]
200 fn support_gtd_orders(&self) -> bool {
201 self.support_gtd_orders
202 }
203
204 #[getter]
205 fn support_contingent_orders(&self) -> bool {
206 self.support_contingent_orders
207 }
208
209 #[getter]
210 fn use_position_ids(&self) -> bool {
211 self.use_position_ids
212 }
213
214 #[getter]
215 fn use_random_ids(&self) -> bool {
216 self.use_random_ids
217 }
218
219 #[getter]
220 fn use_reduce_only(&self) -> bool {
221 self.use_reduce_only
222 }
223
224 #[getter]
225 fn queue_position(&self) -> bool {
226 self.queue_position
227 }
228
229 #[getter]
230 fn liquidity_consumption(&self) -> bool {
231 self.liquidity_consumption
232 }
233
234 #[getter]
235 fn bar_adaptive_high_low_ordering(&self) -> bool {
236 self.bar_adaptive_high_low_ordering
237 }
238
239 #[getter]
240 fn use_market_order_acks(&self) -> bool {
241 self.use_market_order_acks
242 }
243
244 #[getter]
245 fn oto_full_trigger(&self) -> bool {
246 self.oto_full_trigger
247 }
248
249 #[getter]
250 fn price_protection_points(&self) -> u32 {
251 self.price_protection_points
252 }
253}