nautilus_model/python/instruments/
synthetic.rs1use std::collections::HashMap;
17
18use nautilus_core::python::{IntoPyObjectNautilusExt, to_pyvalue_err};
19use pyo3::{basic::CompareOp, prelude::*, types::PyDict};
20
21use crate::{
22 identifiers::{InstrumentId, Symbol},
23 instruments::SyntheticInstrument,
24 types::Price,
25};
26
27#[pymethods]
28#[pyo3_stub_gen::derive::gen_stub_pymethods]
29impl SyntheticInstrument {
30 #[new]
35 #[pyo3(signature = (symbol, price_precision, components, formula, ts_event, ts_init))]
36 fn py_new(
37 symbol: Symbol,
38 price_precision: u8,
39 components: Vec<InstrumentId>,
40 formula: &str,
41 ts_event: u64,
42 ts_init: u64,
43 ) -> PyResult<Self> {
44 Self::new_checked(
45 symbol,
46 price_precision,
47 components,
48 formula,
49 ts_event.into(),
50 ts_init.into(),
51 )
52 .map_err(to_pyvalue_err)
53 }
54
55 fn __richcmp__(&self, other: &Self, op: CompareOp, py: Python<'_>) -> Py<PyAny> {
56 match op {
57 CompareOp::Eq => self.eq(other).into_py_any_unwrap(py),
58 CompareOp::Ne => self.ne(other).into_py_any_unwrap(py),
59 _ => py.NotImplemented(),
60 }
61 }
62
63 #[getter]
64 #[pyo3(name = "id")]
65 fn py_id(&self) -> InstrumentId {
66 self.id
67 }
68
69 #[getter]
70 #[pyo3(name = "price_precision")]
71 fn py_price_precision(&self) -> u8 {
72 self.price_precision
73 }
74
75 #[getter]
76 #[pyo3(name = "price_increment")]
77 fn py_price_increment(&self) -> Price {
78 self.price_increment
79 }
80
81 #[getter]
82 #[pyo3(name = "components")]
83 fn py_components(&self) -> Vec<InstrumentId> {
84 self.components.clone()
85 }
86
87 #[getter]
88 #[pyo3(name = "formula")]
89 fn py_formula(&self) -> &str {
90 self.formula.as_str()
91 }
92
93 #[getter]
94 #[pyo3(name = "ts_event")]
95 fn py_ts_event(&self) -> u64 {
96 self.ts_event.as_u64()
97 }
98
99 #[getter]
100 #[pyo3(name = "ts_init")]
101 fn py_ts_init(&self) -> u64 {
102 self.ts_init.as_u64()
103 }
104
105 #[pyo3(name = "is_valid_formula")]
107 fn py_is_valid_formula(&self, formula: &str) -> bool {
108 self.is_valid_formula(formula)
109 }
110
111 #[pyo3(name = "change_formula")]
117 fn py_change_formula(&mut self, formula: &str) -> PyResult<()> {
118 self.change_formula(formula).map_err(to_pyvalue_err)
119 }
120
121 #[pyo3(name = "calculate")]
129 #[expect(clippy::needless_pass_by_value)]
130 fn py_calculate(&mut self, inputs: Vec<f64>) -> PyResult<Price> {
131 self.calculate(&inputs).map_err(to_pyvalue_err)
132 }
133
134 #[pyo3(name = "calculate_from_map")]
136 fn py_calculate_from_map(
137 &mut self,
138 _py: Python<'_>,
139 inputs: &Bound<'_, PyDict>,
140 ) -> PyResult<Price> {
141 let mut map: HashMap<String, f64> = HashMap::new();
142 for (key, value) in inputs.iter() {
143 let k: String = key.extract()?;
144 let v: f64 = value.extract()?;
145 map.insert(k, v);
146 }
147 self.calculate_from_map(&map).map_err(to_pyvalue_err)
148 }
149}