1use nautilus_common::{actor::DataActorConfig, python::config_error_to_pyvalue_err};
19use nautilus_model::{
20 data::BarType,
21 enums::TimeInForce,
22 identifiers::{ActorId, ClientId, InstrumentId, StrategyId},
23 types::Quantity,
24};
25use nautilus_trading::strategy::StrategyConfig;
26use pyo3::prelude::*;
27use rust_decimal::Decimal;
28
29use crate::{DataTesterConfig, ExecTesterConfig};
30
31#[pymethods]
32#[pyo3_stub_gen::derive::gen_stub_pymethods]
33impl DataTesterConfig {
34 #[new]
36 #[allow(
37 clippy::needless_pass_by_value,
38 reason = "PyO3 #[new] requires owned params"
39 )]
40 #[expect(clippy::too_many_arguments)]
41 #[pyo3(signature = (
42 actor_id = None,
43 client_id = None,
44 instrument_ids = None,
45 bar_types = None,
46 subscribe_book_deltas = None,
47 subscribe_book_depth = None,
48 subscribe_book_at_interval = None,
49 subscribe_quotes = None,
50 subscribe_trades = None,
51 subscribe_mark_prices = None,
52 subscribe_index_prices = None,
53 subscribe_funding_rates = None,
54 subscribe_bars = None,
55 subscribe_instrument = None,
56 subscribe_instrument_status = None,
57 subscribe_instrument_close = None,
58 subscribe_option_greeks = None,
59 can_unsubscribe = None,
60 request_instruments = None,
61 request_quotes = None,
62 request_trades = None,
63 request_bars = None,
64 request_book_snapshot = None,
65 request_book_deltas = None,
66 request_funding_rates = None,
67 book_depth = None,
68 book_interval_ms = None,
69 book_levels_to_print = None,
70 manage_book = None,
71 log_data = None,
72 stats_interval_secs = None,
73 log_events = None,
74 log_commands = None,
75 ))]
76 fn py_new(
77 actor_id: Option<ActorId>,
78 client_id: Option<ClientId>,
79 instrument_ids: Option<Vec<InstrumentId>>,
80 bar_types: Option<Vec<BarType>>,
81 subscribe_book_deltas: Option<bool>,
82 subscribe_book_depth: Option<bool>,
83 subscribe_book_at_interval: Option<bool>,
84 subscribe_quotes: Option<bool>,
85 subscribe_trades: Option<bool>,
86 subscribe_mark_prices: Option<bool>,
87 subscribe_index_prices: Option<bool>,
88 subscribe_funding_rates: Option<bool>,
89 subscribe_bars: Option<bool>,
90 subscribe_instrument: Option<bool>,
91 subscribe_instrument_status: Option<bool>,
92 subscribe_instrument_close: Option<bool>,
93 subscribe_option_greeks: Option<bool>,
94 can_unsubscribe: Option<bool>,
95 request_instruments: Option<bool>,
96 request_quotes: Option<bool>,
97 request_trades: Option<bool>,
98 request_bars: Option<bool>,
99 request_book_snapshot: Option<bool>,
100 request_book_deltas: Option<bool>,
101 request_funding_rates: Option<bool>,
102 book_depth: Option<usize>,
103 book_interval_ms: Option<usize>,
104 book_levels_to_print: Option<usize>,
105 manage_book: Option<bool>,
106 log_data: Option<bool>,
107 stats_interval_secs: Option<u64>,
108 log_events: Option<bool>,
109 log_commands: Option<bool>,
110 ) -> PyResult<Self> {
111 let defaults = Self::default();
112 let config = Self {
113 base: DataActorConfig {
114 actor_id,
115 log_events: log_events.unwrap_or(defaults.base.log_events),
116 log_commands: log_commands.unwrap_or(defaults.base.log_commands),
117 },
118 instrument_ids: instrument_ids.unwrap_or(defaults.instrument_ids),
119 client_id,
120 bar_types,
121 subscribe_book_deltas: subscribe_book_deltas.unwrap_or(defaults.subscribe_book_deltas),
122 subscribe_book_depth: subscribe_book_depth.unwrap_or(defaults.subscribe_book_depth),
123 subscribe_book_at_interval: subscribe_book_at_interval
124 .unwrap_or(defaults.subscribe_book_at_interval),
125 subscribe_quotes: subscribe_quotes.unwrap_or(defaults.subscribe_quotes),
126 subscribe_trades: subscribe_trades.unwrap_or(defaults.subscribe_trades),
127 subscribe_mark_prices: subscribe_mark_prices.unwrap_or(defaults.subscribe_mark_prices),
128 subscribe_index_prices: subscribe_index_prices
129 .unwrap_or(defaults.subscribe_index_prices),
130 subscribe_funding_rates: subscribe_funding_rates
131 .unwrap_or(defaults.subscribe_funding_rates),
132 subscribe_bars: subscribe_bars.unwrap_or(defaults.subscribe_bars),
133 subscribe_instrument: subscribe_instrument.unwrap_or(defaults.subscribe_instrument),
134 subscribe_instrument_status: subscribe_instrument_status
135 .unwrap_or(defaults.subscribe_instrument_status),
136 subscribe_instrument_close: subscribe_instrument_close
137 .unwrap_or(defaults.subscribe_instrument_close),
138 subscribe_option_greeks: subscribe_option_greeks
139 .unwrap_or(defaults.subscribe_option_greeks),
140 subscribe_params: defaults.subscribe_params,
141 request_params: defaults.request_params,
142 can_unsubscribe: can_unsubscribe.unwrap_or(defaults.can_unsubscribe),
143 request_instruments: request_instruments.unwrap_or(defaults.request_instruments),
144 request_quotes: request_quotes.unwrap_or(defaults.request_quotes),
145 request_trades: request_trades.unwrap_or(defaults.request_trades),
146 request_bars: request_bars.unwrap_or(defaults.request_bars),
147 request_book_snapshot: request_book_snapshot.unwrap_or(defaults.request_book_snapshot),
148 request_book_deltas: request_book_deltas.unwrap_or(defaults.request_book_deltas),
149 request_funding_rates: request_funding_rates.unwrap_or(defaults.request_funding_rates),
150 book_type: defaults.book_type,
151 book_depth,
152 book_interval_ms: book_interval_ms.unwrap_or(defaults.book_interval_ms),
153 book_levels_to_print: book_levels_to_print.unwrap_or(defaults.book_levels_to_print),
154 manage_book: manage_book.unwrap_or(defaults.manage_book),
155 log_data: log_data.unwrap_or(defaults.log_data),
156 stats_interval_secs: stats_interval_secs.unwrap_or(defaults.stats_interval_secs),
157 };
158 config.validate().map_err(config_error_to_pyvalue_err)?;
159 Ok(config)
160 }
161
162 fn __repr__(&self) -> String {
163 format!("{self:?}")
164 }
165}
166
167#[pymethods]
168#[pyo3_stub_gen::derive::gen_stub_pymethods]
169impl ExecTesterConfig {
170 #[new]
172 #[allow(
173 clippy::needless_pass_by_value,
174 reason = "PyO3 #[new] requires owned params"
175 )]
176 #[expect(clippy::too_many_arguments)]
177 #[pyo3(signature = (
178 strategy_id = None,
179 order_id_tag = None,
180 use_hyphens_in_client_order_ids = None,
181 external_order_claims = None,
182 instrument_id = None,
183 client_id = None,
184 order_qty = None,
185 subscribe_book = None,
186 subscribe_quotes = None,
187 subscribe_trades = None,
188 open_position_on_start_qty = None,
189 open_position_on_first_quote = None,
190 open_position_time_in_force = None,
191 enable_limit_buys = None,
192 enable_limit_sells = None,
193 enable_stop_buys = None,
194 enable_stop_sells = None,
195 tob_offset_ticks = None,
196 limit_time_in_force = None,
197 use_post_only = None,
198 limit_aggressive = None,
199 cancel_orders_on_stop = None,
200 close_positions_on_stop = None,
201 close_positions_time_in_force = None,
202 reduce_only_on_stop = None,
203 dry_run = None,
204 log_data = None,
205 can_unsubscribe = None,
206 clamp_to_instrument_price_range = None,
207 log_events = None,
208 log_commands = None,
209 ))]
210 fn py_new(
211 strategy_id: Option<StrategyId>,
212 order_id_tag: Option<String>,
213 use_hyphens_in_client_order_ids: Option<bool>,
214 external_order_claims: Option<Vec<InstrumentId>>,
215 instrument_id: Option<InstrumentId>,
216 client_id: Option<ClientId>,
217 order_qty: Option<Quantity>,
218 subscribe_book: Option<bool>,
219 subscribe_quotes: Option<bool>,
220 subscribe_trades: Option<bool>,
221 open_position_on_start_qty: Option<Decimal>,
222 open_position_on_first_quote: Option<bool>,
223 open_position_time_in_force: Option<TimeInForce>,
224 enable_limit_buys: Option<bool>,
225 enable_limit_sells: Option<bool>,
226 enable_stop_buys: Option<bool>,
227 enable_stop_sells: Option<bool>,
228 tob_offset_ticks: Option<u64>,
229 limit_time_in_force: Option<TimeInForce>,
230 use_post_only: Option<bool>,
231 limit_aggressive: Option<bool>,
232 cancel_orders_on_stop: Option<bool>,
233 close_positions_on_stop: Option<bool>,
234 close_positions_time_in_force: Option<TimeInForce>,
235 reduce_only_on_stop: Option<bool>,
236 dry_run: Option<bool>,
237 log_data: Option<bool>,
238 can_unsubscribe: Option<bool>,
239 clamp_to_instrument_price_range: Option<bool>,
240 log_events: Option<bool>,
241 log_commands: Option<bool>,
242 ) -> Self {
243 let defaults = Self::default();
244 Self {
245 base: StrategyConfig {
246 strategy_id,
247 order_id_tag,
248 use_hyphens_in_client_order_ids: use_hyphens_in_client_order_ids
249 .unwrap_or(defaults.base.use_hyphens_in_client_order_ids),
250 external_order_claims,
251 log_events: log_events.unwrap_or(defaults.base.log_events),
252 log_commands: log_commands.unwrap_or(defaults.base.log_commands),
253 ..Default::default()
254 },
255 instrument_id: instrument_id.unwrap_or(defaults.instrument_id),
256 order_qty: order_qty.unwrap_or(defaults.order_qty),
257 order_display_qty: defaults.order_display_qty,
258 order_expire_time_delta_mins: defaults.order_expire_time_delta_mins,
259 order_params: defaults.order_params,
260 client_id,
261 subscribe_book: subscribe_book.unwrap_or(defaults.subscribe_book),
262 subscribe_quotes: subscribe_quotes.unwrap_or(defaults.subscribe_quotes),
263 subscribe_trades: subscribe_trades.unwrap_or(defaults.subscribe_trades),
264 book_type: defaults.book_type,
265 book_depth: defaults.book_depth,
266 book_interval_ms: defaults.book_interval_ms,
267 book_levels_to_print: defaults.book_levels_to_print,
268 open_position_on_start_qty,
269 open_position_on_first_quote: open_position_on_first_quote
270 .unwrap_or(defaults.open_position_on_first_quote),
271 open_position_time_in_force: open_position_time_in_force
272 .unwrap_or(defaults.open_position_time_in_force),
273 enable_limit_buys: enable_limit_buys.unwrap_or(defaults.enable_limit_buys),
274 enable_limit_sells: enable_limit_sells.unwrap_or(defaults.enable_limit_sells),
275 enable_stop_buys: enable_stop_buys.unwrap_or(defaults.enable_stop_buys),
276 enable_stop_sells: enable_stop_sells.unwrap_or(defaults.enable_stop_sells),
277 tob_offset_ticks: tob_offset_ticks.unwrap_or(defaults.tob_offset_ticks),
278 limit_time_in_force,
279 stop_order_type: defaults.stop_order_type,
280 stop_offset_ticks: defaults.stop_offset_ticks,
281 stop_limit_offset_ticks: defaults.stop_limit_offset_ticks,
282 stop_trigger_type: defaults.stop_trigger_type,
283 stop_time_in_force: defaults.stop_time_in_force,
284 trailing_offset: defaults.trailing_offset,
285 trailing_offset_type: defaults.trailing_offset_type,
286 enable_brackets: defaults.enable_brackets,
287 batch_submit_limit_pair: defaults.batch_submit_limit_pair,
288 bracket_entry_order_type: defaults.bracket_entry_order_type,
289 bracket_offset_ticks: defaults.bracket_offset_ticks,
290 modify_orders_to_maintain_tob_offset: defaults.modify_orders_to_maintain_tob_offset,
291 modify_stop_orders_to_maintain_offset: defaults.modify_stop_orders_to_maintain_offset,
292 cancel_replace_orders_to_maintain_tob_offset: defaults
293 .cancel_replace_orders_to_maintain_tob_offset,
294 cancel_replace_stop_orders_to_maintain_offset: defaults
295 .cancel_replace_stop_orders_to_maintain_offset,
296 use_post_only: use_post_only.unwrap_or(defaults.use_post_only),
297 limit_aggressive: limit_aggressive.unwrap_or(defaults.limit_aggressive),
298 use_quote_quantity: defaults.use_quote_quantity,
299 emulation_trigger: defaults.emulation_trigger,
300 cancel_orders_on_stop: cancel_orders_on_stop.unwrap_or(defaults.cancel_orders_on_stop),
301 close_positions_on_stop: close_positions_on_stop
302 .unwrap_or(defaults.close_positions_on_stop),
303 close_positions_time_in_force,
304 reduce_only_on_stop: reduce_only_on_stop.unwrap_or(defaults.reduce_only_on_stop),
305 use_individual_cancels_on_stop: defaults.use_individual_cancels_on_stop,
306 use_batch_cancel_on_stop: defaults.use_batch_cancel_on_stop,
307 dry_run: dry_run.unwrap_or(defaults.dry_run),
308 log_data: log_data.unwrap_or(defaults.log_data),
309 test_reject_post_only: defaults.test_reject_post_only,
310 test_reject_reduce_only: defaults.test_reject_reduce_only,
311 test_modify_rejected: defaults.test_modify_rejected,
312 can_unsubscribe: can_unsubscribe.unwrap_or(defaults.can_unsubscribe),
313 clamp_to_instrument_price_range: clamp_to_instrument_price_range
314 .unwrap_or(defaults.clamp_to_instrument_price_range),
315 }
316 }
317
318 fn __repr__(&self) -> String {
319 format!("{self:?}")
320 }
321}