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