1use chrono::{DateTime, Utc};
19use nautilus_core::python::to_pyvalue_err;
20use nautilus_model::{
21 data::BarType,
22 enums::{OrderSide, OrderType, TimeInForce},
23 identifiers::{AccountId, ClientOrderId, InstrumentId, VenueOrderId},
24 python::instruments::instrument_any_to_pyobject,
25 types::{Price, Quantity},
26};
27use pyo3::{IntoPyObjectExt, prelude::*, types::PyList};
28
29use crate::{common::enums::BinanceEnvironment, spot::http::client::BinanceSpotHttpClient};
30
31#[pymethods]
32impl BinanceSpotHttpClient {
33 #[new]
34 #[pyo3(signature = (
35 environment=BinanceEnvironment::Mainnet,
36 api_key=None,
37 api_secret=None,
38 base_url=None,
39 recv_window=None,
40 timeout_secs=None,
41 proxy_url=None,
42 ))]
43 #[allow(clippy::too_many_arguments)]
44 fn py_new(
45 environment: BinanceEnvironment,
46 api_key: Option<String>,
47 api_secret: Option<String>,
48 base_url: Option<String>,
49 recv_window: Option<u64>,
50 timeout_secs: Option<u64>,
51 proxy_url: Option<String>,
52 ) -> PyResult<Self> {
53 Self::new(
54 environment,
55 api_key,
56 api_secret,
57 base_url,
58 recv_window,
59 timeout_secs,
60 proxy_url,
61 )
62 .map_err(to_pyvalue_err)
63 }
64
65 #[getter]
66 #[pyo3(name = "schema_id")]
67 #[must_use]
68 pub fn py_schema_id(&self) -> u16 {
69 Self::schema_id()
70 }
71
72 #[getter]
73 #[pyo3(name = "schema_version")]
74 #[must_use]
75 pub fn py_schema_version(&self) -> u16 {
76 Self::schema_version()
77 }
78
79 #[pyo3(name = "ping")]
80 fn py_ping<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
81 let client = self.clone();
82 pyo3_async_runtimes::tokio::future_into_py(py, async move {
83 client.ping().await.map_err(to_pyvalue_err)?;
84 Python::attach(|py| Ok(py.None()))
85 })
86 }
87
88 #[pyo3(name = "server_time")]
89 fn py_server_time<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
90 let client = self.clone();
91 pyo3_async_runtimes::tokio::future_into_py(py, async move {
92 let timestamp = client.server_time().await.map_err(to_pyvalue_err)?;
93 Python::attach(|py| Ok(timestamp.into_pyobject(py)?.into_any().unbind()))
94 })
95 }
96
97 #[pyo3(name = "request_instruments")]
98 fn py_request_instruments<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
99 let client = self.clone();
100
101 pyo3_async_runtimes::tokio::future_into_py(py, async move {
102 let instruments = client.request_instruments().await.map_err(to_pyvalue_err)?;
103
104 Python::attach(|py| {
105 let py_instruments: PyResult<Vec<_>> = instruments
106 .into_iter()
107 .map(|inst| instrument_any_to_pyobject(py, inst))
108 .collect();
109 let pylist = PyList::new(py, py_instruments?)?.into_any().unbind();
110 Ok(pylist)
111 })
112 })
113 }
114
115 #[pyo3(name = "request_trades", signature = (instrument_id, limit=None))]
116 fn py_request_trades<'py>(
117 &self,
118 py: Python<'py>,
119 instrument_id: InstrumentId,
120 limit: Option<u32>,
121 ) -> PyResult<Bound<'py, PyAny>> {
122 let client = self.clone();
123
124 pyo3_async_runtimes::tokio::future_into_py(py, async move {
125 let trades = client
126 .request_trades(instrument_id, limit)
127 .await
128 .map_err(to_pyvalue_err)?;
129
130 Python::attach(|py| {
131 let py_trades: PyResult<Vec<_>> = trades
132 .into_iter()
133 .map(|tick| tick.into_py_any(py))
134 .collect();
135 let pylist = PyList::new(py, py_trades?)?.into_any().unbind();
136 Ok(pylist)
137 })
138 })
139 }
140
141 #[pyo3(name = "request_order_status")]
142 #[pyo3(signature = (
143 account_id,
144 instrument_id,
145 venue_order_id=None,
146 client_order_id=None,
147 ))]
148 fn py_request_order_status<'py>(
149 &self,
150 py: Python<'py>,
151 account_id: AccountId,
152 instrument_id: InstrumentId,
153 venue_order_id: Option<VenueOrderId>,
154 client_order_id: Option<ClientOrderId>,
155 ) -> PyResult<Bound<'py, PyAny>> {
156 let client = self.clone();
157
158 pyo3_async_runtimes::tokio::future_into_py(py, async move {
159 let report = client
160 .request_order_status(account_id, instrument_id, venue_order_id, client_order_id)
161 .await
162 .map_err(to_pyvalue_err)?;
163 Python::attach(|py| report.into_py_any(py))
164 })
165 }
166
167 #[pyo3(name = "request_order_status_reports")]
168 #[pyo3(signature = (
169 account_id,
170 instrument_id=None,
171 start=None,
172 end=None,
173 open_only=false,
174 limit=None,
175 ))]
176 #[allow(clippy::too_many_arguments)]
177 fn py_request_order_status_reports<'py>(
178 &self,
179 py: Python<'py>,
180 account_id: AccountId,
181 instrument_id: Option<InstrumentId>,
182 start: Option<DateTime<Utc>>,
183 end: Option<DateTime<Utc>>,
184 open_only: bool,
185 limit: Option<u32>,
186 ) -> PyResult<Bound<'py, PyAny>> {
187 let client = self.clone();
188
189 pyo3_async_runtimes::tokio::future_into_py(py, async move {
190 let reports = client
191 .request_order_status_reports(
192 account_id,
193 instrument_id,
194 start,
195 end,
196 open_only,
197 limit,
198 )
199 .await
200 .map_err(to_pyvalue_err)?;
201
202 Python::attach(|py| {
203 let py_reports: PyResult<Vec<_>> =
204 reports.into_iter().map(|r| r.into_py_any(py)).collect();
205 let pylist = PyList::new(py, py_reports?)?.into_any().unbind();
206 Ok(pylist)
207 })
208 })
209 }
210
211 #[pyo3(name = "request_fill_reports")]
212 #[pyo3(signature = (
213 account_id,
214 instrument_id,
215 venue_order_id=None,
216 start=None,
217 end=None,
218 limit=None,
219 ))]
220 #[allow(clippy::too_many_arguments)]
221 fn py_request_fill_reports<'py>(
222 &self,
223 py: Python<'py>,
224 account_id: AccountId,
225 instrument_id: InstrumentId,
226 venue_order_id: Option<VenueOrderId>,
227 start: Option<DateTime<Utc>>,
228 end: Option<DateTime<Utc>>,
229 limit: Option<u32>,
230 ) -> PyResult<Bound<'py, PyAny>> {
231 let client = self.clone();
232
233 pyo3_async_runtimes::tokio::future_into_py(py, async move {
234 let reports = client
235 .request_fill_reports(account_id, instrument_id, venue_order_id, start, end, limit)
236 .await
237 .map_err(to_pyvalue_err)?;
238 Python::attach(|py| {
239 let py_reports: PyResult<Vec<_>> =
240 reports.into_iter().map(|r| r.into_py_any(py)).collect();
241 let pylist = PyList::new(py, py_reports?)?.into_any().unbind();
242 Ok(pylist)
243 })
244 })
245 }
246
247 #[pyo3(name = "request_bars")]
248 #[pyo3(signature = (
249 bar_type,
250 start=None,
251 end=None,
252 limit=None,
253 ))]
254 fn py_request_bars<'py>(
255 &self,
256 py: Python<'py>,
257 bar_type: BarType,
258 start: Option<DateTime<Utc>>,
259 end: Option<DateTime<Utc>>,
260 limit: Option<u32>,
261 ) -> PyResult<Bound<'py, PyAny>> {
262 let client = self.clone();
263
264 pyo3_async_runtimes::tokio::future_into_py(py, async move {
265 let bars = client
266 .request_bars(bar_type, start, end, limit)
267 .await
268 .map_err(to_pyvalue_err)?;
269 Python::attach(|py| {
270 let py_bars: PyResult<Vec<_>> =
271 bars.into_iter().map(|b| b.into_py_any(py)).collect();
272 let pylist = PyList::new(py, py_bars?)?.into_any().unbind();
273 Ok(pylist)
274 })
275 })
276 }
277
278 #[pyo3(name = "submit_order", signature = (account_id, instrument_id, client_order_id, order_side, order_type, quantity, time_in_force, price=None, trigger_price=None, post_only=false))]
279 #[allow(clippy::too_many_arguments)]
280 fn py_submit_order<'py>(
281 &self,
282 py: Python<'py>,
283 account_id: AccountId,
284 instrument_id: InstrumentId,
285 client_order_id: ClientOrderId,
286 order_side: OrderSide,
287 order_type: OrderType,
288 quantity: Quantity,
289 time_in_force: TimeInForce,
290 price: Option<Price>,
291 trigger_price: Option<Price>,
292 post_only: bool,
293 ) -> PyResult<Bound<'py, PyAny>> {
294 let client = self.clone();
295
296 pyo3_async_runtimes::tokio::future_into_py(py, async move {
297 let report = client
298 .submit_order(
299 account_id,
300 instrument_id,
301 client_order_id,
302 order_side,
303 order_type,
304 quantity,
305 time_in_force,
306 price,
307 trigger_price,
308 post_only,
309 )
310 .await
311 .map_err(to_pyvalue_err)?;
312 Python::attach(|py| report.into_py_any(py))
313 })
314 }
315
316 #[pyo3(name = "modify_order", signature = (account_id, instrument_id, venue_order_id, client_order_id, order_side, order_type, quantity, time_in_force, price=None))]
317 #[allow(clippy::too_many_arguments)]
318 fn py_modify_order<'py>(
319 &self,
320 py: Python<'py>,
321 account_id: AccountId,
322 instrument_id: InstrumentId,
323 venue_order_id: VenueOrderId,
324 client_order_id: ClientOrderId,
325 order_side: OrderSide,
326 order_type: OrderType,
327 quantity: Quantity,
328 time_in_force: TimeInForce,
329 price: Option<Price>,
330 ) -> PyResult<Bound<'py, PyAny>> {
331 let client = self.clone();
332
333 pyo3_async_runtimes::tokio::future_into_py(py, async move {
334 let report = client
335 .modify_order(
336 account_id,
337 instrument_id,
338 venue_order_id,
339 client_order_id,
340 order_side,
341 order_type,
342 quantity,
343 time_in_force,
344 price,
345 )
346 .await
347 .map_err(to_pyvalue_err)?;
348 Python::attach(|py| report.into_py_any(py))
349 })
350 }
351
352 #[pyo3(name = "cancel_order")]
353 #[pyo3(signature = (
354 instrument_id,
355 venue_order_id=None,
356 client_order_id=None,
357 ))]
358 fn py_cancel_order<'py>(
359 &self,
360 py: Python<'py>,
361 instrument_id: InstrumentId,
362 venue_order_id: Option<VenueOrderId>,
363 client_order_id: Option<ClientOrderId>,
364 ) -> PyResult<Bound<'py, PyAny>> {
365 let client = self.clone();
366
367 pyo3_async_runtimes::tokio::future_into_py(py, async move {
368 let order_id = client
369 .cancel_order(instrument_id, venue_order_id, client_order_id)
370 .await
371 .map_err(to_pyvalue_err)?;
372 Python::attach(|py| order_id.into_py_any(py))
373 })
374 }
375
376 #[pyo3(name = "cancel_all_orders")]
377 fn py_cancel_all_orders<'py>(
378 &self,
379 py: Python<'py>,
380 instrument_id: InstrumentId,
381 ) -> PyResult<Bound<'py, PyAny>> {
382 let client = self.clone();
383
384 pyo3_async_runtimes::tokio::future_into_py(py, async move {
385 let order_ids = client
386 .cancel_all_orders(instrument_id)
387 .await
388 .map_err(to_pyvalue_err)?;
389 Python::attach(|py| {
390 let py_ids: PyResult<Vec<_>> =
391 order_ids.into_iter().map(|id| id.into_py_any(py)).collect();
392 let pylist = PyList::new(py, py_ids?)?.into_any().unbind();
393 Ok(pylist)
394 })
395 })
396 }
397}