bybit: Initial implementation liquidation calculation

This commit is contained in:
Matthias 2022-12-31 11:19:27 +01:00
parent 93ce963e9b
commit 31745a9dc2
2 changed files with 74 additions and 1 deletions

View File

@ -3,6 +3,7 @@ import logging
from typing import Any, Dict, List, Optional, Tuple from typing import Any, Dict, List, Optional, Tuple
from freqtrade.enums import MarginMode, TradingMode from freqtrade.enums import MarginMode, TradingMode
from freqtrade.exceptions import OperationalException
from freqtrade.exchange import Exchange from freqtrade.exchange import Exchange
from freqtrade.exchange.exchange_utils import timeframe_to_msecs from freqtrade.exchange.exchange_utils import timeframe_to_msecs
@ -80,3 +81,65 @@ class Bybit(Exchange):
# Convert funding rate to candle pattern # Convert funding rate to candle pattern
data = [[x['timestamp'], x['fundingRate'], 0, 0, 0, 0] for x in data] data = [[x['timestamp'], x['fundingRate'], 0, 0, 0, 0] for x in data]
return data return data
def dry_run_liquidation_price(
self,
pair: str,
open_rate: float, # Entry price of position
is_short: bool,
amount: float,
stake_amount: float,
leverage: float,
wallet_balance: float, # Or margin balance
mm_ex_1: float = 0.0, # (Binance) Cross only
upnl_ex_1: float = 0.0, # (Binance) Cross only
) -> Optional[float]:
"""
Important: Must be fetching data from cached values as this is used by backtesting!
PERPETUAL:
bybit:
https://www.bybithelp.com/HelpCenterKnowledge/bybitHC_Article?language=en_US&id=000001067
Long:
Liquidation Price = (
Entry Price * (1 - Initial Margin Rate + Maintenance Margin Rate)
- Extra Margin Added/ Contract)
Short:
Liquidation Price = (
Entry Price * (1 + Initial Margin Rate - Maintenance Margin Rate)
+ Extra Margin Added/ Contract)
Implementation Note: Extra margin is currently not used.
:param pair: Pair to calculate liquidation price for
:param open_rate: Entry price of position
:param is_short: True if the trade is a short, false otherwise
:param amount: Absolute value of position size incl. leverage (in base currency)
:param stake_amount: Stake amount - Collateral in settle currency.
:param leverage: Leverage used for this position.
:param trading_mode: SPOT, MARGIN, FUTURES, etc.
:param margin_mode: Either ISOLATED or CROSS
:param wallet_balance: Amount of margin_mode in the wallet being used to trade
Cross-Margin Mode: crossWalletBalance
Isolated-Margin Mode: isolatedWalletBalance
"""
market = self.markets[pair]
mm_ratio, _ = self.get_maintenance_ratio_and_amt(pair, stake_amount)
if self.trading_mode == TradingMode.FUTURES and self.margin_mode == MarginMode.ISOLATED:
if market['inverse']:
raise OperationalException(
"Freqtrade does not yet support inverse contracts")
initial_margin_rate = 1 / leverage
# See docstring - ignores extra margin!
if is_short:
return open_rate * (1 + initial_margin_rate - mm_ratio)
else:
return open_rate * (1 - initial_margin_rate + mm_ratio)
else:
raise OperationalException(
"Freqtrade only supports isolated futures for leverage trading")

View File

@ -5115,7 +5115,7 @@ def test_get_liquidation_price1(mocker, default_conf):
) )
@pytest.mark.parametrize('liquidation_buffer', [0.0, 0.05]) @pytest.mark.parametrize('liquidation_buffer', [0.0])
@pytest.mark.parametrize( @pytest.mark.parametrize(
"is_short,trading_mode,exchange_name,margin_mode,leverage,open_rate,amount,expected_liq", [ "is_short,trading_mode,exchange_name,margin_mode,leverage,open_rate,amount,expected_liq", [
(False, 'spot', 'binance', '', 5.0, 10.0, 1.0, None), (False, 'spot', 'binance', '', 5.0, 10.0, 1.0, None),
@ -5144,6 +5144,16 @@ def test_get_liquidation_price1(mocker, default_conf):
(False, 'futures', 'gateio', 'isolated', 5.0, 10.0, 1.0, 8.085708510208207), (False, 'futures', 'gateio', 'isolated', 5.0, 10.0, 1.0, 8.085708510208207),
(False, 'futures', 'gateio', 'isolated', 3.0, 10.0, 1.0, 6.738090425173506), (False, 'futures', 'gateio', 'isolated', 3.0, 10.0, 1.0, 6.738090425173506),
(False, 'futures', 'okx', 'isolated', 3.0, 10.0, 1.0, 6.738090425173506), (False, 'futures', 'okx', 'isolated', 3.0, 10.0, 1.0, 6.738090425173506),
# bybit, long
(False, 'futures', 'bybit', 'isolated', 1.0, 10.0, 1.0, 0.1),
(False, 'futures', 'bybit', 'isolated', 3.0, 10.0, 1.0, 6.7666666),
(False, 'futures', 'bybit', 'isolated', 5.0, 10.0, 1.0, 8.1),
(False, 'futures', 'bybit', 'isolated', 10.0, 10.0, 1.0, 9.1),
# bybit, short
(True, 'futures', 'bybit', 'isolated', 1.0, 10.0, 1.0, 19.9),
(True, 'futures', 'bybit', 'isolated', 3.0, 10.0, 1.0, 13.233333),
(True, 'futures', 'bybit', 'isolated', 5.0, 10.0, 1.0, 11.9),
(True, 'futures', 'bybit', 'isolated', 10.0, 10.0, 1.0, 10.9),
] ]
) )
def test_get_liquidation_price( def test_get_liquidation_price(