nautilus_model/python/data/
close.rs1use 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::{
28 Serializable,
29 msgpack::{FromMsgPack, ToMsgPack},
30 },
31};
32use pyo3::{IntoPyObjectExt, basic::CompareOp, prelude::*, types::PyDict};
33
34use super::ERROR_MONOTONICITY;
35use crate::{
36 data::close::InstrumentClose, enums::InstrumentCloseType, identifiers::InstrumentId,
37 python::common::PY_MODULE_MODEL, types::Price,
38};
39
40#[pymethods]
44#[pyo3_stub_gen::derive::gen_stub_pymethods]
45impl InstrumentClose {
46 #[new]
48 #[pyo3(signature = (instrument_id, close_price, close_type, ts_event, ts_init))]
49 fn py_new(
50 instrument_id: InstrumentId,
51 close_price: Price,
52 close_type: InstrumentCloseType,
53 ts_event: u64,
54 ts_init: u64,
55 ) -> Self {
56 Self {
57 instrument_id,
58 close_price,
59 close_type,
60 ts_event: ts_event.into(),
61 ts_init: ts_init.into(),
62 }
63 }
64
65 fn __richcmp__(&self, other: &Self, op: CompareOp, py: Python<'_>) -> Py<PyAny> {
66 match op {
67 CompareOp::Eq => self.eq(other).into_py_any_unwrap(py),
68 CompareOp::Ne => self.ne(other).into_py_any_unwrap(py),
69 _ => py.NotImplemented(),
70 }
71 }
72
73 fn __hash__(&self) -> isize {
74 let mut h = DefaultHasher::new();
75 self.hash(&mut h);
76 h.finish() as isize
77 }
78
79 fn __repr__(&self) -> String {
80 format!("{}({})", stringify!(InstrumentStatus), self)
81 }
82
83 fn __str__(&self) -> String {
84 self.to_string()
85 }
86
87 #[getter]
88 #[pyo3(name = "instrument_id")]
89 fn py_instrument_id(&self) -> InstrumentId {
90 self.instrument_id
91 }
92
93 #[getter]
94 #[pyo3(name = "close_price")]
95 #[must_use]
96 pub fn py_close_price(&self) -> Price {
97 self.close_price
98 }
99
100 #[getter]
101 #[pyo3(name = "close_type")]
102 #[must_use]
103 pub fn py_close_type(&self) -> InstrumentCloseType {
104 self.close_type
105 }
106
107 #[getter]
108 #[pyo3(name = "ts_event")]
109 #[must_use]
110 pub fn py_ts_event(&self) -> u64 {
111 self.ts_event.as_u64()
112 }
113
114 #[getter]
115 #[pyo3(name = "ts_init")]
116 #[must_use]
117 pub fn py_ts_init(&self) -> u64 {
118 self.ts_init.as_u64()
119 }
120
121 #[staticmethod]
122 #[pyo3(name = "fully_qualified_name")]
123 fn py_fully_qualified_name() -> String {
124 format!("{}:{}", PY_MODULE_MODEL, stringify!(InstrumentClose))
125 }
126
127 #[staticmethod]
129 #[pyo3(name = "get_metadata")]
130 fn py_get_metadata(
131 instrument_id: &InstrumentId,
132 price_precision: u8,
133 ) -> HashMap<String, String> {
134 Self::get_metadata(instrument_id, price_precision)
135 }
136
137 #[staticmethod]
139 #[pyo3(name = "get_fields")]
140 fn py_get_fields(py: Python<'_>) -> PyResult<Bound<'_, PyDict>> {
141 let py_dict = PyDict::new(py);
142 for (k, v) in Self::get_fields() {
143 py_dict.set_item(k, v)?;
144 }
145
146 Ok(py_dict)
147 }
148
149 #[staticmethod]
151 #[pyo3(name = "from_dict")]
152 fn py_from_dict(py: Python<'_>, values: Py<PyDict>) -> PyResult<Self> {
153 from_dict_pyo3(py, values)
154 }
155
156 #[pyo3(name = "to_dict")]
158 fn py_to_dict(&self, py: Python<'_>) -> PyResult<Py<PyDict>> {
159 to_dict_pyo3(py, self)
160 }
161
162 #[pyo3(name = "to_json_bytes")]
164 fn py_to_json_bytes(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
165 self.to_json_bytes()
166 .map_err(to_pyvalue_err)?
167 .into_py_any(py)
168 }
169
170 #[pyo3(name = "to_msgpack_bytes")]
172 fn py_to_msgpack_bytes(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
173 self.to_msgpack_bytes()
174 .map_err(to_pyvalue_err)?
175 .into_py_any(py)
176 }
177}
178
179#[pymethods]
180impl InstrumentClose {
181 #[staticmethod]
182 #[pyo3(name = "from_json")]
183 fn py_from_json(data: &[u8]) -> PyResult<Self> {
184 Self::from_json_bytes(data).map_err(to_pyvalue_err)
185 }
186
187 #[staticmethod]
188 #[pyo3(name = "from_msgpack")]
189 fn py_from_msgpack(data: &[u8]) -> PyResult<Self> {
190 Self::from_msgpack_bytes(data).map_err(to_pyvalue_err)
191 }
192}
193
194pub fn pyobjects_to_instrument_closes(
200 data: Vec<Bound<'_, PyAny>>,
201) -> PyResult<Vec<InstrumentClose>> {
202 let closes = data
203 .into_iter()
204 .map(|obj| obj.extract::<InstrumentClose>().map_err(PyErr::from))
205 .collect::<PyResult<Vec<InstrumentClose>>>()?;
206
207 if !crate::data::is_monotonically_increasing_by_init(&closes) {
209 return Err(to_pyvalue_err(ERROR_MONOTONICITY));
210 }
211
212 Ok(closes)
213}