1use chrono::{DateTime, Utc};
17use nautilus_core::python::{IntoPyObjectNautilusExt, to_pyvalue_err};
18use nautilus_model::{
19 data::BarType,
20 identifiers::{AccountId, InstrumentId},
21 python::instruments::{instrument_any_to_pyobject, pyobject_to_instrument_any},
22};
23use pyo3::{prelude::*, types::PyList};
24
25use crate::{
26 common::enums::{OKXInstrumentType, OKXPositionMode},
27 http::client::OKXHttpClient,
28};
29
30#[pymethods]
31impl OKXHttpClient {
32 #[new]
33 #[pyo3(signature = (api_key=None, api_secret=None, api_passphrase=None, base_url=None, timeout_secs=None, max_retries=None, retry_delay_ms=None, retry_delay_max_ms=None))]
34 #[allow(clippy::too_many_arguments)]
35 fn py_new(
36 api_key: Option<String>,
37 api_secret: Option<String>,
38 api_passphrase: Option<String>,
39 base_url: Option<String>,
40 timeout_secs: Option<u64>,
41 max_retries: Option<u32>,
42 retry_delay_ms: Option<u64>,
43 retry_delay_max_ms: Option<u64>,
44 ) -> PyResult<Self> {
45 Self::with_credentials(
46 api_key,
47 api_secret,
48 api_passphrase,
49 base_url,
50 timeout_secs,
51 max_retries,
52 retry_delay_ms,
53 retry_delay_max_ms,
54 )
55 .map_err(to_pyvalue_err)
56 }
57
58 #[staticmethod]
59 #[pyo3(name = "from_env")]
60 fn py_from_env() -> PyResult<Self> {
61 Self::from_env().map_err(to_pyvalue_err)
62 }
63
64 #[getter]
65 #[pyo3(name = "base_url")]
66 #[must_use]
67 pub fn py_base_url(&self) -> &str {
68 self.base_url()
69 }
70
71 #[getter]
72 #[pyo3(name = "api_key")]
73 #[must_use]
74 pub fn py_api_key(&self) -> Option<&str> {
75 self.api_key()
76 }
77
78 #[pyo3(name = "is_initialized")]
79 #[must_use]
80 pub const fn py_is_initialized(&self) -> bool {
81 self.is_initialized()
82 }
83
84 #[pyo3(name = "get_cached_symbols")]
85 #[must_use]
86 pub fn py_get_cached_symbols(&self) -> Vec<String> {
87 self.get_cached_symbols()
88 }
89
90 #[pyo3(name = "cancel_all_requests")]
91 pub fn py_cancel_all_requests(&self) {
92 self.cancel_all_requests();
93 }
94
95 #[pyo3(name = "add_instrument")]
99 pub fn py_add_instrument(&mut self, py: Python<'_>, instrument: PyObject) -> PyResult<()> {
100 self.add_instrument(pyobject_to_instrument_any(py, instrument)?);
101 Ok(())
102 }
103
104 #[pyo3(name = "set_position_mode")]
106 fn py_set_position_mode<'py>(
107 &self,
108 py: Python<'py>,
109 position_mode: OKXPositionMode,
110 ) -> PyResult<Bound<'py, PyAny>> {
111 let client = self.clone();
112
113 pyo3_async_runtimes::tokio::future_into_py(py, async move {
114 client
115 .set_position_mode(position_mode)
116 .await
117 .map_err(to_pyvalue_err)?;
118 Ok(Python::with_gil(|py| py.None()))
119 })
120 }
121
122 #[pyo3(name = "request_instruments")]
123 fn py_request_instruments<'py>(
124 &self,
125 py: Python<'py>,
126 instrument_type: OKXInstrumentType,
127 ) -> PyResult<Bound<'py, PyAny>> {
128 let client = self.clone();
129
130 pyo3_async_runtimes::tokio::future_into_py(py, async move {
131 let instruments = client
132 .request_instruments(instrument_type)
133 .await
134 .map_err(to_pyvalue_err)?;
135
136 Python::with_gil(|py| {
137 let py_instruments: PyResult<Vec<_>> = instruments
138 .into_iter()
139 .map(|inst| instrument_any_to_pyobject(py, inst))
140 .collect();
141 let pylist = PyList::new(py, py_instruments?)
142 .unwrap()
143 .into_any()
144 .unbind();
145 Ok(pylist)
146 })
147 })
148 }
149
150 #[pyo3(name = "request_account_state")]
151 fn py_request_account_state<'py>(
152 &self,
153 py: Python<'py>,
154 account_id: AccountId,
155 ) -> PyResult<Bound<'py, PyAny>> {
156 let client = self.clone();
157
158 pyo3_async_runtimes::tokio::future_into_py(py, async move {
159 let account_state = client
160 .request_account_state(account_id)
161 .await
162 .map_err(to_pyvalue_err)?;
163 Ok(Python::with_gil(|py| account_state.into_py_any_unwrap(py)))
164 })
165 }
166
167 #[pyo3(name = "request_trades")]
168 #[pyo3(signature = (instrument_id, start=None, end=None, limit=None))]
169 fn py_request_trades<'py>(
170 &self,
171 py: Python<'py>,
172 instrument_id: InstrumentId,
173 start: Option<DateTime<Utc>>,
174 end: Option<DateTime<Utc>>,
175 limit: Option<u32>,
176 ) -> PyResult<Bound<'py, PyAny>> {
177 let client = self.clone();
178
179 pyo3_async_runtimes::tokio::future_into_py(py, async move {
180 let trades = client
181 .request_trades(instrument_id, start, end, limit)
182 .await
183 .map_err(to_pyvalue_err)?;
184 Python::with_gil(|py| {
185 let pylist = PyList::new(py, trades.into_iter().map(|t| t.into_py_any_unwrap(py)))?;
186 Ok(pylist.into_py_any_unwrap(py))
187 })
188 })
189 }
190
191 #[pyo3(name = "request_bars")]
192 #[pyo3(signature = (bar_type, start=None, end=None, limit=None))]
193 fn py_request_bars<'py>(
194 &self,
195 py: Python<'py>,
196 bar_type: BarType,
197 start: Option<DateTime<Utc>>,
198 end: Option<DateTime<Utc>>,
199 limit: Option<u32>,
200 ) -> PyResult<Bound<'py, PyAny>> {
201 let client = self.clone();
202
203 pyo3_async_runtimes::tokio::future_into_py(py, async move {
204 let bars = client
205 .request_bars(bar_type, start, end, limit)
206 .await
207 .map_err(to_pyvalue_err)?;
208 Python::with_gil(|py| {
209 let pylist =
210 PyList::new(py, bars.into_iter().map(|bar| bar.into_py_any_unwrap(py)))?;
211 Ok(pylist.into_py_any_unwrap(py))
212 })
213 })
214 }
215
216 #[pyo3(name = "request_mark_price")]
217 fn py_request_mark_price<'py>(
218 &self,
219 py: Python<'py>,
220 instrument_id: InstrumentId,
221 ) -> PyResult<Bound<'py, PyAny>> {
222 let client = self.clone();
223
224 pyo3_async_runtimes::tokio::future_into_py(py, async move {
225 let mark_price = client
226 .request_mark_price(instrument_id)
227 .await
228 .map_err(to_pyvalue_err)?;
229 Ok(Python::with_gil(|py| mark_price.into_py_any_unwrap(py)))
230 })
231 }
232
233 #[pyo3(name = "request_index_price")]
234 fn py_request_index_price<'py>(
235 &self,
236 py: Python<'py>,
237 instrument_id: InstrumentId,
238 ) -> PyResult<Bound<'py, PyAny>> {
239 let client = self.clone();
240
241 pyo3_async_runtimes::tokio::future_into_py(py, async move {
242 let index_price = client
243 .request_index_price(instrument_id)
244 .await
245 .map_err(to_pyvalue_err)?;
246 Ok(Python::with_gil(|py| index_price.into_py_any_unwrap(py)))
247 })
248 }
249
250 #[pyo3(name = "request_order_status_reports")]
251 #[pyo3(signature = (account_id, instrument_type=None, instrument_id=None, start=None, end=None, open_only=false, limit=None))]
252 #[allow(clippy::too_many_arguments)]
253 fn py_request_order_status_reports<'py>(
254 &self,
255 py: Python<'py>,
256 account_id: AccountId,
257 instrument_type: Option<OKXInstrumentType>,
258 instrument_id: Option<InstrumentId>,
259 start: Option<DateTime<Utc>>,
260 end: Option<DateTime<Utc>>,
261 open_only: bool,
262 limit: Option<u32>,
263 ) -> PyResult<Bound<'py, PyAny>> {
264 let client = self.clone();
265
266 pyo3_async_runtimes::tokio::future_into_py(py, async move {
267 let reports = client
268 .request_order_status_reports(
269 account_id,
270 instrument_type,
271 instrument_id,
272 start,
273 end,
274 open_only,
275 limit,
276 )
277 .await
278 .map_err(to_pyvalue_err)?;
279 Python::with_gil(|py| {
280 let pylist =
281 PyList::new(py, reports.into_iter().map(|t| t.into_py_any_unwrap(py)))?;
282 Ok(pylist.into_py_any_unwrap(py))
283 })
284 })
285 }
286
287 #[pyo3(name = "request_fill_reports")]
288 #[pyo3(signature = (account_id, instrument_type=None, instrument_id=None, start=None, end=None, limit=None))]
289 #[allow(clippy::too_many_arguments)]
290 fn py_request_fill_reports<'py>(
291 &self,
292 py: Python<'py>,
293 account_id: AccountId,
294 instrument_type: Option<OKXInstrumentType>,
295 instrument_id: Option<InstrumentId>,
296 start: Option<DateTime<Utc>>,
297 end: Option<DateTime<Utc>>,
298 limit: Option<u32>,
299 ) -> PyResult<Bound<'py, PyAny>> {
300 let client = self.clone();
301
302 pyo3_async_runtimes::tokio::future_into_py(py, async move {
303 let trades = client
304 .request_fill_reports(
305 account_id,
306 instrument_type,
307 instrument_id,
308 start,
309 end,
310 limit,
311 )
312 .await
313 .map_err(to_pyvalue_err)?;
314 Python::with_gil(|py| {
315 let pylist = PyList::new(py, trades.into_iter().map(|t| t.into_py_any_unwrap(py)))?;
316 Ok(pylist.into_py_any_unwrap(py))
317 })
318 })
319 }
320
321 #[pyo3(name = "request_position_status_reports")]
322 #[pyo3(signature = (account_id, instrument_type=None, instrument_id=None))]
323 fn py_request_position_status_reports<'py>(
324 &self,
325 py: Python<'py>,
326 account_id: AccountId,
327 instrument_type: Option<OKXInstrumentType>,
328 instrument_id: Option<InstrumentId>,
329 ) -> PyResult<Bound<'py, PyAny>> {
330 let client = self.clone();
331
332 pyo3_async_runtimes::tokio::future_into_py(py, async move {
333 let reports = client
334 .request_position_status_reports(account_id, instrument_type, instrument_id)
335 .await
336 .map_err(to_pyvalue_err)?;
337 Python::with_gil(|py| {
338 let pylist =
339 PyList::new(py, reports.into_iter().map(|t| t.into_py_any_unwrap(py)))?;
340 Ok(pylist.into_py_any_unwrap(py))
341 })
342 })
343 }
344}