feat: support hyperliquid unified account

This commit is contained in:
Matthias
2026-03-08 15:15:46 +01:00
parent b57a7f207e
commit 71f03ffbc6
+46 -2
View File
@@ -5,11 +5,20 @@ from copy import deepcopy
from datetime import datetime
from typing import Any
import ccxt
from freqtrade.constants import BuySell
from freqtrade.enums import MarginMode, TradingMode
from freqtrade.enums.runmode import NON_UTIL_MODES
from freqtrade.exceptions import ConfigurationError, ExchangeError, OperationalException
from freqtrade.exceptions import (
ConfigurationError,
DDosProtection,
ExchangeError,
OperationalException,
TemporaryError,
)
from freqtrade.exchange import Exchange
from freqtrade.exchange.common import retrier
from freqtrade.exchange.exchange_types import CcxtBalances, CcxtOrder, CcxtPosition, FtHas
from freqtrade.util.datetime_helpers import dt_from_ts
@@ -22,6 +31,8 @@ class Hyperliquid(Exchange):
Contains adjustments needed for Freqtrade to work with this exchange.
"""
unified_account = False
_ft_has: FtHas = {
"ohlcv_has_history": False,
"l2_limit_range": [20],
@@ -58,6 +69,36 @@ class Hyperliquid(Exchange):
config.update(super()._ccxt_config)
return config
@retrier
def additional_exchange_init(self) -> None:
"""
Additional exchange initialization logic.
.api will be available at this point.
Query User account Account Type to determine unified account status
https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#query-a-users-abstraction-state
"""
try:
if self.trading_mode == TradingMode.FUTURES and not self._config["dry_run"]:
# Determine account status
# Unified accounts must use the spot endpoint for balances
request = {
"type": "userAbstraction",
"user": self._api.walletAddress,
}
response = self._api.publicPostInfo(request)
self.unified_account = response in ('"unifiedAccount"', '"portfolioMargin"')
except ccxt.DDoSProtection as e:
raise DDosProtection(e) from e
except (ccxt.OperationFailed, ccxt.ExchangeError) as e:
raise TemporaryError(
f"Error in additional_exchange_init due to {e.__class__.__name__}. Message: {e}"
) from e
except ccxt.BaseError as e:
raise OperationalException(e) from e
def _get_configured_hip3_dexes(self) -> list[str]:
"""Get list of configured HIP-3 DEXes."""
return self._config.get("exchange", {}).get("hip3_dexes", [])
@@ -122,7 +163,10 @@ class Hyperliquid(Exchange):
This override is not absolutely necessary and is only there for correct used / total values
which are however not used by Freqtrade in futures mode at the moment.
"""
balances = super().get_balances()
params = params or {}
if self.unified_account:
params["type"] = "spot"
balances = super().get_balances(params)
dexes = self._get_configured_hip3_dexes()
for dex in dexes:
try: