Simplify liquidation price calling structure
This commit is contained in:
parent
f664ebd262
commit
226fa5d93c
@ -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]:
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
))
|
))
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
Loading…
Reference in New Issue
Block a user