1use nautilus_model::{
19 data::BarType,
20 enums::TimeInForce,
21 identifiers::{ActorId, ClientId, InstrumentId, StrategyId},
22 types::Quantity,
23};
24use pyo3::prelude::*;
25
26use crate::examples::{
27 actors::BookImbalanceActorConfig,
28 strategies::{
29 CompositeMarketMakerConfig, DeltaNeutralVolConfig, EmaCrossConfig, GridMarketMakerConfig,
30 HurstVpinDirectionalConfig,
31 },
32};
33
34#[pymethods]
35#[pyo3_stub_gen::derive::gen_stub_pymethods]
36impl CompositeMarketMakerConfig {
37 #[new]
39 #[pyo3(signature = (
40 instrument_id,
41 signal_instrument_id,
42 max_position,
43 strategy_id=None,
44 order_id_tag=None,
45 trade_size=None,
46 half_spread_bps=5,
47 inventory_skew_factor=0.0,
48 signal_skew_factor=0.0,
49 signal_baseline=None,
50 requote_threshold_bps=5,
51 expire_time_secs=None,
52 on_cancel_resubmit=false,
53 ))]
54 #[expect(clippy::too_many_arguments)]
55 fn py_new(
56 instrument_id: InstrumentId,
57 signal_instrument_id: InstrumentId,
58 max_position: Quantity,
59 strategy_id: Option<StrategyId>,
60 order_id_tag: Option<String>,
61 trade_size: Option<Quantity>,
62 half_spread_bps: u32,
63 inventory_skew_factor: f64,
64 signal_skew_factor: f64,
65 signal_baseline: Option<f64>,
66 requote_threshold_bps: u32,
67 expire_time_secs: Option<u64>,
68 on_cancel_resubmit: bool,
69 ) -> Self {
70 let mut config = Self::builder()
71 .instrument_id(instrument_id)
72 .signal_instrument_id(signal_instrument_id)
73 .max_position(max_position)
74 .half_spread_bps(half_spread_bps)
75 .inventory_skew_factor(inventory_skew_factor)
76 .signal_skew_factor(signal_skew_factor)
77 .requote_threshold_bps(requote_threshold_bps)
78 .on_cancel_resubmit(on_cancel_resubmit)
79 .maybe_trade_size(trade_size)
80 .maybe_signal_baseline(signal_baseline)
81 .maybe_expire_time_secs(expire_time_secs)
82 .build();
83
84 if let Some(id) = strategy_id {
85 config.base.strategy_id = Some(id);
86 }
87
88 if let Some(tag) = order_id_tag {
89 config.base.order_id_tag = Some(tag);
90 }
91
92 config
93 }
94
95 #[getter]
96 fn instrument_id(&self) -> InstrumentId {
97 self.instrument_id
98 }
99
100 #[getter]
101 fn signal_instrument_id(&self) -> InstrumentId {
102 self.signal_instrument_id
103 }
104
105 #[getter]
106 fn max_position(&self) -> Quantity {
107 self.max_position
108 }
109
110 #[getter]
111 fn trade_size(&self) -> Option<Quantity> {
112 self.trade_size
113 }
114
115 #[getter]
116 fn half_spread_bps(&self) -> u32 {
117 self.half_spread_bps
118 }
119
120 #[getter]
121 fn inventory_skew_factor(&self) -> f64 {
122 self.inventory_skew_factor
123 }
124
125 #[getter]
126 fn signal_skew_factor(&self) -> f64 {
127 self.signal_skew_factor
128 }
129
130 #[getter]
131 fn signal_baseline(&self) -> Option<f64> {
132 self.signal_baseline
133 }
134
135 #[getter]
136 fn requote_threshold_bps(&self) -> u32 {
137 self.requote_threshold_bps
138 }
139
140 #[getter]
141 fn expire_time_secs(&self) -> Option<u64> {
142 self.expire_time_secs
143 }
144
145 #[getter]
146 fn on_cancel_resubmit(&self) -> bool {
147 self.on_cancel_resubmit
148 }
149}
150
151#[pymethods]
152#[pyo3_stub_gen::derive::gen_stub_pymethods]
153impl GridMarketMakerConfig {
154 #[new]
156 #[pyo3(signature = (
157 instrument_id,
158 max_position,
159 strategy_id=None,
160 order_id_tag=None,
161 trade_size=None,
162 num_levels=3,
163 grid_step_bps=10,
164 skew_factor=0.0,
165 requote_threshold_bps=5,
166 expire_time_secs=None,
167 on_cancel_resubmit=false,
168 ))]
169 #[expect(clippy::too_many_arguments)]
170 fn py_new(
171 instrument_id: InstrumentId,
172 max_position: Quantity,
173 strategy_id: Option<StrategyId>,
174 order_id_tag: Option<String>,
175 trade_size: Option<Quantity>,
176 num_levels: usize,
177 grid_step_bps: u32,
178 skew_factor: f64,
179 requote_threshold_bps: u32,
180 expire_time_secs: Option<u64>,
181 on_cancel_resubmit: bool,
182 ) -> Self {
183 let mut config = Self::builder()
184 .instrument_id(instrument_id)
185 .max_position(max_position)
186 .num_levels(num_levels)
187 .grid_step_bps(grid_step_bps)
188 .skew_factor(skew_factor)
189 .requote_threshold_bps(requote_threshold_bps)
190 .on_cancel_resubmit(on_cancel_resubmit)
191 .maybe_trade_size(trade_size)
192 .maybe_expire_time_secs(expire_time_secs)
193 .build();
194
195 if let Some(id) = strategy_id {
196 config.base.strategy_id = Some(id);
197 }
198
199 if let Some(tag) = order_id_tag {
200 config.base.order_id_tag = Some(tag);
201 }
202
203 config
204 }
205
206 #[getter]
207 fn instrument_id(&self) -> InstrumentId {
208 self.instrument_id
209 }
210
211 #[getter]
212 fn max_position(&self) -> Quantity {
213 self.max_position
214 }
215
216 #[getter]
217 fn trade_size(&self) -> Option<Quantity> {
218 self.trade_size
219 }
220
221 #[getter]
222 fn num_levels(&self) -> usize {
223 self.num_levels
224 }
225
226 #[getter]
227 fn grid_step_bps(&self) -> u32 {
228 self.grid_step_bps
229 }
230
231 #[getter]
232 fn skew_factor(&self) -> f64 {
233 self.skew_factor
234 }
235
236 #[getter]
237 fn requote_threshold_bps(&self) -> u32 {
238 self.requote_threshold_bps
239 }
240
241 #[getter]
242 fn expire_time_secs(&self) -> Option<u64> {
243 self.expire_time_secs
244 }
245
246 #[getter]
247 fn on_cancel_resubmit(&self) -> bool {
248 self.on_cancel_resubmit
249 }
250}
251
252#[pymethods]
253#[pyo3_stub_gen::derive::gen_stub_pymethods]
254impl EmaCrossConfig {
255 #[new]
257 #[pyo3(signature = (
258 instrument_id,
259 trade_size,
260 fast_period=10,
261 slow_period=50,
262 strategy_id=None,
263 order_id_tag=None,
264 ))]
265 fn py_new(
266 instrument_id: InstrumentId,
267 trade_size: Quantity,
268 fast_period: usize,
269 slow_period: usize,
270 strategy_id: Option<StrategyId>,
271 order_id_tag: Option<String>,
272 ) -> Self {
273 let mut config = Self::builder()
274 .instrument_id(instrument_id)
275 .trade_size(trade_size)
276 .fast_period(fast_period)
277 .slow_period(slow_period)
278 .build();
279
280 if let Some(id) = strategy_id {
281 config.base.strategy_id = Some(id);
282 }
283
284 if let Some(tag) = order_id_tag {
285 config.base.order_id_tag = Some(tag);
286 }
287
288 config
289 }
290
291 #[getter]
292 fn instrument_id(&self) -> InstrumentId {
293 self.instrument_id
294 }
295
296 #[getter]
297 fn trade_size(&self) -> Quantity {
298 self.trade_size
299 }
300
301 #[getter]
302 fn fast_period(&self) -> usize {
303 self.fast_period
304 }
305
306 #[getter]
307 fn slow_period(&self) -> usize {
308 self.slow_period
309 }
310}
311
312#[pymethods]
313#[pyo3_stub_gen::derive::gen_stub_pymethods]
314impl DeltaNeutralVolConfig {
315 #[new]
321 #[pyo3(signature = (
322 option_family,
323 hedge_instrument_id,
324 client_id,
325 strategy_id=None,
326 order_id_tag=None,
327 target_call_delta=0.20,
328 target_put_delta=-0.20,
329 contracts=1,
330 rehedge_delta_threshold=0.5,
331 rehedge_interval_secs=30,
332 expiry_filter=None,
333 enter_strangle=true,
334 entry_iv_offset=0.0,
335 entry_time_in_force=TimeInForce::Gtc,
336 entry_premium_offset_ticks=None,
337 iv_param_key="px_vol",
338 ))]
339 #[expect(clippy::too_many_arguments)]
340 fn py_new(
341 option_family: String,
342 hedge_instrument_id: InstrumentId,
343 client_id: ClientId,
344 strategy_id: Option<StrategyId>,
345 order_id_tag: Option<String>,
346 target_call_delta: f64,
347 target_put_delta: f64,
348 contracts: u64,
349 rehedge_delta_threshold: f64,
350 rehedge_interval_secs: u64,
351 expiry_filter: Option<String>,
352 enter_strangle: bool,
353 entry_iv_offset: f64,
354 entry_time_in_force: TimeInForce,
355 entry_premium_offset_ticks: Option<i32>,
356 iv_param_key: &str,
357 ) -> Self {
358 let mut config = Self::builder()
359 .option_family(option_family)
360 .hedge_instrument_id(hedge_instrument_id)
361 .client_id(client_id)
362 .target_call_delta(target_call_delta)
363 .target_put_delta(target_put_delta)
364 .contracts(contracts)
365 .rehedge_delta_threshold(rehedge_delta_threshold)
366 .rehedge_interval_secs(rehedge_interval_secs)
367 .enter_strangle(enter_strangle)
368 .entry_iv_offset(entry_iv_offset)
369 .entry_time_in_force(entry_time_in_force)
370 .iv_param_key(iv_param_key.to_string())
371 .maybe_expiry_filter(expiry_filter)
372 .maybe_entry_premium_offset_ticks(entry_premium_offset_ticks)
373 .build();
374
375 if let Some(id) = strategy_id {
376 config.base.strategy_id = Some(id);
377 }
378
379 if let Some(tag) = order_id_tag {
380 config.base.order_id_tag = Some(tag);
381 }
382
383 config
384 }
385
386 #[getter]
387 fn option_family(&self) -> &str {
388 &self.option_family
389 }
390
391 #[getter]
392 fn hedge_instrument_id(&self) -> InstrumentId {
393 self.hedge_instrument_id
394 }
395
396 #[getter]
397 fn client_id(&self) -> ClientId {
398 self.client_id
399 }
400
401 #[getter]
402 fn target_call_delta(&self) -> f64 {
403 self.target_call_delta
404 }
405
406 #[getter]
407 fn target_put_delta(&self) -> f64 {
408 self.target_put_delta
409 }
410
411 #[getter]
412 fn contracts(&self) -> u64 {
413 self.contracts
414 }
415
416 #[getter]
417 fn rehedge_delta_threshold(&self) -> f64 {
418 self.rehedge_delta_threshold
419 }
420
421 #[getter]
422 fn rehedge_interval_secs(&self) -> u64 {
423 self.rehedge_interval_secs
424 }
425
426 #[getter]
427 fn expiry_filter(&self) -> Option<&str> {
428 self.expiry_filter.as_deref()
429 }
430
431 #[getter]
432 fn enter_strangle(&self) -> bool {
433 self.enter_strangle
434 }
435
436 #[getter]
437 fn entry_iv_offset(&self) -> f64 {
438 self.entry_iv_offset
439 }
440
441 #[getter]
442 fn entry_time_in_force(&self) -> TimeInForce {
443 self.entry_time_in_force
444 }
445
446 #[getter]
447 fn entry_premium_offset_ticks(&self) -> Option<i32> {
448 self.entry_premium_offset_ticks
449 }
450}
451
452#[pymethods]
453#[pyo3_stub_gen::derive::gen_stub_pymethods]
454impl HurstVpinDirectionalConfig {
455 #[new]
461 #[pyo3(signature = (
462 instrument_id,
463 bar_type,
464 trade_size,
465 strategy_id=None,
466 order_id_tag=None,
467 hurst_window=128,
468 hurst_lags=None,
469 hurst_enter=0.55,
470 hurst_exit=0.50,
471 vpin_window=50,
472 vpin_threshold=0.30,
473 max_holding_secs=3600,
474 ))]
475 #[expect(clippy::too_many_arguments)]
476 fn py_new(
477 instrument_id: InstrumentId,
478 bar_type: BarType,
479 trade_size: Quantity,
480 strategy_id: Option<StrategyId>,
481 order_id_tag: Option<String>,
482 hurst_window: usize,
483 hurst_lags: Option<Vec<usize>>,
484 hurst_enter: f64,
485 hurst_exit: f64,
486 vpin_window: usize,
487 vpin_threshold: f64,
488 max_holding_secs: u64,
489 ) -> Self {
490 let mut config = Self::builder()
491 .instrument_id(instrument_id)
492 .bar_type(bar_type)
493 .trade_size(trade_size)
494 .hurst_window(hurst_window)
495 .maybe_hurst_lags(hurst_lags)
496 .hurst_enter(hurst_enter)
497 .hurst_exit(hurst_exit)
498 .vpin_window(vpin_window)
499 .vpin_threshold(vpin_threshold)
500 .max_holding_secs(max_holding_secs)
501 .build();
502
503 if let Some(id) = strategy_id {
504 config.base.strategy_id = Some(id);
505 }
506
507 if let Some(tag) = order_id_tag {
508 config.base.order_id_tag = Some(tag);
509 }
510
511 config
512 }
513
514 #[getter]
515 fn instrument_id(&self) -> InstrumentId {
516 self.instrument_id
517 }
518
519 #[getter]
520 fn bar_type(&self) -> BarType {
521 self.bar_type
522 }
523
524 #[getter]
525 fn trade_size(&self) -> Quantity {
526 self.trade_size
527 }
528
529 #[getter]
530 fn hurst_window(&self) -> usize {
531 self.hurst_window
532 }
533
534 #[getter]
535 fn hurst_lags(&self) -> Vec<usize> {
536 self.hurst_lags.clone()
537 }
538
539 #[getter]
540 fn hurst_enter(&self) -> f64 {
541 self.hurst_enter
542 }
543
544 #[getter]
545 fn hurst_exit(&self) -> f64 {
546 self.hurst_exit
547 }
548
549 #[getter]
550 fn vpin_window(&self) -> usize {
551 self.vpin_window
552 }
553
554 #[getter]
555 fn vpin_threshold(&self) -> f64 {
556 self.vpin_threshold
557 }
558
559 #[getter]
560 fn max_holding_secs(&self) -> u64 {
561 self.max_holding_secs
562 }
563}
564
565#[pymethods]
566#[pyo3_stub_gen::derive::gen_stub_pymethods]
567impl BookImbalanceActorConfig {
568 #[new]
570 #[pyo3(signature = (instrument_ids, log_interval=100, actor_id=None))]
571 fn py_new(
572 instrument_ids: Vec<InstrumentId>,
573 log_interval: u64,
574 actor_id: Option<ActorId>,
575 ) -> Self {
576 Self::builder()
577 .instrument_ids(instrument_ids)
578 .log_interval(log_interval)
579 .maybe_actor_id(actor_id)
580 .build()
581 }
582
583 #[getter]
584 fn instrument_ids(&self) -> Vec<InstrumentId> {
585 self.instrument_ids.clone()
586 }
587
588 #[getter]
589 fn log_interval(&self) -> u64 {
590 self.log_interval
591 }
592
593 #[getter]
594 fn actor_id(&self) -> Option<ActorId> {
595 self.actor_id
596 }
597}