Skip to main content

nautilus_hyperliquid/common/
consts.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16use std::{sync::LazyLock, time::Duration};
17
18use nautilus_model::{enums::OrderType, identifiers::Venue};
19use ustr::Ustr;
20
21use super::enums::HyperliquidEnvironment;
22
23pub const HYPERLIQUID: &str = "HYPERLIQUID";
24pub static HYPERLIQUID_VENUE: LazyLock<Venue> =
25    LazyLock::new(|| Venue::new(Ustr::from(HYPERLIQUID)));
26
27pub const HYPERLIQUID_WS_URL: &str = "wss://api.hyperliquid.xyz/ws";
28pub const HYPERLIQUID_INFO_URL: &str = "https://api.hyperliquid.xyz/info";
29pub const HYPERLIQUID_EXCHANGE_URL: &str = "https://api.hyperliquid.xyz/exchange";
30
31pub const HYPERLIQUID_TESTNET_WS_URL: &str = "wss://api.hyperliquid-testnet.xyz/ws";
32pub const HYPERLIQUID_TESTNET_INFO_URL: &str = "https://api.hyperliquid-testnet.xyz/info";
33pub const HYPERLIQUID_TESTNET_EXCHANGE_URL: &str = "https://api.hyperliquid-testnet.xyz/exchange";
34
35// Builder code address for order attribution (zero-fee)
36// Address MUST be lowercase for msgpack serialization
37pub const NAUTILUS_BUILDER_ADDRESS: &str = "0x0c8d970c462726e014ad36f6c5a63e99db48a8e7";
38
39/// Hyperliquid signing chain ID (0x66eee = 421614 decimal).
40pub const HYPERLIQUID_CHAIN_ID: u64 = 421614;
41
42// Error message substrings for detecting specific rejection reasons
43pub const HYPERLIQUID_POST_ONLY_WOULD_MATCH: &str =
44    "Post only order would have immediately matched";
45
46/// Hyperliquid supported order types.
47///
48/// # Notes
49///
50/// - All order types support trigger prices except Market and Limit.
51/// - Conditional orders follow patterns from OKX, Bybit, and BitMEX adapters.
52/// - Stop orders (StopMarket/StopLimit) are protective stops (sl).
53/// - If Touched orders (MarketIfTouched/LimitIfTouched) are profit-taking or entry orders (tp).
54/// - Post-only orders are implemented via ALO (Add Liquidity Only) time-in-force.
55///
56/// Trailing stops (TrailingStopMarket/TrailingStopLimit) are supported by the exchange
57/// and can be parsed from incoming WS messages, but the outgoing request model does not
58/// yet serialize the trailing offset parameters. Add them once HyperliquidExecTriggerParams
59/// is extended with trailing offset fields.
60pub const HYPERLIQUID_SUPPORTED_ORDER_TYPES: &[OrderType] = &[
61    OrderType::Market,          // IOC limit order
62    OrderType::Limit,           // Standard limit with GTC/IOC/ALO
63    OrderType::StopMarket,      // Protective stop with market execution
64    OrderType::StopLimit,       // Protective stop with limit price
65    OrderType::MarketIfTouched, // Profit-taking/entry with market execution
66    OrderType::LimitIfTouched,  // Profit-taking/entry with limit price
67];
68
69/// Conditional order types that use trigger orders on Hyperliquid.
70///
71/// These order types require a trigger_price and are implemented using
72/// HyperliquidExecOrderKind::Trigger with appropriate parameters.
73pub const HYPERLIQUID_CONDITIONAL_ORDER_TYPES: &[OrderType] = &[
74    OrderType::StopMarket,
75    OrderType::StopLimit,
76    OrderType::MarketIfTouched,
77    OrderType::LimitIfTouched,
78];
79
80/// Gets WebSocket URL for the specified environment.
81pub fn ws_url(environment: HyperliquidEnvironment) -> &'static str {
82    match environment {
83        HyperliquidEnvironment::Testnet => HYPERLIQUID_TESTNET_WS_URL,
84        HyperliquidEnvironment::Mainnet => HYPERLIQUID_WS_URL,
85    }
86}
87
88/// Gets info API URL for the specified environment.
89pub fn info_url(environment: HyperliquidEnvironment) -> &'static str {
90    match environment {
91        HyperliquidEnvironment::Testnet => HYPERLIQUID_TESTNET_INFO_URL,
92        HyperliquidEnvironment::Mainnet => HYPERLIQUID_INFO_URL,
93    }
94}
95
96/// Gets exchange API URL for the specified environment.
97pub fn exchange_url(environment: HyperliquidEnvironment) -> &'static str {
98    match environment {
99        HyperliquidEnvironment::Testnet => HYPERLIQUID_TESTNET_EXCHANGE_URL,
100        HyperliquidEnvironment::Mainnet => HYPERLIQUID_EXCHANGE_URL,
101    }
102}
103
104// Default configuration values
105// Server closes if no message in last 60s, so ping every 30s
106pub const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(30);
107pub const RECONNECT_BASE_BACKOFF: Duration = Duration::from_millis(250);
108pub const RECONNECT_MAX_BACKOFF: Duration = Duration::from_secs(30);
109pub const HTTP_TIMEOUT: Duration = Duration::from_secs(10);
110// Max 100 inflight WS post messages per Hyperliquid docs
111pub const INFLIGHT_MAX: usize = 100;
112pub const QUEUE_MAX: usize = 1000;
113
114#[cfg(test)]
115mod tests {
116    use rstest::rstest;
117
118    use super::*;
119
120    #[rstest]
121    fn test_ws_url() {
122        assert_eq!(ws_url(HyperliquidEnvironment::Mainnet), HYPERLIQUID_WS_URL);
123        assert_eq!(
124            ws_url(HyperliquidEnvironment::Testnet),
125            HYPERLIQUID_TESTNET_WS_URL
126        );
127    }
128
129    #[rstest]
130    fn test_info_url() {
131        assert_eq!(
132            info_url(HyperliquidEnvironment::Mainnet),
133            HYPERLIQUID_INFO_URL
134        );
135        assert_eq!(
136            info_url(HyperliquidEnvironment::Testnet),
137            HYPERLIQUID_TESTNET_INFO_URL
138        );
139    }
140
141    #[rstest]
142    fn test_exchange_url() {
143        assert_eq!(
144            exchange_url(HyperliquidEnvironment::Mainnet),
145            HYPERLIQUID_EXCHANGE_URL
146        );
147        assert_eq!(
148            exchange_url(HyperliquidEnvironment::Testnet),
149            HYPERLIQUID_TESTNET_EXCHANGE_URL
150        );
151    }
152
153    #[rstest]
154    fn test_constants_values() {
155        assert_eq!(HEARTBEAT_INTERVAL, Duration::from_secs(30));
156        assert_eq!(RECONNECT_BASE_BACKOFF, Duration::from_millis(250));
157        assert_eq!(RECONNECT_MAX_BACKOFF, Duration::from_secs(30));
158        assert_eq!(HTTP_TIMEOUT, Duration::from_secs(10));
159        assert_eq!(INFLIGHT_MAX, 100);
160        assert_eq!(QUEUE_MAX, 1000);
161    }
162}