mirror of
https://github.com/freqtrade/freqtrade.git
synced 2025-11-30 17:13:06 +00:00
Merge pull request #12309 from freqtrade/feat/hyperliquid_cross
hyperliquid cross futures support
This commit is contained in:
@@ -11,7 +11,7 @@
|
||||
| [Gate.io](exchanges.md#gateio) | futures | isolated | limit |
|
||||
| [HTX](exchanges.md#htx) | spot | | limit |
|
||||
| [Hyperliquid](exchanges.md#hyperliquid) | spot | | ❌ (not supported) |
|
||||
| [Hyperliquid](exchanges.md#hyperliquid) | futures | isolated | limit |
|
||||
| [Hyperliquid](exchanges.md#hyperliquid) | futures | isolated, cross | limit |
|
||||
| [Kraken](exchanges.md#kraken) | spot | | market, limit |
|
||||
| [OKX](exchanges.md#okx) | spot | | limit |
|
||||
| [OKX](exchanges.md#okx) | futures | isolated | limit |
|
||||
|
||||
@@ -92,6 +92,11 @@ One account is used to share collateral between markets (trading pairs). Margin
|
||||
|
||||
Please read the [exchange specific notes](exchanges.md) for exchanges that support this mode and how they differ.
|
||||
|
||||
!!! Warning "Increased risk of liquidation"
|
||||
Cross margin mode increases the risk of full account liquidation, as all trades share the same collateral.
|
||||
A loss on one trade can affect the liquidation price of other trades.
|
||||
Also, cross-position influence may not be fully simulated in dry-run or backtesting mode.
|
||||
|
||||
## Set leverage to use
|
||||
|
||||
Different strategies and risk profiles will require different levels of leverage.
|
||||
|
||||
@@ -44,6 +44,7 @@ class Hyperliquid(Exchange):
|
||||
_supported_trading_mode_margin_pairs: list[tuple[TradingMode, MarginMode]] = [
|
||||
(TradingMode.SPOT, MarginMode.NONE),
|
||||
(TradingMode.FUTURES, MarginMode.ISOLATED),
|
||||
(TradingMode.FUTURES, MarginMode.CROSS),
|
||||
]
|
||||
|
||||
@property
|
||||
@@ -99,7 +100,6 @@ class Hyperliquid(Exchange):
|
||||
'SOL/USDC:USDC': 43}}
|
||||
"""
|
||||
# Defining/renaming variables to match the documentation
|
||||
isolated_margin = wallet_balance
|
||||
position_size = amount
|
||||
price = open_rate
|
||||
position_value = price * position_size
|
||||
@@ -117,8 +117,14 @@ class Hyperliquid(Exchange):
|
||||
# 3. Divide this by 2
|
||||
maintenance_margin_required = position_value / max_leverage / 2
|
||||
|
||||
# Docs: margin_available (isolated) = isolated_margin - maintenance_margin_required
|
||||
margin_available = isolated_margin - maintenance_margin_required
|
||||
if self.margin_mode == MarginMode.ISOLATED:
|
||||
# Docs: margin_available (isolated) = isolated_margin - maintenance_margin_required
|
||||
margin_available = stake_amount - maintenance_margin_required
|
||||
elif self.margin_mode == MarginMode.CROSS:
|
||||
# Docs: margin_available (cross) = account_value - maintenance_margin_required
|
||||
margin_available = wallet_balance - maintenance_margin_required
|
||||
else:
|
||||
raise OperationalException("Unsupported margin mode for liquidation price calculation")
|
||||
|
||||
# Docs: The maintenance margin is half of the initial margin at max leverage
|
||||
# The docs don't explicitly specify maintenance leverage, but this works.
|
||||
|
||||
@@ -6,7 +6,8 @@ import pytest
|
||||
from tests.conftest import EXMS, get_mock_coro, get_patched_exchange
|
||||
|
||||
|
||||
def test_hyperliquid_dry_run_liquidation_price(default_conf, mocker):
|
||||
@pytest.mark.parametrize("margin_mode", ["isolated", "cross"])
|
||||
def test_hyperliquid_dry_run_liquidation_price(default_conf, mocker, margin_mode):
|
||||
# test if liq price calculated by dry_run_liquidation_price() is close to ccxt liq price
|
||||
# testing different pairs with large/small prices, different leverages, long, short
|
||||
markets = {
|
||||
@@ -281,7 +282,7 @@ def test_hyperliquid_dry_run_liquidation_price(default_conf, mocker):
|
||||
|
||||
api_mock = MagicMock()
|
||||
default_conf["trading_mode"] = "futures"
|
||||
default_conf["margin_mode"] = "isolated"
|
||||
default_conf["margin_mode"] = margin_mode
|
||||
default_conf["stake_currency"] = "USDC"
|
||||
api_mock.load_markets = get_mock_coro()
|
||||
api_mock.markets = markets
|
||||
@@ -299,11 +300,32 @@ def test_hyperliquid_dry_run_liquidation_price(default_conf, mocker):
|
||||
position["contracts"],
|
||||
position["collateral"],
|
||||
position["leverage"],
|
||||
position["collateral"],
|
||||
[],
|
||||
# isolated doesn't use wallet-balance
|
||||
wallet_balance=0.0 if margin_mode == "isolated" else position["collateral"],
|
||||
open_trades=[],
|
||||
)
|
||||
# Assume full position size is the wallet balance
|
||||
assert pytest.approx(liq_price_returned, rel=0.0001) == liq_price_calculated
|
||||
|
||||
if margin_mode == "cross":
|
||||
# test with larger wallet balance
|
||||
liq_price_calculated_cross = exchange.dry_run_liquidation_price(
|
||||
position["symbol"],
|
||||
position["entryPrice"],
|
||||
is_short,
|
||||
position["contracts"],
|
||||
position["collateral"],
|
||||
position["leverage"],
|
||||
wallet_balance=position["collateral"] * 2,
|
||||
open_trades=[],
|
||||
)
|
||||
# Assume full position size is the wallet balance
|
||||
# This
|
||||
if position["side"] == "long":
|
||||
assert liq_price_returned > liq_price_calculated_cross < position["entryPrice"]
|
||||
else:
|
||||
assert liq_price_returned < liq_price_calculated_cross > position["entryPrice"]
|
||||
|
||||
|
||||
def test_hyperliquid_get_funding_fees(default_conf, mocker):
|
||||
now = datetime.now(UTC)
|
||||
|
||||
Reference in New Issue
Block a user