nautilus_model/python/data/
close.rs
1use std::{
17 collections::{HashMap, hash_map::DefaultHasher},
18 hash::{Hash, Hasher},
19};
20
21use nautilus_core::{
22 python::{
23 IntoPyObjectNautilusExt,
24 serialization::{from_dict_pyo3, to_dict_pyo3},
25 to_pyvalue_err,
26 },
27 serialization::Serializable,
28};
29use pyo3::{basic::CompareOp, exceptions::PyValueError, prelude::*, types::PyDict};
30
31use super::ERROR_MONOTONICITY;
32use crate::{
33 data::close::InstrumentClose, enums::InstrumentCloseType, identifiers::InstrumentId,
34 python::common::PY_MODULE_MODEL, types::Price,
35};
36
37#[pymethods]
41impl InstrumentClose {
42 #[new]
43 #[pyo3(signature = (instrument_id, close_price, close_type, ts_event, ts_init))]
44 fn py_new(
45 instrument_id: InstrumentId,
46 close_price: Price,
47 close_type: InstrumentCloseType,
48 ts_event: u64,
49 ts_init: u64,
50 ) -> Self {
51 Self {
52 instrument_id,
53 close_price,
54 close_type,
55 ts_event: ts_event.into(),
56 ts_init: ts_init.into(),
57 }
58 }
59
60 fn __richcmp__(&self, other: &Self, op: CompareOp, py: Python<'_>) -> Py<PyAny> {
61 match op {
62 CompareOp::Eq => self.eq(other).into_py_any_unwrap(py),
63 CompareOp::Ne => self.ne(other).into_py_any_unwrap(py),
64 _ => py.NotImplemented(),
65 }
66 }
67
68 fn __hash__(&self) -> isize {
69 let mut h = DefaultHasher::new();
70 self.hash(&mut h);
71 h.finish() as isize
72 }
73
74 fn __repr__(&self) -> String {
75 format!("{}({})", stringify!(InstrumentStatus), self)
76 }
77
78 fn __str__(&self) -> String {
79 self.to_string()
80 }
81
82 #[getter]
83 #[pyo3(name = "instrument_id")]
84 fn py_instrument_id(&self) -> InstrumentId {
85 self.instrument_id
86 }
87
88 #[getter]
89 #[pyo3(name = "close_price")]
90 pub fn py_close_price(&self) -> Price {
91 self.close_price
92 }
93
94 #[getter]
95 #[pyo3(name = "close_type")]
96 pub fn py_close_type(&self) -> InstrumentCloseType {
97 self.close_type
98 }
99
100 #[getter]
101 #[pyo3(name = "ts_event")]
102 pub fn py_ts_event(&self) -> u64 {
103 self.ts_event.as_u64()
104 }
105
106 #[getter]
107 #[pyo3(name = "ts_init")]
108 pub fn py_ts_init(&self) -> u64 {
109 self.ts_init.as_u64()
110 }
111
112 #[staticmethod]
113 #[pyo3(name = "fully_qualified_name")]
114 fn py_fully_qualified_name() -> String {
115 format!("{}:{}", PY_MODULE_MODEL, stringify!(InstrumentClose))
116 }
117
118 #[staticmethod]
119 #[pyo3(name = "get_metadata")]
120 fn py_get_metadata(
121 instrument_id: &InstrumentId,
122 price_precision: u8,
123 ) -> PyResult<HashMap<String, String>> {
124 Ok(Self::get_metadata(instrument_id, price_precision))
125 }
126
127 #[staticmethod]
128 #[pyo3(name = "get_fields")]
129 fn py_get_fields(py: Python<'_>) -> PyResult<Bound<'_, PyDict>> {
130 let py_dict = PyDict::new(py);
131 for (k, v) in Self::get_fields() {
132 py_dict.set_item(k, v)?;
133 }
134
135 Ok(py_dict)
136 }
137
138 #[staticmethod]
140 #[pyo3(name = "from_dict")]
141 fn py_from_dict(py: Python<'_>, values: Py<PyDict>) -> PyResult<Self> {
142 from_dict_pyo3(py, values)
143 }
144
145 #[staticmethod]
146 #[pyo3(name = "from_json")]
147 fn py_from_json(data: Vec<u8>) -> PyResult<Self> {
148 Self::from_json_bytes(&data).map_err(to_pyvalue_err)
149 }
150
151 #[staticmethod]
152 #[pyo3(name = "from_msgpack")]
153 fn py_from_msgpack(data: Vec<u8>) -> PyResult<Self> {
154 Self::from_msgpack_bytes(&data).map_err(to_pyvalue_err)
155 }
156
157 #[pyo3(name = "as_dict")]
159 fn py_as_dict(&self, py: Python<'_>) -> PyResult<Py<PyDict>> {
160 to_dict_pyo3(py, self)
161 }
162
163 #[pyo3(name = "as_json")]
165 fn py_as_json(&self, py: Python<'_>) -> Py<PyAny> {
166 self.as_json_bytes().unwrap().into_py_any_unwrap(py)
168 }
169
170 #[pyo3(name = "as_msgpack")]
172 fn py_as_msgpack(&self, py: Python<'_>) -> Py<PyAny> {
173 self.as_msgpack_bytes().unwrap().into_py_any_unwrap(py)
175 }
176}
177
178impl InstrumentClose {
179 pub fn from_pyobject(obj: &Bound<'_, PyAny>) -> PyResult<Self> {
181 let instrument_id = obj.getattr("instrument_id")?.extract::<InstrumentId>()?;
182 let close_price = obj.getattr("close_price")?.extract::<Price>()?;
183 let close_type = obj
184 .getattr("close_type")?
185 .extract::<InstrumentCloseType>()?;
186 let ts_event = obj.getattr("ts_event")?.extract::<u64>()?;
187 let ts_init = obj.getattr("ts_init")?.extract::<u64>()?;
188
189 Ok(Self {
190 instrument_id,
191 close_price,
192 close_type,
193 ts_event: ts_event.into(),
194 ts_init: ts_init.into(),
195 })
196 }
197}
198
199pub fn pyobjects_to_instrument_closes(
201 data: Vec<Bound<'_, PyAny>>,
202) -> PyResult<Vec<InstrumentClose>> {
203 let closes = data
204 .into_iter()
205 .map(|obj| InstrumentClose::from_pyobject(&obj))
206 .collect::<PyResult<Vec<InstrumentClose>>>()?;
207
208 if !crate::data::is_monotonically_increasing_by_init(&closes) {
210 return Err(PyValueError::new_err(ERROR_MONOTONICITY));
211 }
212
213 Ok(closes)
214}