nautilus_testkit/testers/exec/
config.rs1use std::num::NonZeroUsize;
17
18use nautilus_core::Params;
19use nautilus_model::{
20 enums::{BookType, OrderType, TimeInForce, TrailingOffsetType, TriggerType},
21 identifiers::{ClientId, InstrumentId, StrategyId},
22 types::Quantity,
23};
24use nautilus_trading::strategy::StrategyConfig;
25use rust_decimal::Decimal;
26use serde::{Deserialize, Serialize};
27
28#[derive(Debug, Clone, Deserialize, Serialize, bon::Builder)]
30#[serde(default, deny_unknown_fields)]
31#[cfg_attr(
32 feature = "python",
33 pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.testkit", from_py_object)
34)]
35#[cfg_attr(
36 feature = "python",
37 pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.testkit")
38)]
39pub struct ExecTesterConfig {
40 #[builder(default)]
42 pub base: StrategyConfig,
43 #[builder(default = InstrumentId::from("BTCUSDT-PERP.BINANCE"))]
45 pub instrument_id: InstrumentId,
46 #[builder(default = Quantity::from("0.001"))]
48 pub order_qty: Quantity,
49 pub order_display_qty: Option<Quantity>,
51 pub order_expire_time_delta_mins: Option<u64>,
53 pub order_params: Option<Params>,
55 pub client_id: Option<ClientId>,
57 #[builder(default = false)]
59 pub subscribe_book: bool,
60 #[builder(default = true)]
62 pub subscribe_quotes: bool,
63 #[builder(default = true)]
65 pub subscribe_trades: bool,
66 #[builder(default = BookType::L2_MBP)]
68 pub book_type: BookType,
69 pub book_depth: Option<NonZeroUsize>,
71 #[builder(default = NonZeroUsize::new(1000).unwrap())]
73 pub book_interval_ms: NonZeroUsize,
74 #[builder(default = 10)]
76 pub book_levels_to_print: usize,
77 pub open_position_on_start_qty: Option<Decimal>,
79 #[builder(default = false)]
81 pub open_position_on_first_quote: bool,
82 #[builder(default = TimeInForce::Gtc)]
84 pub open_position_time_in_force: TimeInForce,
85 #[builder(default = true)]
87 pub enable_limit_buys: bool,
88 #[builder(default = true)]
90 pub enable_limit_sells: bool,
91 #[builder(default = false)]
93 pub enable_stop_buys: bool,
94 #[builder(default = false)]
96 pub enable_stop_sells: bool,
97 #[builder(default = 500)]
99 pub tob_offset_ticks: u64,
100 pub limit_time_in_force: Option<TimeInForce>,
102 #[builder(default = OrderType::StopMarket)]
104 pub stop_order_type: OrderType,
105 #[builder(default = 100)]
107 pub stop_offset_ticks: u64,
108 pub stop_limit_offset_ticks: Option<u64>,
110 #[builder(default = TriggerType::Default)]
112 pub stop_trigger_type: TriggerType,
113 pub stop_time_in_force: Option<TimeInForce>,
115 pub trailing_offset: Option<Decimal>,
117 #[builder(default = TrailingOffsetType::BasisPoints)]
119 pub trailing_offset_type: TrailingOffsetType,
120 #[builder(default = false)]
122 pub enable_brackets: bool,
123 #[builder(default = false)]
125 pub batch_submit_limit_pair: bool,
126 #[builder(default = OrderType::Limit)]
128 pub bracket_entry_order_type: OrderType,
129 #[builder(default = 500)]
131 pub bracket_offset_ticks: u64,
132 #[builder(default = false)]
134 pub modify_orders_to_maintain_tob_offset: bool,
135 #[builder(default = false)]
137 pub modify_stop_orders_to_maintain_offset: bool,
138 #[builder(default = false)]
140 pub cancel_replace_orders_to_maintain_tob_offset: bool,
141 #[builder(default = false)]
143 pub cancel_replace_stop_orders_to_maintain_offset: bool,
144 #[builder(default = false)]
146 pub use_post_only: bool,
147 #[builder(default = false)]
152 pub limit_aggressive: bool,
153 #[builder(default = false)]
155 pub use_quote_quantity: bool,
156 pub emulation_trigger: Option<TriggerType>,
158 #[builder(default = true)]
160 pub cancel_orders_on_stop: bool,
161 #[builder(default = true)]
163 pub close_positions_on_stop: bool,
164 pub close_positions_time_in_force: Option<TimeInForce>,
166 #[builder(default = true)]
168 pub reduce_only_on_stop: bool,
169 #[builder(default = false)]
171 pub use_individual_cancels_on_stop: bool,
172 #[builder(default = false)]
174 pub use_batch_cancel_on_stop: bool,
175 #[builder(default = false)]
177 pub dry_run: bool,
178 #[builder(default = true)]
180 pub log_data: bool,
181 #[builder(default = false)]
183 pub test_reject_post_only: bool,
184 #[builder(default = false)]
186 pub test_reject_reduce_only: bool,
187 #[builder(default = false)]
194 pub test_modify_rejected: bool,
195 #[builder(default = true)]
197 pub can_unsubscribe: bool,
198 #[builder(default = false)]
200 pub clamp_to_instrument_price_range: bool,
201}
202
203impl ExecTesterConfig {
204 #[must_use]
210 pub fn new(
211 strategy_id: StrategyId,
212 instrument_id: InstrumentId,
213 client_id: ClientId,
214 order_qty: Quantity,
215 ) -> Self {
216 Self {
217 base: StrategyConfig {
218 strategy_id: Some(strategy_id),
219 order_id_tag: None,
220 ..Default::default()
221 },
222 instrument_id,
223 order_qty,
224 order_display_qty: None,
225 order_expire_time_delta_mins: None,
226 order_params: None,
227 client_id: Some(client_id),
228 subscribe_quotes: true,
229 subscribe_trades: true,
230 subscribe_book: false,
231 book_type: BookType::L2_MBP,
232 book_depth: None,
233 book_interval_ms: NonZeroUsize::new(1000).unwrap(),
234 book_levels_to_print: 10,
235 open_position_on_start_qty: None,
236 open_position_on_first_quote: false,
237 open_position_time_in_force: TimeInForce::Gtc,
238 enable_limit_buys: true,
239 enable_limit_sells: true,
240 enable_stop_buys: false,
241 enable_stop_sells: false,
242 tob_offset_ticks: 500,
243 limit_time_in_force: None,
244 stop_order_type: OrderType::StopMarket,
245 stop_offset_ticks: 100,
246 stop_limit_offset_ticks: None,
247 stop_trigger_type: TriggerType::Default,
248 stop_time_in_force: None,
249 trailing_offset: None,
250 trailing_offset_type: TrailingOffsetType::BasisPoints,
251 enable_brackets: false,
252 batch_submit_limit_pair: false,
253 bracket_entry_order_type: OrderType::Limit,
254 bracket_offset_ticks: 500,
255 modify_orders_to_maintain_tob_offset: false,
256 modify_stop_orders_to_maintain_offset: false,
257 cancel_replace_orders_to_maintain_tob_offset: false,
258 cancel_replace_stop_orders_to_maintain_offset: false,
259 use_post_only: false,
260 limit_aggressive: false,
261 use_quote_quantity: false,
262 emulation_trigger: None,
263 cancel_orders_on_stop: true,
264 close_positions_on_stop: true,
265 close_positions_time_in_force: None,
266 reduce_only_on_stop: true,
267 use_individual_cancels_on_stop: false,
268 use_batch_cancel_on_stop: false,
269 dry_run: false,
270 log_data: true,
271 test_reject_post_only: false,
272 test_reject_reduce_only: false,
273 test_modify_rejected: false,
274 can_unsubscribe: true,
275 clamp_to_instrument_price_range: false,
276 }
277 }
278}
279
280impl Default for ExecTesterConfig {
281 fn default() -> Self {
282 Self::builder().build()
283 }
284}