Simplify liquidation price calling structure

This commit is contained in:
Matthias 2022-08-29 06:45:00 +02:00
parent f664ebd262
commit 226fa5d93c
4 changed files with 69 additions and 101 deletions

View File

@ -2432,36 +2432,6 @@ class Exchange:
""" """
return 0.0 return 0.0
def get_liquidation_price(
self,
pair: str,
open_rate: float,
amount: float, # quote currency, includes leverage
stake_amount: float,
leverage: float,
is_short: bool
) -> Optional[float]:
if self.trading_mode in TradingMode.SPOT:
return None
elif (
self.trading_mode == TradingMode.FUTURES
):
isolated_liq = self.get_or_calculate_liquidation_price(
pair=pair,
open_rate=open_rate,
is_short=is_short,
amount=amount,
stake_amount=stake_amount,
wallet_balance=stake_amount, # In isolated mode, stake-amount = wallet size
mm_ex_1=0.0,
upnl_ex_1=0.0,
)
return isolated_liq
else:
raise OperationalException(
"Freqtrade currently only supports futures for leverage trading.")
def funding_fee_cutoff(self, open_date: datetime): def funding_fee_cutoff(self, open_date: datetime):
""" """
:param open_date: The open date for a trade :param open_date: The open date for a trade
@ -2622,7 +2592,7 @@ class Exchange:
else: else:
return 0.0 return 0.0
def get_or_calculate_liquidation_price( def get_liquidation_price(
self, self,
pair: str, pair: str,
# Dry-run # Dry-run
@ -2630,7 +2600,7 @@ class Exchange:
is_short: bool, is_short: bool,
amount: float, # Absolute value of position size amount: float, # Absolute value of position size
stake_amount: float, stake_amount: float,
wallet_balance: float, # Or margin balance wallet_balance: float = 0.0,
mm_ex_1: float = 0.0, # (Binance) Cross only mm_ex_1: float = 0.0, # (Binance) Cross only
upnl_ex_1: float = 0.0, # (Binance) Cross only upnl_ex_1: float = 0.0, # (Binance) Cross only
) -> Optional[float]: ) -> Optional[float]:

View File

@ -1732,12 +1732,12 @@ class FreqtradeBot(LoggingMixin):
# TODO: Margin will need to use interest_rate as well. # TODO: Margin will need to use interest_rate as well.
# interest_rate = self.exchange.get_interest_rate() # interest_rate = self.exchange.get_interest_rate()
trade.set_liquidation_price(self.exchange.get_liquidation_price( trade.set_liquidation_price(self.exchange.get_liquidation_price(
leverage=trade.leverage,
pair=trade.pair, pair=trade.pair,
open_rate=trade.open_rate,
is_short=trade.is_short,
amount=trade.amount, amount=trade.amount,
stake_amount=trade.stake_amount, stake_amount=trade.stake_amount,
open_rate=trade.open_rate, wallet_balance=trade.stake_amount,
is_short=trade.is_short
)) ))
# Updating wallets when order is closed # Updating wallets when order is closed

View File

@ -881,7 +881,7 @@ class Backtesting:
open_rate=propose_rate, open_rate=propose_rate,
amount=amount, amount=amount,
stake_amount=trade.stake_amount, stake_amount=trade.stake_amount,
leverage=leverage, wallet_balance=trade.stake_amount,
is_short=is_short, is_short=is_short,
)) ))

View File

@ -4089,68 +4089,6 @@ def test_combine_funding_and_mark(
assert len(df) == 0 assert len(df) == 0
def test_get_or_calculate_liquidation_price(mocker, default_conf):
api_mock = MagicMock()
positions = [
{
'info': {},
'symbol': 'NEAR/USDT:USDT',
'timestamp': 1642164737148,
'datetime': '2022-01-14T12:52:17.148Z',
'initialMargin': 1.51072,
'initialMarginPercentage': 0.1,
'maintenanceMargin': 0.38916147,
'maintenanceMarginPercentage': 0.025,
'entryPrice': 18.884,
'notional': 15.1072,
'leverage': 9.97,
'unrealizedPnl': 0.0048,
'contracts': 8,
'contractSize': 0.1,
'marginRatio': None,
'liquidationPrice': 17.47,
'markPrice': 18.89,
'margin_mode': 1.52549075,
'marginType': 'isolated',
'side': 'buy',
'percentage': 0.003177292946409658
}
]
api_mock.fetch_positions = MagicMock(return_value=positions)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
exchange_has=MagicMock(return_value=True),
)
default_conf['dry_run'] = False
default_conf['trading_mode'] = 'futures'
default_conf['margin_mode'] = 'isolated'
default_conf['liquidation_buffer'] = 0.0
exchange = get_patched_exchange(mocker, default_conf, api_mock)
liq_price = exchange.get_or_calculate_liquidation_price(
pair='NEAR/USDT:USDT',
open_rate=18.884,
is_short=False,
amount=0.8,
stake_amount=18.884 * 0.8,
wallet_balance=0.8,
)
assert liq_price == 17.47
default_conf['liquidation_buffer'] = 0.05
exchange = get_patched_exchange(mocker, default_conf, api_mock)
liq_price = exchange.get_or_calculate_liquidation_price(
pair='NEAR/USDT:USDT',
open_rate=18.884,
is_short=False,
amount=0.8,
stake_amount=18.884 * 0.8,
wallet_balance=0.8,
)
assert liq_price == 17.540699999999998
@pytest.mark.parametrize('exchange,rate_start,rate_end,d1,d2,amount,expected_fees', [ @pytest.mark.parametrize('exchange,rate_start,rate_end,d1,d2,amount,expected_fees', [
('binance', 0, 2, "2021-09-01 01:00:00", "2021-09-01 04:00:00", 30.0, 0.0), ('binance', 0, 2, "2021-09-01 01:00:00", "2021-09-01 04:00:00", 30.0, 0.0),
('binance', 0, 2, "2021-09-01 00:00:00", "2021-09-01 08:00:00", 30.0, -0.00091409999), ('binance', 0, 2, "2021-09-01 00:00:00", "2021-09-01 08:00:00", 30.0, -0.00091409999),
@ -4541,7 +4479,7 @@ def test_liquidation_price_is_none(
default_conf['trading_mode'] = trading_mode default_conf['trading_mode'] = trading_mode
default_conf['margin_mode'] = margin_mode default_conf['margin_mode'] = margin_mode
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name) exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
assert exchange.get_or_calculate_liquidation_price( assert exchange.get_liquidation_price(
pair='DOGE/USDT', pair='DOGE/USDT',
open_rate=open_rate, open_rate=open_rate,
is_short=is_short, is_short=is_short,
@ -4576,7 +4514,7 @@ def test_liquidation_price(
default_conf['liquidation_buffer'] = 0.0 default_conf['liquidation_buffer'] = 0.0
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name) exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
exchange.get_maintenance_ratio_and_amt = MagicMock(return_value=(mm_ratio, maintenance_amt)) exchange.get_maintenance_ratio_and_amt = MagicMock(return_value=(mm_ratio, maintenance_amt))
assert isclose(round(exchange.get_or_calculate_liquidation_price( assert isclose(round(exchange.get_liquidation_price(
pair='DOGE/USDT', pair='DOGE/USDT',
open_rate=open_rate, open_rate=open_rate,
is_short=is_short, is_short=is_short,
@ -5003,6 +4941,66 @@ def test__get_params(mocker, default_conf, exchange_name):
) == params2 ) == params2
def test_get_liquidation_price1(mocker, default_conf):
api_mock = MagicMock()
positions = [
{
'info': {},
'symbol': 'NEAR/USDT:USDT',
'timestamp': 1642164737148,
'datetime': '2022-01-14T12:52:17.148Z',
'initialMargin': 1.51072,
'initialMarginPercentage': 0.1,
'maintenanceMargin': 0.38916147,
'maintenanceMarginPercentage': 0.025,
'entryPrice': 18.884,
'notional': 15.1072,
'leverage': 9.97,
'unrealizedPnl': 0.0048,
'contracts': 8,
'contractSize': 0.1,
'marginRatio': None,
'liquidationPrice': 17.47,
'markPrice': 18.89,
'margin_mode': 1.52549075,
'marginType': 'isolated',
'side': 'buy',
'percentage': 0.003177292946409658
}
]
api_mock.fetch_positions = MagicMock(return_value=positions)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
exchange_has=MagicMock(return_value=True),
)
default_conf['dry_run'] = False
default_conf['trading_mode'] = 'futures'
default_conf['margin_mode'] = 'isolated'
default_conf['liquidation_buffer'] = 0.0
exchange = get_patched_exchange(mocker, default_conf, api_mock)
liq_price = exchange.get_liquidation_price(
pair='NEAR/USDT:USDT',
open_rate=18.884,
is_short=False,
amount=0.8,
stake_amount=18.884 * 0.8,
)
assert liq_price == 17.47
default_conf['liquidation_buffer'] = 0.05
exchange = get_patched_exchange(mocker, default_conf, api_mock)
liq_price = exchange.get_liquidation_price(
pair='NEAR/USDT:USDT',
open_rate=18.884,
is_short=False,
amount=0.8,
stake_amount=18.884 * 0.8,
)
assert liq_price == 17.540699999999998
@pytest.mark.parametrize('liquidation_buffer', [0.0, 0.05]) @pytest.mark.parametrize('liquidation_buffer', [0.0, 0.05])
@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", [
@ -5116,7 +5114,7 @@ def test_get_liquidation_price(
open_rate=open_rate, open_rate=open_rate,
amount=amount, amount=amount,
stake_amount=amount * open_rate / leverage, stake_amount=amount * open_rate / leverage,
leverage=leverage, # leverage=leverage,
is_short=is_short, is_short=is_short,
) )
if expected_liq is None: if expected_liq is None: