Skip to main content

nautilus_binance/python/
types.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16use std::{
17    collections::hash_map::DefaultHasher,
18    hash::{Hash, Hasher},
19};
20
21use nautilus_core::python::{IntoPyObjectNautilusExt, serialization::from_dict_pyo3};
22use nautilus_model::{
23    data::bar::BarType,
24    enums::OrderSide,
25    identifiers::InstrumentId,
26    types::{Price, Quantity},
27};
28use pyo3::{
29    basic::CompareOp,
30    prelude::*,
31    types::{PyDict, PyList},
32};
33use rust_decimal::Decimal;
34
35use crate::{
36    common::bar::BinanceBar,
37    data_types::{
38        BinanceFuturesLiquidation, BinanceFuturesOpenInterest, BinanceFuturesOpenInterestHist,
39        BinanceFuturesOpenInterestHistPoint, BinanceFuturesTicker,
40    },
41};
42
43#[pymethods]
44#[pyo3_stub_gen::derive::gen_stub_pymethods]
45impl BinanceBar {
46    fn __richcmp__(&self, other: &Self, op: CompareOp, py: Python<'_>) -> Py<PyAny> {
47        match op {
48            CompareOp::Eq => self.eq(other).into_py_any_unwrap(py),
49            CompareOp::Ne => self.ne(other).into_py_any_unwrap(py),
50            _ => py.NotImplemented(),
51        }
52    }
53
54    fn __hash__(&self) -> isize {
55        let mut hasher = DefaultHasher::new();
56        self.bar_type.hash(&mut hasher);
57        self.ts_event.hash(&mut hasher);
58        hasher.finish() as isize
59    }
60
61    fn __repr__(&self) -> String {
62        format!(
63            "{}(bar_type={}, open={}, high={}, low={}, close={}, volume={}, quote_volume={}, count={}, taker_buy_base_volume={}, taker_buy_quote_volume={}, ts_event={}, ts_init={})",
64            stringify!(BinanceBar),
65            self.bar_type,
66            self.open,
67            self.high,
68            self.low,
69            self.close,
70            self.volume,
71            self.quote_volume,
72            self.count,
73            self.taker_buy_base_volume,
74            self.taker_buy_quote_volume,
75            self.ts_event,
76            self.ts_init,
77        )
78    }
79
80    fn __str__(&self) -> String {
81        self.__repr__()
82    }
83
84    #[getter]
85    #[pyo3(name = "bar_type")]
86    fn py_bar_type(&self) -> BarType {
87        self.bar_type
88    }
89
90    #[getter]
91    #[pyo3(name = "open")]
92    const fn py_open(&self) -> Price {
93        self.open
94    }
95
96    #[getter]
97    #[pyo3(name = "high")]
98    const fn py_high(&self) -> Price {
99        self.high
100    }
101
102    #[getter]
103    #[pyo3(name = "low")]
104    const fn py_low(&self) -> Price {
105        self.low
106    }
107
108    #[getter]
109    #[pyo3(name = "close")]
110    const fn py_close(&self) -> Price {
111        self.close
112    }
113
114    #[getter]
115    #[pyo3(name = "volume")]
116    const fn py_volume(&self) -> Quantity {
117        self.volume
118    }
119
120    #[getter]
121    #[pyo3(name = "quote_volume")]
122    fn py_quote_volume(&self) -> Decimal {
123        self.quote_volume
124    }
125
126    #[getter]
127    #[pyo3(name = "count")]
128    const fn py_count(&self) -> u64 {
129        self.count
130    }
131
132    #[getter]
133    #[pyo3(name = "taker_buy_base_volume")]
134    fn py_taker_buy_base_volume(&self) -> Decimal {
135        self.taker_buy_base_volume
136    }
137
138    #[getter]
139    #[pyo3(name = "taker_buy_quote_volume")]
140    fn py_taker_buy_quote_volume(&self) -> Decimal {
141        self.taker_buy_quote_volume
142    }
143
144    #[getter]
145    #[pyo3(name = "ts_event")]
146    const fn py_ts_event(&self) -> u64 {
147        self.ts_event.as_u64()
148    }
149
150    #[getter]
151    #[pyo3(name = "ts_init")]
152    const fn py_ts_init(&self) -> u64 {
153        self.ts_init.as_u64()
154    }
155
156    #[staticmethod]
157    #[pyo3(name = "from_dict")]
158    fn py_from_dict(py: Python<'_>, values: Py<PyDict>) -> PyResult<Self> {
159        from_dict_pyo3(py, values)
160    }
161
162    /// # Errors
163    ///
164    /// Returns a `PyErr` if generating the Python dictionary fails.
165    #[pyo3(name = "to_dict")]
166    pub fn py_to_dict(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
167        let dict = PyDict::new(py);
168        dict.set_item("type", stringify!(BinanceBar))?;
169        dict.set_item("bar_type", self.bar_type.to_string())?;
170        dict.set_item("open", self.open.to_string())?;
171        dict.set_item("high", self.high.to_string())?;
172        dict.set_item("low", self.low.to_string())?;
173        dict.set_item("close", self.close.to_string())?;
174        dict.set_item("volume", self.volume.to_string())?;
175        dict.set_item("quote_volume", self.quote_volume.to_string())?;
176        dict.set_item("count", self.count)?;
177        dict.set_item(
178            "taker_buy_base_volume",
179            self.taker_buy_base_volume.to_string(),
180        )?;
181        dict.set_item(
182            "taker_buy_quote_volume",
183            self.taker_buy_quote_volume.to_string(),
184        )?;
185        dict.set_item("ts_event", self.ts_event.as_u64())?;
186        dict.set_item("ts_init", self.ts_init.as_u64())?;
187        Ok(dict.into())
188    }
189}
190
191#[pymethods]
192#[pyo3_stub_gen::derive::gen_stub_pymethods]
193impl BinanceFuturesLiquidation {
194    #[getter]
195    #[pyo3(name = "instrument_id")]
196    fn py_instrument_id(&self) -> InstrumentId {
197        self.instrument_id
198    }
199
200    #[getter]
201    #[pyo3(name = "side")]
202    fn py_side(&self) -> OrderSide {
203        self.side
204    }
205
206    #[getter]
207    #[pyo3(name = "price")]
208    fn py_price(&self) -> Price {
209        self.price
210    }
211
212    #[getter]
213    #[pyo3(name = "average_price")]
214    fn py_average_price(&self) -> Price {
215        self.average_price
216    }
217
218    #[getter]
219    #[pyo3(name = "last_filled_qty")]
220    fn py_last_filled_qty(&self) -> Quantity {
221        self.last_filled_qty
222    }
223
224    #[getter]
225    #[pyo3(name = "accumulated_qty")]
226    fn py_accumulated_qty(&self) -> Quantity {
227        self.accumulated_qty
228    }
229
230    #[getter]
231    #[pyo3(name = "ts_event")]
232    fn py_ts_event(&self) -> u64 {
233        self.ts_event.as_u64()
234    }
235
236    #[getter]
237    #[pyo3(name = "ts_init")]
238    fn py_ts_init(&self) -> u64 {
239        self.ts_init.as_u64()
240    }
241}
242
243#[pymethods]
244#[pyo3_stub_gen::derive::gen_stub_pymethods]
245impl BinanceFuturesTicker {
246    #[getter]
247    #[pyo3(name = "instrument_id")]
248    fn py_instrument_id(&self) -> InstrumentId {
249        self.instrument_id
250    }
251
252    #[getter]
253    #[pyo3(name = "price_change")]
254    fn py_price_change(&self) -> Decimal {
255        self.price_change
256    }
257
258    #[getter]
259    #[pyo3(name = "price_change_percent")]
260    fn py_price_change_percent(&self) -> Decimal {
261        self.price_change_percent
262    }
263
264    #[getter]
265    #[pyo3(name = "weighted_avg_price")]
266    fn py_weighted_avg_price(&self) -> Decimal {
267        self.weighted_avg_price
268    }
269
270    #[getter]
271    #[pyo3(name = "last_price")]
272    fn py_last_price(&self) -> Decimal {
273        self.last_price
274    }
275
276    #[getter]
277    #[pyo3(name = "last_qty")]
278    fn py_last_qty(&self) -> Decimal {
279        self.last_qty
280    }
281
282    #[getter]
283    #[pyo3(name = "open_price")]
284    fn py_open_price(&self) -> Decimal {
285        self.open_price
286    }
287
288    #[getter]
289    #[pyo3(name = "high_price")]
290    fn py_high_price(&self) -> Decimal {
291        self.high_price
292    }
293
294    #[getter]
295    #[pyo3(name = "low_price")]
296    fn py_low_price(&self) -> Decimal {
297        self.low_price
298    }
299
300    #[getter]
301    #[pyo3(name = "volume")]
302    fn py_volume(&self) -> Decimal {
303        self.volume
304    }
305
306    #[getter]
307    #[pyo3(name = "quote_volume")]
308    fn py_quote_volume(&self) -> Decimal {
309        self.quote_volume
310    }
311
312    #[getter]
313    #[pyo3(name = "open_time")]
314    fn py_open_time(&self) -> u64 {
315        self.open_time.as_u64()
316    }
317
318    #[getter]
319    #[pyo3(name = "close_time")]
320    fn py_close_time(&self) -> u64 {
321        self.close_time.as_u64()
322    }
323
324    #[getter]
325    #[pyo3(name = "first_trade_id")]
326    fn py_first_trade_id(&self) -> i64 {
327        self.first_trade_id
328    }
329
330    #[getter]
331    #[pyo3(name = "last_trade_id")]
332    fn py_last_trade_id(&self) -> i64 {
333        self.last_trade_id
334    }
335
336    #[getter]
337    #[pyo3(name = "num_trades")]
338    fn py_num_trades(&self) -> i64 {
339        self.num_trades
340    }
341
342    #[getter]
343    #[pyo3(name = "ts_event")]
344    fn py_ts_event(&self) -> u64 {
345        self.ts_event.as_u64()
346    }
347
348    #[getter]
349    #[pyo3(name = "ts_init")]
350    fn py_ts_init(&self) -> u64 {
351        self.ts_init.as_u64()
352    }
353}
354
355#[pymethods]
356#[pyo3_stub_gen::derive::gen_stub_pymethods]
357impl BinanceFuturesOpenInterest {
358    #[getter]
359    #[pyo3(name = "instrument_id")]
360    fn py_instrument_id(&self) -> InstrumentId {
361        self.instrument_id
362    }
363
364    #[getter]
365    #[pyo3(name = "open_interest")]
366    fn py_open_interest(&self) -> Decimal {
367        self.open_interest
368    }
369
370    #[getter]
371    #[pyo3(name = "ts_event")]
372    fn py_ts_event(&self) -> u64 {
373        self.ts_event.as_u64()
374    }
375
376    #[getter]
377    #[pyo3(name = "ts_init")]
378    fn py_ts_init(&self) -> u64 {
379        self.ts_init.as_u64()
380    }
381}
382
383#[pymethods]
384#[pyo3_stub_gen::derive::gen_stub_pymethods]
385impl BinanceFuturesOpenInterestHistPoint {
386    #[getter]
387    #[pyo3(name = "sum_open_interest")]
388    fn py_sum_open_interest(&self) -> Decimal {
389        self.sum_open_interest
390    }
391
392    #[getter]
393    #[pyo3(name = "sum_open_interest_value")]
394    fn py_sum_open_interest_value(&self) -> Decimal {
395        self.sum_open_interest_value
396    }
397
398    #[getter]
399    #[pyo3(name = "ts_event")]
400    fn py_ts_event(&self) -> u64 {
401        self.ts_event.as_u64()
402    }
403}
404
405#[pymethods]
406#[pyo3_stub_gen::derive::gen_stub_pymethods]
407impl BinanceFuturesOpenInterestHist {
408    #[getter]
409    #[pyo3(name = "instrument_id")]
410    fn py_instrument_id(&self) -> InstrumentId {
411        self.instrument_id
412    }
413
414    #[getter]
415    #[pyo3(name = "period")]
416    fn py_period(&self) -> String {
417        self.period.clone()
418    }
419
420    #[getter]
421    #[pyo3(name = "points")]
422    fn py_points(&self, py: Python<'_>) -> PyResult<Py<PyList>> {
423        let points = self
424            .points
425            .iter()
426            .cloned()
427            .map(|point| point.into_py_any_unwrap(py))
428            .collect::<Vec<_>>();
429        Ok(PyList::new(py, points)?.into())
430    }
431
432    #[getter]
433    #[pyo3(name = "ts_event")]
434    fn py_ts_event(&self) -> u64 {
435        self.ts_event.as_u64()
436    }
437
438    #[getter]
439    #[pyo3(name = "ts_init")]
440    fn py_ts_init(&self) -> u64 {
441        self.ts_init.as_u64()
442    }
443}