nautilus_hyperliquid/python/
mod.rs1#![expect(
19 clippy::missing_errors_doc,
20 reason = "errors documented on underlying Rust methods"
21)]
22
23pub mod config;
24pub mod enums;
25pub mod factories;
26pub mod http;
27pub mod urls;
28pub mod websocket;
29
30use nautilus_common::factories::{ClientConfig, DataClientFactory, ExecutionClientFactory};
31use nautilus_core::python::{to_pyruntime_err, to_pyvalue_err};
32use nautilus_model::{data::ensure_rust_extractor_registered, identifiers::ClientOrderId};
33use nautilus_system::get_global_pyo3_registry;
34use pyo3::prelude::*;
35
36use crate::{
37 account::resolve_execution_account_address,
38 common::{
39 consts::{HYPERLIQUID, HYPERLIQUID_POST_ONLY_WOULD_MATCH},
40 enums::{
41 HyperliquidConditionalOrderType, HyperliquidEnvironment, HyperliquidProductType,
42 HyperliquidTpSl, HyperliquidTrailingOffsetType,
43 },
44 },
45 config::{HyperliquidDataClientConfig, HyperliquidExecClientConfig},
46 data_types::{
47 HyperliquidAllDexsAssetCtxs, HyperliquidAllMids, HyperliquidOpenInterest,
48 register_hyperliquid_custom_data,
49 },
50 factories::{
51 HyperliquidDataClientFactory, HyperliquidExecFactoryConfig,
52 HyperliquidExecutionClientFactory,
53 },
54 http::{HyperliquidHttpClient, models::Cloid},
55 websocket::HyperliquidWebSocketClient,
56};
57
58#[pyfunction]
63#[pyo3_stub_gen::derive::gen_stub_pyfunction(module = "nautilus_trader.adapters.hyperliquid")]
64#[pyo3(name = "hyperliquid_cloid_from_client_order_id")]
65fn py_hyperliquid_cloid_from_client_order_id(client_order_id: ClientOrderId) -> String {
66 Cloid::from_client_order_id(client_order_id).to_hex()
67}
68
69#[pyfunction]
75#[pyo3_stub_gen::derive::gen_stub_pyfunction(module = "nautilus_trader.adapters.hyperliquid")]
76#[pyo3(name = "hyperliquid_product_type_from_symbol")]
77fn py_hyperliquid_product_type_from_symbol(symbol: &str) -> PyResult<HyperliquidProductType> {
78 HyperliquidProductType::from_symbol(symbol).map_err(to_pyvalue_err)
79}
80
81#[pyfunction]
87#[pyo3_stub_gen::derive::gen_stub_pyfunction(module = "nautilus_trader.adapters.hyperliquid")]
88#[pyo3(name = "hyperliquid_resolve_execution_account_address", signature = (private_key=None, vault_address=None, account_address=None, environment=HyperliquidEnvironment::Mainnet))]
89fn py_hyperliquid_resolve_execution_account_address(
90 private_key: Option<&str>,
91 vault_address: Option<&str>,
92 account_address: Option<&str>,
93 environment: HyperliquidEnvironment,
94) -> PyResult<Option<String>> {
95 resolve_execution_account_address(private_key, vault_address, account_address, environment)
96 .map_err(to_pyvalue_err)
97}
98
99#[expect(clippy::needless_pass_by_value)]
100fn extract_hyperliquid_data_factory(
101 py: Python<'_>,
102 factory: Py<PyAny>,
103) -> PyResult<Box<dyn DataClientFactory>> {
104 match factory.extract::<HyperliquidDataClientFactory>(py) {
105 Ok(f) => Ok(Box::new(f)),
106 Err(e) => Err(to_pyvalue_err(format!(
107 "Failed to extract HyperliquidDataClientFactory: {e}"
108 ))),
109 }
110}
111
112#[expect(clippy::needless_pass_by_value)]
113fn extract_hyperliquid_exec_factory(
114 py: Python<'_>,
115 factory: Py<PyAny>,
116) -> PyResult<Box<dyn ExecutionClientFactory>> {
117 match factory.extract::<HyperliquidExecutionClientFactory>(py) {
118 Ok(f) => Ok(Box::new(f)),
119 Err(e) => Err(to_pyvalue_err(format!(
120 "Failed to extract HyperliquidExecutionClientFactory: {e}"
121 ))),
122 }
123}
124
125#[expect(clippy::needless_pass_by_value)]
126fn extract_hyperliquid_data_config(
127 py: Python<'_>,
128 config: Py<PyAny>,
129) -> PyResult<Box<dyn ClientConfig>> {
130 match config.extract::<HyperliquidDataClientConfig>(py) {
131 Ok(c) => Ok(Box::new(c)),
132 Err(e) => Err(to_pyvalue_err(format!(
133 "Failed to extract HyperliquidDataClientConfig: {e}"
134 ))),
135 }
136}
137
138#[expect(clippy::needless_pass_by_value)]
139fn extract_hyperliquid_exec_config(
140 py: Python<'_>,
141 config: Py<PyAny>,
142) -> PyResult<Box<dyn ClientConfig>> {
143 match config.extract::<HyperliquidExecFactoryConfig>(py) {
144 Ok(c) => Ok(Box::new(c)),
145 Err(e) => Err(to_pyvalue_err(format!(
146 "Failed to extract HyperliquidExecFactoryConfig: {e}"
147 ))),
148 }
149}
150
151#[pymodule]
153pub fn hyperliquid(m: &Bound<'_, PyModule>) -> PyResult<()> {
154 m.add(
155 "HYPERLIQUID_POST_ONLY_WOULD_MATCH",
156 HYPERLIQUID_POST_ONLY_WOULD_MATCH,
157 )?;
158 m.add_class::<HyperliquidHttpClient>()?;
159 m.add_class::<HyperliquidWebSocketClient>()?;
160 m.add_class::<HyperliquidProductType>()?;
161 m.add_class::<HyperliquidTpSl>()?;
162 m.add_class::<HyperliquidConditionalOrderType>()?;
163 m.add_class::<HyperliquidTrailingOffsetType>()?;
164 m.add_class::<HyperliquidEnvironment>()?;
165 m.add_function(wrap_pyfunction!(urls::py_get_hyperliquid_http_base_url, m)?)?;
166 m.add_function(wrap_pyfunction!(urls::py_get_hyperliquid_ws_url, m)?)?;
167 m.add_function(wrap_pyfunction!(
168 py_hyperliquid_product_type_from_symbol,
169 m
170 )?)?;
171 m.add_function(wrap_pyfunction!(
172 py_hyperliquid_cloid_from_client_order_id,
173 m
174 )?)?;
175 m.add_function(wrap_pyfunction!(
176 py_hyperliquid_resolve_execution_account_address,
177 m
178 )?)?;
179 m.add_class::<HyperliquidDataClientConfig>()?;
180 m.add_class::<HyperliquidExecClientConfig>()?;
181 m.add_class::<HyperliquidExecFactoryConfig>()?;
182 m.add_class::<HyperliquidDataClientFactory>()?;
183 m.add_class::<HyperliquidExecutionClientFactory>()?;
184 m.add_class::<HyperliquidAllDexsAssetCtxs>()?;
185 m.add_class::<HyperliquidAllMids>()?;
186 m.add_class::<HyperliquidOpenInterest>()?;
187
188 register_hyperliquid_custom_data();
189 let _result = ensure_rust_extractor_registered::<HyperliquidAllDexsAssetCtxs>();
190 let _result = ensure_rust_extractor_registered::<HyperliquidAllMids>();
191 let _result = ensure_rust_extractor_registered::<HyperliquidOpenInterest>();
192
193 let registry = get_global_pyo3_registry();
194
195 if let Err(e) = registry
196 .register_factory_extractor(HYPERLIQUID.to_string(), extract_hyperliquid_data_factory)
197 {
198 return Err(to_pyruntime_err(format!(
199 "Failed to register Hyperliquid data factory extractor: {e}"
200 )));
201 }
202
203 if let Err(e) = registry
204 .register_exec_factory_extractor(HYPERLIQUID.to_string(), extract_hyperliquid_exec_factory)
205 {
206 return Err(to_pyruntime_err(format!(
207 "Failed to register Hyperliquid exec factory extractor: {e}"
208 )));
209 }
210
211 if let Err(e) = registry.register_config_extractor(
212 "HyperliquidDataClientConfig".to_string(),
213 extract_hyperliquid_data_config,
214 ) {
215 return Err(to_pyruntime_err(format!(
216 "Failed to register Hyperliquid data config extractor: {e}"
217 )));
218 }
219
220 if let Err(e) = registry.register_config_extractor(
221 "HyperliquidExecFactoryConfig".to_string(),
222 extract_hyperliquid_exec_config,
223 ) {
224 return Err(to_pyruntime_err(format!(
225 "Failed to register Hyperliquid exec config extractor: {e}"
226 )));
227 }
228
229 Ok(())
230}