diff --git a/docs/exchanges.md b/docs/exchanges.md index 358242fe9..9c8f3b426 100644 --- a/docs/exchanges.md +++ b/docs/exchanges.md @@ -428,6 +428,36 @@ Your balance and trades will now be used from your vault / subaccount - and no l The Hyperliquid API does not provide historic data beyond the single call to fetch current data, so downloading data is not possible, as the downloaded data would not constitute proper historic data. +### HIP-3 DEXes + +Hyperliquid supports HIP-3 decentralized exchanges (DEXes), which are independent exchanges built on the Hyperliquid infrastructure. These DEXes operate similarly to the main Hyperliquid exchange but are community-created and managed. + +To trade on HIP-3 DEXes with Freqtrade, you need to add them to your configuration using the `hip3_dexes` parameter: + +```json +"exchange": { + "name": "hyperliquid", + "walletAddress": "your_master_wallet_address", + "privateKey": "your_api_private_key", + "hip3_dexes": ["dex_name_1", "dex_name_2"] +} +``` + +Replace `"dex_name_1"` and `"dex_name_2"` with the actual names of the HIP-3 DEXes you want to trade on. + +!!! Warning Performance and Rate Limit Impact + +**Each HIP-3 DEX you add significantly impacts bot performance and rate limits:** + +* **Additional API Calls**: For each HIP-3 DEX configured, Freqtrade makes additional Balance and Position API queries. +* **Increased Latency**: Each DEX adds approximately 0.7 seconds of delay due to these calls. +* **Rate Limit Pressure**: Additional API calls contribute to Hyperliquid's strict rate limits. With multiple DEXes, you may hit rate limits faster. + +**Recommendation**: Only add HIP-3 DEXes that you actively trade on. Monitor your logs for rate limit warnings. + +!!! Note + HIP-3 DEXes share the same wallet and free amount of colleteral as your main Hyperliquid account. Trades on different DEXes will affect your overall account balance and margin. + ## Bitvavo If your account is required to use an operatorId, you can set it in the configuration file as follows: diff --git a/freqtrade/exchange/hyperliquid.py b/freqtrade/exchange/hyperliquid.py index 170bc400a..ceb13d92c 100644 --- a/freqtrade/exchange/hyperliquid.py +++ b/freqtrade/exchange/hyperliquid.py @@ -66,16 +66,7 @@ class Hyperliquid(Exchange): super().validate_config(config) configured = self._get_configured_hip3_dexes() - if not configured: - return - - if len(configured) > 2: - raise OperationalException( - f"Maximum 2 HIP-3 DEXes allowed, but {len(configured)} configured: {configured}. " - f"Remove extra DEXes from your 'hip3_dexes' configuration!" - ) - - if not self.markets: + if not configured or not self.markets: return available = { diff --git a/tests/exchange/test_hyperliquid.py b/tests/exchange/test_hyperliquid.py index 8b159537e..c805342dc 100644 --- a/tests/exchange/test_hyperliquid.py +++ b/tests/exchange/test_hyperliquid.py @@ -674,8 +674,6 @@ def test_hyperliquid_hip3_config_validation(default_conf, mocker): markets = { "BTC/USDC:USDC": {"info": {}}, "XYZ-AAPL/USDC:USDC": {"info": {"hip3": True, "dex": "xyz"}}, - "VNTL-SPACEX/USDH:USDH": {"info": {"hip3": True, "dex": "vntl"}}, - "FLX-TOKEN/USDC:USDC": {"info": {"hip3": True, "dex": "flx"}}, } api_mock.load_markets = get_mock_coro(return_value=markets) api_mock.markets = markets @@ -687,22 +685,7 @@ def test_hyperliquid_hip3_config_validation(default_conf, mocker): ) assert exchange._get_configured_hip3_dexes() == ["xyz"] - # Test 2: Valid two DEXes (max allowed) - default_conf["exchange"]["hip3_dexes"] = ["xyz", "vntl"] - exchange = get_patched_exchange( - mocker, default_conf, api_mock, exchange="hyperliquid", mock_markets=False - ) - assert exchange._get_configured_hip3_dexes() == ["xyz", "vntl"] - - # Test 3: Too many DEXes - default_conf["exchange"]["hip3_dexes"] = ["xyz", "vntl", "flx"] - with pytest.raises(OperationalException, match="Maximum 2 HIP-3 DEXes allowed"): - exchange = get_patched_exchange( - mocker, default_conf, api_mock, exchange="hyperliquid", mock_markets=False - ) - exchange.validate_config(default_conf) - - # Test 4: Invalid DEX + # Test 2: Invalid DEX default_conf["exchange"]["hip3_dexes"] = ["invalid_dex"] with pytest.raises(OperationalException, match="Invalid HIP-3 DEXes configured"): exchange = get_patched_exchange( @@ -710,7 +693,7 @@ def test_hyperliquid_hip3_config_validation(default_conf, mocker): ) exchange.validate_config(default_conf) - # Test 5: Mix of valid and invalid DEX + # Test 3: Mix of valid and invalid DEX default_conf["exchange"]["hip3_dexes"] = ["xyz", "invalid_dex"] with pytest.raises(OperationalException, match="Invalid HIP-3 DEXes configured"): exchange = get_patched_exchange( @@ -796,15 +779,21 @@ def test_hyperliquid_fetch_positions_hip3(default_conf, mocker): mocker, default_conf, api_mock, exchange="hyperliquid", mock_markets=False ) + # Mock super().fetch_positions() to return default positions + mocker.patch( + "freqtrade.exchange.exchange.Exchange.fetch_positions", return_value=default_positions + ) + positions = exchange.fetch_positions() - # Should have HIP-3 positions (default position not included in test mock) - assert len(positions) == 2 + # Should have all positions combined (default + HIP-3) + assert len(positions) == 3 + assert any(p["symbol"] == "BTC/USDC:USDC" for p in positions) assert any(p["symbol"] == "XYZ-AAPL/USDC:USDC" for p in positions) assert any(p["symbol"] == "VNTL-SPACEX/USDH:USDH" for p in positions) - # Verify API calls (only HIP-3 DEXes, super() returns empty list in test) - assert api_mock.fetch_positions.call_count == 2 # xyz + vntl + # Verify API calls (xyz + vntl, default is mocked separately) + assert api_mock.fetch_positions.call_count == 2 def test_hyperliquid_market_is_tradable(default_conf, mocker):