nautilus_live/python/client/
requests.rs1use std::num::NonZero;
23
24use nautilus_common::messages::data::{
25 RequestBars, RequestBookDeltas, RequestBookDepth, RequestBookSnapshot, RequestCustomData,
26 RequestFundingRates, RequestInstrument, RequestInstruments, RequestOptionChainReferencePrice,
27 RequestQuotes, RequestTrades,
28};
29use nautilus_core::{
30 UUID4,
31 python::{params::params_to_pydict, to_pyvalue_err},
32};
33use nautilus_model::{
34 data::{BarType, DataType},
35 identifiers::{ClientId, InstrumentId, OptionSeriesId, Venue},
36};
37use pyo3::{IntoPyObjectExt, prelude::*, types::PyDict};
38
39macro_rules! request {
40 ($wrapper:ident, $request:ident, $name:tt, $client_id:ty, {$($field:ident: $ty:ty = $convert:expr),* $(,)?}) => {
41 #[doc = concat!("An owned ", $name, " request.")]
42 #[pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.live")]
43 #[pyclass(name = $name, module = "nautilus_trader.live", frozen)]
44 #[derive(Debug)]
45 pub struct $wrapper {
46 pub(crate) request: $request,
47 }
48
49 #[pyo3_stub_gen::derive::gen_stub_pymethods]
50 #[pymethods]
51 impl $wrapper {
52 #[getter]
53 fn client_id(&self) -> $client_id { self.request.client_id }
54
55 #[getter]
56 fn request_id(&self) -> UUID4 { self.request.request_id }
57
58 #[getter]
59 fn ts_init(&self) -> u64 { self.request.ts_init.as_u64() }
60
61 #[getter]
62 fn params(&self, py: Python<'_>) -> PyResult<Option<Py<PyDict>>> {
63 self.request.params.as_ref().map(|params| params_to_pydict(py, params)).transpose()
64 }
65 $(
66 #[getter]
67 fn $field(&self) -> $ty { ($convert)(&self.request) }
68 )*
69 }
70 };
71}
72
73macro_rules! request_window {
74 ($wrapper:ident) => {
75 #[pyo3_stub_gen::derive::gen_stub_pymethods]
76 #[pymethods]
77 impl $wrapper {
78 #[getter]
79 #[gen_stub(override_return_type(type_repr = "datetime.datetime | None", imports = ("datetime",)))]
80 fn start(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
81 self.request.start.into_py_any(py)
82 }
83
84 #[getter]
85 #[gen_stub(override_return_type(type_repr = "datetime.datetime | None", imports = ("datetime",)))]
86 fn end(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
87 self.request.end.into_py_any(py)
88 }
89
90 #[getter]
91 fn start_ns(&self) -> Option<i128> {
92 self.request.start.map(|timestamp| timestamp.as_nanosecond())
93 }
94
95 #[getter]
96 fn end_ns(&self) -> Option<i128> {
97 self.request.end.map(|timestamp| timestamp.as_nanosecond())
98 }
99 }
100 };
101}
102
103request!(PyRequestCustomData, RequestCustomData, "RequestCustomData", ClientId, {
104 data_type: DataType = |request: &RequestCustomData| request.data_type.clone(),
105 limit: Option<usize> = |request: &RequestCustomData| request.limit.map(NonZero::get)
106});
107request_window!(PyRequestCustomData);
108
109request!(PyRequestInstruments, RequestInstruments, "RequestInstruments", Option<ClientId>, {
110 venue: Option<Venue> = |request: &RequestInstruments| request.venue
111});
112request_window!(PyRequestInstruments);
113
114request!(PyRequestInstrument, RequestInstrument, "RequestInstrument", Option<ClientId>, {
115 instrument_ids: Vec<InstrumentId> = |request: &RequestInstrument| request.instrument_ids.clone(),
116 instrument_id: PyResult<InstrumentId> = |request: &RequestInstrument| request.single_instrument_id().map_err(to_pyvalue_err)
117});
118request_window!(PyRequestInstrument);
119
120request!(PyRequestBookSnapshot, RequestBookSnapshot, "RequestBookSnapshot", Option<ClientId>, {
121 instrument_ids: Vec<InstrumentId> = |request: &RequestBookSnapshot| request.instrument_ids.clone(),
122 instrument_id: PyResult<InstrumentId> = |request: &RequestBookSnapshot| request.single_instrument_id().map_err(to_pyvalue_err),
123 depth: Option<usize> = |request: &RequestBookSnapshot| request.depth.map(NonZero::get)
124});
125
126request!(PyRequestQuotes, RequestQuotes, "RequestQuotes", Option<ClientId>, {
127 instrument_ids: Vec<InstrumentId> = |request: &RequestQuotes| request.instrument_ids.clone(),
128 instrument_id: PyResult<InstrumentId> = |request: &RequestQuotes| request.single_instrument_id().map_err(to_pyvalue_err),
129 limit: Option<usize> = |request: &RequestQuotes| request.limit.map(NonZero::get)
130});
131request_window!(PyRequestQuotes);
132
133request!(PyRequestTrades, RequestTrades, "RequestTrades", Option<ClientId>, {
134 instrument_ids: Vec<InstrumentId> = |request: &RequestTrades| request.instrument_ids.clone(),
135 instrument_id: PyResult<InstrumentId> = |request: &RequestTrades| request.single_instrument_id().map_err(to_pyvalue_err),
136 limit: Option<usize> = |request: &RequestTrades| request.limit.map(NonZero::get)
137});
138request_window!(PyRequestTrades);
139
140request!(PyRequestFundingRates, RequestFundingRates, "RequestFundingRates", Option<ClientId>, {
141 instrument_ids: Vec<InstrumentId> = |request: &RequestFundingRates| request.instrument_ids.clone(),
142 instrument_id: PyResult<InstrumentId> = |request: &RequestFundingRates| request.single_instrument_id().map_err(to_pyvalue_err),
143 limit: Option<usize> = |request: &RequestFundingRates| request.limit.map(NonZero::get)
144});
145request_window!(PyRequestFundingRates);
146
147request!(PyRequestOptionChainReferencePrice, RequestOptionChainReferencePrice, "RequestOptionChainReferencePrice", Option<ClientId>, {
148 instrument_id: InstrumentId = |request: &RequestOptionChainReferencePrice| request.instrument_id,
149 series_id: OptionSeriesId = |request: &RequestOptionChainReferencePrice| request.series_id
150});
151
152request!(PyRequestBars, RequestBars, "RequestBars", Option<ClientId>, {
153 bar_types: Vec<BarType> = |request: &RequestBars| request.bar_types.clone(),
154 bar_type: PyResult<BarType> = |request: &RequestBars| request.single_bar_type().map_err(to_pyvalue_err),
155 limit: Option<usize> = |request: &RequestBars| request.limit.map(NonZero::get)
156});
157request_window!(PyRequestBars);
158
159request!(PyRequestBookDepth, RequestBookDepth, "RequestBookDepth", Option<ClientId>, {
160 instrument_ids: Vec<InstrumentId> = |request: &RequestBookDepth| request.instrument_ids.clone(),
161 instrument_id: PyResult<InstrumentId> = |request: &RequestBookDepth| request.single_instrument_id().map_err(to_pyvalue_err),
162 limit: Option<usize> = |request: &RequestBookDepth| request.limit.map(NonZero::get),
163 depth: Option<usize> = |request: &RequestBookDepth| request.depth.map(NonZero::get)
164});
165request_window!(PyRequestBookDepth);
166
167request!(PyRequestBookDeltas, RequestBookDeltas, "RequestBookDeltas", Option<ClientId>, {
168 instrument_ids: Vec<InstrumentId> = |request: &RequestBookDeltas| request.instrument_ids.clone(),
169 instrument_id: PyResult<InstrumentId> = |request: &RequestBookDeltas| request.single_instrument_id().map_err(to_pyvalue_err),
170 limit: Option<usize> = |request: &RequestBookDeltas| request.limit.map(NonZero::get)
171});
172request_window!(PyRequestBookDeltas);
173
174pub(crate) fn register(m: &Bound<'_, PyModule>) -> PyResult<()> {
175 m.add_class::<PyRequestCustomData>()?;
176 m.add_class::<PyRequestInstruments>()?;
177 m.add_class::<PyRequestInstrument>()?;
178 m.add_class::<PyRequestBookSnapshot>()?;
179 m.add_class::<PyRequestQuotes>()?;
180 m.add_class::<PyRequestTrades>()?;
181 m.add_class::<PyRequestFundingRates>()?;
182 m.add_class::<PyRequestOptionChainReferencePrice>()?;
183 m.add_class::<PyRequestBars>()?;
184 m.add_class::<PyRequestBookDepth>()?;
185 m.add_class::<PyRequestBookDeltas>()?;
186 Ok(())
187}