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