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 datetime import datetime
from typing import Any from typing import Any
import ccxt
from freqtrade.constants import BuySell from freqtrade.constants import BuySell
from freqtrade.enums import MarginMode, TradingMode from freqtrade.enums import MarginMode, TradingMode
from freqtrade.enums.runmode import NON_UTIL_MODES 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 import Exchange
from freqtrade.exchange.common import retrier
from freqtrade.exchange.exchange_types import CcxtBalances, CcxtOrder, CcxtPosition, FtHas from freqtrade.exchange.exchange_types import CcxtBalances, CcxtOrder, CcxtPosition, FtHas
from freqtrade.util.datetime_helpers import dt_from_ts 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. Contains adjustments needed for Freqtrade to work with this exchange.
""" """
unified_account = False
_ft_has: FtHas = { _ft_has: FtHas = {
"ohlcv_has_history": False, "ohlcv_has_history": False,
"l2_limit_range": [20], "l2_limit_range": [20],
@@ -58,6 +69,36 @@ class Hyperliquid(Exchange):
config.update(super()._ccxt_config) config.update(super()._ccxt_config)
return 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]: def _get_configured_hip3_dexes(self) -> list[str]:
"""Get list of configured HIP-3 DEXes.""" """Get list of configured HIP-3 DEXes."""
return self._config.get("exchange", {}).get("hip3_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 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. 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() dexes = self._get_configured_hip3_dexes()
for dex in dexes: for dex in dexes:
try: try: