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    IntoPyObjectExt,
30    basic::CompareOp,
31    prelude::*,
32    types::{PyDict, PyList},
33};
34use rust_decimal::Decimal;
35
36use crate::{
37    common::bar::BinanceBar,
38    data_types::{
39        BinanceFuturesLiquidation, BinanceFuturesMarkPriceUpdate, BinanceFuturesOpenInterest,
40        BinanceFuturesOpenInterestHist, BinanceFuturesOpenInterestHistPoint, BinanceFuturesTicker,
41        BinanceSpotTicker,
42    },
43};
44
45#[pymethods]
46#[pyo3_stub_gen::derive::gen_stub_pymethods]
47impl BinanceBar {
48    fn __richcmp__(&self, other: &Self, op: CompareOp, py: Python<'_>) -> Py<PyAny> {
49        match op {
50            CompareOp::Eq => self.eq(other).into_py_any_unwrap(py),
51            CompareOp::Ne => self.ne(other).into_py_any_unwrap(py),
52            _ => py.NotImplemented(),
53        }
54    }
55
56    fn __hash__(&self) -> isize {
57        let mut hasher = DefaultHasher::new();
58        self.bar_type.hash(&mut hasher);
59        self.ts_event.hash(&mut hasher);
60        hasher.finish() as isize
61    }
62
63    fn __repr__(&self) -> String {
64        format!(
65            "{}(bar_type={}, open={}, high={}, low={}, close={}, volume={}, quote_volume={}, count={}, taker_buy_base_volume={}, taker_buy_quote_volume={}, ts_event={}, ts_init={})",
66            stringify!(BinanceBar),
67            self.bar_type,
68            self.open,
69            self.high,
70            self.low,
71            self.close,
72            self.volume,
73            self.quote_volume,
74            self.count,
75            self.taker_buy_base_volume,
76            self.taker_buy_quote_volume,
77            self.ts_event,
78            self.ts_init,
79        )
80    }
81
82    fn __str__(&self) -> String {
83        self.__repr__()
84    }
85
86    #[getter]
87    #[pyo3(name = "bar_type")]
88    fn py_bar_type(&self) -> BarType {
89        self.bar_type
90    }
91
92    #[getter]
93    #[pyo3(name = "open")]
94    const fn py_open(&self) -> Price {
95        self.open
96    }
97
98    #[getter]
99    #[pyo3(name = "high")]
100    const fn py_high(&self) -> Price {
101        self.high
102    }
103
104    #[getter]
105    #[pyo3(name = "low")]
106    const fn py_low(&self) -> Price {
107        self.low
108    }
109
110    #[getter]
111    #[pyo3(name = "close")]
112    const fn py_close(&self) -> Price {
113        self.close
114    }
115
116    #[getter]
117    #[pyo3(name = "volume")]
118    const fn py_volume(&self) -> Quantity {
119        self.volume
120    }
121
122    #[getter]
123    #[pyo3(name = "quote_volume")]
124    fn py_quote_volume(&self) -> Decimal {
125        self.quote_volume
126    }
127
128    #[getter]
129    #[pyo3(name = "count")]
130    const fn py_count(&self) -> u64 {
131        self.count
132    }
133
134    #[getter]
135    #[pyo3(name = "taker_buy_base_volume")]
136    fn py_taker_buy_base_volume(&self) -> Decimal {
137        self.taker_buy_base_volume
138    }
139
140    #[getter]
141    #[pyo3(name = "taker_buy_quote_volume")]
142    fn py_taker_buy_quote_volume(&self) -> Decimal {
143        self.taker_buy_quote_volume
144    }
145
146    #[getter]
147    #[pyo3(name = "ts_event")]
148    const fn py_ts_event(&self) -> u64 {
149        self.ts_event.as_u64()
150    }
151
152    #[getter]
153    #[pyo3(name = "ts_init")]
154    const fn py_ts_init(&self) -> u64 {
155        self.ts_init.as_u64()
156    }
157
158    #[staticmethod]
159    #[pyo3(name = "from_dict")]
160    fn py_from_dict(py: Python<'_>, values: Py<PyDict>) -> PyResult<Self> {
161        from_dict_pyo3(py, values)
162    }
163
164    /// # Errors
165    ///
166    /// Returns a `PyErr` if generating the Python dictionary fails.
167    #[pyo3(name = "to_dict")]
168    pub fn py_to_dict(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
169        let dict = PyDict::new(py);
170        dict.set_item("type", stringify!(BinanceBar))?;
171        dict.set_item("bar_type", self.bar_type.to_string())?;
172        dict.set_item("open", self.open.to_string())?;
173        dict.set_item("high", self.high.to_string())?;
174        dict.set_item("low", self.low.to_string())?;
175        dict.set_item("close", self.close.to_string())?;
176        dict.set_item("volume", self.volume.to_string())?;
177        dict.set_item("quote_volume", self.quote_volume.to_string())?;
178        dict.set_item("count", self.count)?;
179        dict.set_item(
180            "taker_buy_base_volume",
181            self.taker_buy_base_volume.to_string(),
182        )?;
183        dict.set_item(
184            "taker_buy_quote_volume",
185            self.taker_buy_quote_volume.to_string(),
186        )?;
187        dict.set_item("ts_event", self.ts_event.as_u64())?;
188        dict.set_item("ts_init", self.ts_init.as_u64())?;
189        Ok(dict.into())
190    }
191}
192
193#[pymethods]
194#[pyo3_stub_gen::derive::gen_stub_pymethods]
195impl BinanceFuturesLiquidation {
196    #[getter]
197    #[pyo3(name = "instrument_id")]
198    fn py_instrument_id(&self) -> InstrumentId {
199        self.instrument_id
200    }
201
202    #[getter]
203    #[pyo3(name = "side")]
204    fn py_side(&self) -> OrderSide {
205        self.side
206    }
207
208    #[getter]
209    #[pyo3(name = "price")]
210    fn py_price(&self) -> Price {
211        self.price
212    }
213
214    #[getter]
215    #[pyo3(name = "average_price")]
216    fn py_average_price(&self) -> Price {
217        self.average_price
218    }
219
220    #[getter]
221    #[pyo3(name = "last_filled_qty")]
222    fn py_last_filled_qty(&self) -> Quantity {
223        self.last_filled_qty
224    }
225
226    #[getter]
227    #[pyo3(name = "accumulated_qty")]
228    fn py_accumulated_qty(&self) -> Quantity {
229        self.accumulated_qty
230    }
231
232    #[getter]
233    #[pyo3(name = "ts_event")]
234    fn py_ts_event(&self) -> u64 {
235        self.ts_event.as_u64()
236    }
237
238    #[getter]
239    #[pyo3(name = "ts_init")]
240    fn py_ts_init(&self) -> u64 {
241        self.ts_init.as_u64()
242    }
243}
244
245#[pymethods]
246#[pyo3_stub_gen::derive::gen_stub_pymethods]
247impl BinanceFuturesTicker {
248    #[getter]
249    #[pyo3(name = "instrument_id")]
250    fn py_instrument_id(&self) -> InstrumentId {
251        self.instrument_id
252    }
253
254    #[getter]
255    #[pyo3(name = "price_change")]
256    fn py_price_change(&self) -> Decimal {
257        self.price_change
258    }
259
260    #[getter]
261    #[pyo3(name = "price_change_percent")]
262    fn py_price_change_percent(&self) -> Decimal {
263        self.price_change_percent
264    }
265
266    #[getter]
267    #[pyo3(name = "weighted_avg_price")]
268    fn py_weighted_avg_price(&self) -> Decimal {
269        self.weighted_avg_price
270    }
271
272    #[getter]
273    #[pyo3(name = "last_price")]
274    fn py_last_price(&self) -> Decimal {
275        self.last_price
276    }
277
278    #[getter]
279    #[pyo3(name = "last_qty")]
280    fn py_last_qty(&self) -> Decimal {
281        self.last_qty
282    }
283
284    #[getter]
285    #[pyo3(name = "open_price")]
286    fn py_open_price(&self) -> Decimal {
287        self.open_price
288    }
289
290    #[getter]
291    #[pyo3(name = "high_price")]
292    fn py_high_price(&self) -> Decimal {
293        self.high_price
294    }
295
296    #[getter]
297    #[pyo3(name = "low_price")]
298    fn py_low_price(&self) -> Decimal {
299        self.low_price
300    }
301
302    #[getter]
303    #[pyo3(name = "volume")]
304    fn py_volume(&self) -> Decimal {
305        self.volume
306    }
307
308    #[getter]
309    #[pyo3(name = "quote_volume")]
310    fn py_quote_volume(&self) -> Decimal {
311        self.quote_volume
312    }
313
314    #[getter]
315    #[pyo3(name = "open_time")]
316    fn py_open_time(&self) -> u64 {
317        self.open_time.as_u64()
318    }
319
320    #[getter]
321    #[pyo3(name = "close_time")]
322    fn py_close_time(&self) -> u64 {
323        self.close_time.as_u64()
324    }
325
326    #[getter]
327    #[pyo3(name = "first_trade_id")]
328    fn py_first_trade_id(&self) -> i64 {
329        self.first_trade_id
330    }
331
332    #[getter]
333    #[pyo3(name = "last_trade_id")]
334    fn py_last_trade_id(&self) -> i64 {
335        self.last_trade_id
336    }
337
338    #[getter]
339    #[pyo3(name = "num_trades")]
340    fn py_num_trades(&self) -> i64 {
341        self.num_trades
342    }
343
344    #[getter]
345    #[pyo3(name = "ts_event")]
346    fn py_ts_event(&self) -> u64 {
347        self.ts_event.as_u64()
348    }
349
350    #[getter]
351    #[pyo3(name = "ts_init")]
352    fn py_ts_init(&self) -> u64 {
353        self.ts_init.as_u64()
354    }
355}
356
357#[pymethods]
358#[pyo3_stub_gen::derive::gen_stub_pymethods]
359impl BinanceSpotTicker {
360    #[getter]
361    fn instrument_id(&self) -> InstrumentId {
362        self.instrument_id
363    }
364    #[getter]
365    fn price_change(&self) -> Decimal {
366        self.price_change
367    }
368    #[getter]
369    fn price_change_percent(&self) -> Decimal {
370        self.price_change_percent
371    }
372    #[getter]
373    fn weighted_avg_price(&self) -> Decimal {
374        self.weighted_avg_price
375    }
376    #[getter]
377    fn prev_close_price(&self) -> Decimal {
378        self.prev_close_price
379    }
380    #[getter]
381    fn last_price(&self) -> Decimal {
382        self.last_price
383    }
384    #[getter]
385    fn last_qty(&self) -> Decimal {
386        self.last_qty
387    }
388    #[getter]
389    fn bid_price(&self) -> Decimal {
390        self.bid_price
391    }
392    #[getter]
393    fn bid_qty(&self) -> Decimal {
394        self.bid_qty
395    }
396    #[getter]
397    fn ask_price(&self) -> Decimal {
398        self.ask_price
399    }
400    #[getter]
401    fn ask_qty(&self) -> Decimal {
402        self.ask_qty
403    }
404    #[getter]
405    fn open_price(&self) -> Decimal {
406        self.open_price
407    }
408    #[getter]
409    fn high_price(&self) -> Decimal {
410        self.high_price
411    }
412    #[getter]
413    fn low_price(&self) -> Decimal {
414        self.low_price
415    }
416    #[getter]
417    fn volume(&self) -> Decimal {
418        self.volume
419    }
420    #[getter]
421    fn quote_volume(&self) -> Decimal {
422        self.quote_volume
423    }
424    #[getter]
425    fn open_time(&self) -> u64 {
426        self.open_time.as_u64()
427    }
428    #[getter]
429    fn close_time(&self) -> u64 {
430        self.close_time.as_u64()
431    }
432    #[getter]
433    fn first_trade_id(&self) -> i64 {
434        self.first_trade_id
435    }
436    #[getter]
437    fn last_trade_id(&self) -> i64 {
438        self.last_trade_id
439    }
440    #[getter]
441    fn num_trades(&self) -> i64 {
442        self.num_trades
443    }
444    #[getter]
445    fn ts_event(&self) -> u64 {
446        self.ts_event.as_u64()
447    }
448    #[getter]
449    fn ts_init(&self) -> u64 {
450        self.ts_init.as_u64()
451    }
452}
453
454#[pymethods]
455#[pyo3_stub_gen::derive::gen_stub_pymethods]
456impl BinanceFuturesMarkPriceUpdate {
457    #[getter]
458    fn instrument_id(&self) -> InstrumentId {
459        self.instrument_id
460    }
461    #[getter]
462    fn mark_price(&self) -> Price {
463        self.mark_price
464    }
465    #[getter]
466    fn index_price(&self) -> Price {
467        self.index_price
468    }
469    #[getter]
470    fn estimated_settle_price(&self) -> Price {
471        self.estimated_settle_price
472    }
473    #[getter]
474    fn funding_rate(&self) -> Decimal {
475        self.funding_rate
476    }
477    #[getter]
478    fn next_funding_time(&self) -> Option<u64> {
479        self.next_funding_time.map(|time| time.as_u64())
480    }
481    #[getter]
482    fn ts_event(&self) -> u64 {
483        self.ts_event.as_u64()
484    }
485    #[getter]
486    fn ts_init(&self) -> u64 {
487        self.ts_init.as_u64()
488    }
489}
490
491#[pymethods]
492#[pyo3_stub_gen::derive::gen_stub_pymethods]
493impl BinanceFuturesOpenInterest {
494    #[getter]
495    #[pyo3(name = "instrument_id")]
496    fn py_instrument_id(&self) -> InstrumentId {
497        self.instrument_id
498    }
499
500    #[getter]
501    #[pyo3(name = "open_interest")]
502    fn py_open_interest(&self) -> Decimal {
503        self.open_interest
504    }
505
506    #[getter]
507    #[pyo3(name = "ts_event")]
508    fn py_ts_event(&self) -> u64 {
509        self.ts_event.as_u64()
510    }
511
512    #[getter]
513    #[pyo3(name = "ts_init")]
514    fn py_ts_init(&self) -> u64 {
515        self.ts_init.as_u64()
516    }
517}
518
519#[pymethods]
520#[pyo3_stub_gen::derive::gen_stub_pymethods]
521impl BinanceFuturesOpenInterestHistPoint {
522    #[getter]
523    #[pyo3(name = "sum_open_interest")]
524    fn py_sum_open_interest(&self) -> Decimal {
525        self.sum_open_interest
526    }
527
528    #[getter]
529    #[pyo3(name = "sum_open_interest_value")]
530    fn py_sum_open_interest_value(&self) -> Decimal {
531        self.sum_open_interest_value
532    }
533
534    #[getter]
535    #[pyo3(name = "ts_event")]
536    fn py_ts_event(&self) -> u64 {
537        self.ts_event.as_u64()
538    }
539}
540
541#[pymethods]
542#[pyo3_stub_gen::derive::gen_stub_pymethods]
543impl BinanceFuturesOpenInterestHist {
544    #[getter]
545    #[pyo3(name = "instrument_id")]
546    fn py_instrument_id(&self) -> InstrumentId {
547        self.instrument_id
548    }
549
550    #[getter]
551    #[pyo3(name = "period")]
552    fn py_period(&self) -> String {
553        self.period.clone()
554    }
555
556    #[getter]
557    #[pyo3(name = "points")]
558    fn py_points(&self, py: Python<'_>) -> PyResult<Py<PyList>> {
559        let points = self
560            .points
561            .iter()
562            .cloned()
563            .map(|point| point.into_py_any(py))
564            .collect::<PyResult<Vec<_>>>()?;
565        Ok(PyList::new(py, points)?.into())
566    }
567
568    #[getter]
569    #[pyo3(name = "ts_event")]
570    fn py_ts_event(&self) -> u64 {
571        self.ts_event.as_u64()
572    }
573
574    #[getter]
575    #[pyo3(name = "ts_init")]
576    fn py_ts_init(&self) -> u64 {
577        self.ts_init.as_u64()
578    }
579}