nautilus_hyperliquid/python/
http.rs1use nautilus_core::python::{IntoPyObjectNautilusExt, to_pyvalue_err};
17use nautilus_model::{
18 instruments::{Instrument, InstrumentAny},
19 python::{
20 instruments::{instrument_any_to_pyobject, pyobject_to_instrument_any},
21 orders::pyobject_to_order_any,
22 },
23};
24use pyo3::{prelude::*, types::PyList};
25use serde_json::to_string;
26
27use crate::http::client::HyperliquidHttpClient;
28
29#[pymethods]
30impl HyperliquidHttpClient {
31 #[new]
32 #[pyo3(signature = (is_testnet=false, timeout_secs=None))]
33 fn py_new(is_testnet: bool, timeout_secs: Option<u64>) -> Self {
34 Self::new(is_testnet, timeout_secs)
35 }
36
37 #[staticmethod]
45 #[pyo3(name = "from_env")]
46 fn py_from_env() -> PyResult<Self> {
47 Self::from_env().map_err(to_pyvalue_err)
48 }
49
50 #[pyo3(name = "get_perp_meta")]
52 fn py_get_perp_meta<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
53 let client = self.clone();
54 pyo3_async_runtimes::tokio::future_into_py(py, async move {
55 let meta = client.load_perp_meta().await.map_err(to_pyvalue_err)?;
56 to_string(&meta).map_err(to_pyvalue_err)
57 })
58 }
59
60 #[pyo3(name = "get_spot_meta")]
62 fn py_get_spot_meta<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
63 let client = self.clone();
64 pyo3_async_runtimes::tokio::future_into_py(py, async move {
65 let meta = client.get_spot_meta().await.map_err(to_pyvalue_err)?;
66 to_string(&meta).map_err(to_pyvalue_err)
67 })
68 }
69
70 #[pyo3(name = "load_instrument_definitions", signature = (include_perp=true, include_spot=true))]
72 fn py_load_instrument_definitions<'py>(
73 &self,
74 py: Python<'py>,
75 include_perp: bool,
76 include_spot: bool,
77 ) -> PyResult<Bound<'py, PyAny>> {
78 let client = self.clone();
79
80 pyo3_async_runtimes::tokio::future_into_py(py, async move {
81 let mut instruments = client.request_instruments().await.map_err(to_pyvalue_err)?;
82
83 if !include_perp || !include_spot {
84 instruments.retain(|instrument| match instrument {
85 InstrumentAny::CryptoPerpetual(_) => include_perp,
86 InstrumentAny::CurrencyPair(_) => include_spot,
87 _ => true,
88 });
89 }
90
91 instruments.sort_by_key(|instrument| instrument.id());
92
93 Python::attach(|py| {
94 let mut py_instruments = Vec::with_capacity(instruments.len());
95 for instrument in instruments {
96 py_instruments.push(instrument_any_to_pyobject(py, instrument)?);
97 }
98
99 let py_list = PyList::new(py, &py_instruments)?;
100 Ok(py_list.into_any().unbind())
101 })
102 })
103 }
104
105 #[pyo3(name = "submit_order")]
112 fn py_submit_order<'py>(
113 &self,
114 py: Python<'py>,
115 order: Py<PyAny>,
116 ) -> PyResult<Bound<'py, PyAny>> {
117 let client = self.clone();
118
119 pyo3_async_runtimes::tokio::future_into_py(py, async move {
120 let order_any =
122 Python::attach(|py| pyobject_to_order_any(py, order).map_err(to_pyvalue_err))?;
123
124 let report = client
125 .submit_order(&order_any)
126 .await
127 .map_err(to_pyvalue_err)?;
128
129 Python::attach(|py| Ok(report.into_py_any_unwrap(py)))
130 })
131 }
132
133 #[pyo3(name = "submit_orders")]
140 fn py_submit_orders<'py>(
141 &self,
142 py: Python<'py>,
143 orders: Vec<Py<PyAny>>,
144 ) -> PyResult<Bound<'py, PyAny>> {
145 let client = self.clone();
146
147 pyo3_async_runtimes::tokio::future_into_py(py, async move {
148 let order_anys: Vec<nautilus_model::orders::any::OrderAny> = Python::attach(|py| {
150 orders
151 .into_iter()
152 .map(|order| pyobject_to_order_any(py, order))
153 .collect::<PyResult<Vec<_>>>()
154 .map_err(to_pyvalue_err)
155 })?;
156
157 let order_refs: Vec<&nautilus_model::orders::any::OrderAny> =
159 order_anys.iter().collect();
160
161 let reports = client
162 .submit_orders(&order_refs)
163 .await
164 .map_err(to_pyvalue_err)?;
165
166 Python::attach(|py| {
167 let pylist =
168 PyList::new(py, reports.into_iter().map(|r| r.into_py_any_unwrap(py)))?;
169 Ok(pylist.into_py_any_unwrap(py))
170 })
171 })
172 }
173
174 #[pyo3(name = "get_open_orders")]
178 fn py_get_open_orders<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
179 let client = self.clone();
180
181 pyo3_async_runtimes::tokio::future_into_py(py, async move {
182 let user_address = client.get_user_address().map_err(to_pyvalue_err)?;
183 let response = client
184 .info_open_orders(&user_address)
185 .await
186 .map_err(to_pyvalue_err)?;
187 to_string(&response).map_err(to_pyvalue_err)
188 })
189 }
190
191 #[pyo3(name = "get_clearinghouse_state")]
195 fn py_get_clearinghouse_state<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
196 let client = self.clone();
197
198 pyo3_async_runtimes::tokio::future_into_py(py, async move {
199 let user_address = client.get_user_address().map_err(to_pyvalue_err)?;
200 let response = client
201 .info_clearinghouse_state(&user_address)
202 .await
203 .map_err(to_pyvalue_err)?;
204 to_string(&response).map_err(to_pyvalue_err)
205 })
206 }
207
208 #[pyo3(name = "add_instrument")]
212 fn py_add_instrument(&self, py: Python<'_>, instrument: Py<PyAny>) -> PyResult<()> {
213 self.add_instrument(pyobject_to_instrument_any(py, instrument)?);
214 Ok(())
215 }
216
217 #[pyo3(name = "set_account_id")]
221 fn py_set_account_id(&mut self, account_id: &str) -> PyResult<()> {
222 let account_id = nautilus_model::identifiers::AccountId::from(account_id);
223 self.set_account_id(account_id);
224 Ok(())
225 }
226
227 #[pyo3(name = "request_order_status_reports")]
231 fn py_request_order_status_reports<'py>(
232 &self,
233 py: Python<'py>,
234 instrument_id: Option<&str>,
235 ) -> PyResult<Bound<'py, PyAny>> {
236 let client = self.clone();
237 let instrument_id = instrument_id.map(nautilus_model::identifiers::InstrumentId::from);
238
239 pyo3_async_runtimes::tokio::future_into_py(py, async move {
240 let user_address = client.get_user_address().map_err(to_pyvalue_err)?;
241 let reports = client
242 .request_order_status_reports(&user_address, instrument_id)
243 .await
244 .map_err(to_pyvalue_err)?;
245
246 Python::attach(|py| {
247 let pylist =
248 PyList::new(py, reports.into_iter().map(|r| r.into_py_any_unwrap(py)))?;
249 Ok(pylist.into_py_any_unwrap(py))
250 })
251 })
252 }
253
254 #[pyo3(name = "request_fill_reports")]
258 fn py_request_fill_reports<'py>(
259 &self,
260 py: Python<'py>,
261 instrument_id: Option<&str>,
262 ) -> PyResult<Bound<'py, PyAny>> {
263 let client = self.clone();
264 let instrument_id = instrument_id.map(nautilus_model::identifiers::InstrumentId::from);
265
266 pyo3_async_runtimes::tokio::future_into_py(py, async move {
267 let user_address = client.get_user_address().map_err(to_pyvalue_err)?;
268 let reports = client
269 .request_fill_reports(&user_address, instrument_id)
270 .await
271 .map_err(to_pyvalue_err)?;
272
273 Python::attach(|py| {
274 let pylist =
275 PyList::new(py, reports.into_iter().map(|r| r.into_py_any_unwrap(py)))?;
276 Ok(pylist.into_py_any_unwrap(py))
277 })
278 })
279 }
280
281 #[pyo3(name = "request_position_status_reports")]
285 fn py_request_position_status_reports<'py>(
286 &self,
287 py: Python<'py>,
288 instrument_id: Option<&str>,
289 ) -> PyResult<Bound<'py, PyAny>> {
290 let client = self.clone();
291 let instrument_id = instrument_id.map(nautilus_model::identifiers::InstrumentId::from);
292
293 pyo3_async_runtimes::tokio::future_into_py(py, async move {
294 let user_address = client.get_user_address().map_err(to_pyvalue_err)?;
295 let reports = client
296 .request_position_status_reports(&user_address, instrument_id)
297 .await
298 .map_err(to_pyvalue_err)?;
299
300 Python::attach(|py| {
301 let pylist =
302 PyList::new(py, reports.into_iter().map(|r| r.into_py_any_unwrap(py)))?;
303 Ok(pylist.into_py_any_unwrap(py))
304 })
305 })
306 }
307}