parent
753d1b2aad
commit
01126c43f7
@ -137,23 +137,27 @@ class Binance(Exchange):
|
||||
pair: str,
|
||||
open_rate: float, # Entry price of position
|
||||
is_short: bool,
|
||||
position: float, # Absolute value of position size
|
||||
amount: float,
|
||||
stake_amount: 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!
|
||||
MARGIN: https://www.binance.com/en/support/faq/f6b010588e55413aa58b7d63ee0125ed
|
||||
PERPETUAL: https://www.binance.com/en/support/faq/b3c689c1f50a44cabb3a84e663b81d93
|
||||
|
||||
:param exchange_name:
|
||||
:param open_rate: (EP1) Entry price of position
|
||||
:param open_rate: Entry price of position
|
||||
:param is_short: True if the trade is a short, false otherwise
|
||||
:param position: Absolute value of position size (in base currency)
|
||||
:param wallet_balance: (WB)
|
||||
:param amount: Absolute value of position size incl. leverage (in base currency)
|
||||
:param stake_amount: Stake amount - Collateral in settle currency.
|
||||
: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
|
||||
:param maintenance_amt:
|
||||
|
||||
# * Only required for Cross
|
||||
:param mm_ex_1: (TMM)
|
||||
@ -165,12 +169,11 @@ class Binance(Exchange):
|
||||
"""
|
||||
|
||||
side_1 = -1 if is_short else 1
|
||||
position = abs(position)
|
||||
cross_vars = upnl_ex_1 - mm_ex_1 if self.margin_mode == MarginMode.CROSS else 0.0
|
||||
|
||||
# mm_ratio: Binance's formula specifies maintenance margin rate which is mm_ratio * 100%
|
||||
# maintenance_amt: (CUM) Maintenance Amount of position
|
||||
mm_ratio, maintenance_amt = self.get_maintenance_ratio_and_amt(pair, position)
|
||||
mm_ratio, maintenance_amt = self.get_maintenance_ratio_and_amt(pair, stake_amount)
|
||||
|
||||
if (maintenance_amt is None):
|
||||
raise OperationalException(
|
||||
@ -182,9 +185,9 @@ class Binance(Exchange):
|
||||
return (
|
||||
(
|
||||
(wallet_balance + cross_vars + maintenance_amt) -
|
||||
(side_1 * position * open_rate)
|
||||
(side_1 * amount * open_rate)
|
||||
) / (
|
||||
(position * mm_ratio) - (side_1 * position)
|
||||
(amount * mm_ratio) - (side_1 * amount)
|
||||
)
|
||||
)
|
||||
else:
|
||||
|
@ -2437,6 +2437,7 @@ class Exchange:
|
||||
pair: str,
|
||||
open_rate: float,
|
||||
amount: float, # quote currency, includes leverage
|
||||
stake_amount: float,
|
||||
leverage: float,
|
||||
is_short: bool
|
||||
) -> Optional[float]:
|
||||
@ -2446,13 +2447,13 @@ class Exchange:
|
||||
elif (
|
||||
self.trading_mode == TradingMode.FUTURES
|
||||
):
|
||||
wallet_balance = (amount * open_rate) / leverage
|
||||
isolated_liq = self.get_or_calculate_liquidation_price(
|
||||
pair=pair,
|
||||
open_rate=open_rate,
|
||||
is_short=is_short,
|
||||
position=amount,
|
||||
wallet_balance=wallet_balance,
|
||||
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,
|
||||
)
|
||||
@ -2627,14 +2628,14 @@ class Exchange:
|
||||
# Dry-run
|
||||
open_rate: float, # Entry price of position
|
||||
is_short: bool,
|
||||
position: float, # Absolute value of position size
|
||||
amount: float, # Absolute value of position size
|
||||
stake_amount: 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]:
|
||||
"""
|
||||
Set's the margin mode on the exchange to cross or isolated for a specific pair
|
||||
:param pair: base/quote currency pair (e.g. "ADA/USDT")
|
||||
"""
|
||||
if self.trading_mode == TradingMode.SPOT:
|
||||
return None
|
||||
@ -2648,7 +2649,8 @@ class Exchange:
|
||||
pair=pair,
|
||||
open_rate=open_rate,
|
||||
is_short=is_short,
|
||||
position=position,
|
||||
amount=amount,
|
||||
stake_amount=stake_amount,
|
||||
wallet_balance=wallet_balance,
|
||||
mm_ex_1=mm_ex_1,
|
||||
upnl_ex_1=upnl_ex_1
|
||||
@ -2677,22 +2679,24 @@ class Exchange:
|
||||
pair: str,
|
||||
open_rate: float, # Entry price of position
|
||||
is_short: bool,
|
||||
position: float, # Absolute value of position size
|
||||
amount: float,
|
||||
stake_amount: 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:
|
||||
gateio: https://www.gate.io/help/futures/perpetual/22160/calculation-of-liquidation-price
|
||||
okex: https://www.okex.com/support/hc/en-us/articles/
|
||||
360053909592-VI-Introduction-to-the-isolated-mode-of-Single-Multi-currency-Portfolio-margin
|
||||
Important: Must be fetching data from cached values as this is used by backtesting!
|
||||
|
||||
:param exchange_name:
|
||||
:param open_rate: Entry price of position
|
||||
:param is_short: True if the trade is a short, false otherwise
|
||||
:param position: Absolute value of position size incl. leverage (in base currency)
|
||||
:param amount: Absolute value of position size incl. leverage (in base currency)
|
||||
:param stake_amount: Stake amount - Collateral in settle currency.
|
||||
: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
|
||||
@ -2706,7 +2710,7 @@ class Exchange:
|
||||
|
||||
market = self.markets[pair]
|
||||
taker_fee_rate = market['taker']
|
||||
mm_ratio, _ = self.get_maintenance_ratio_and_amt(pair, position)
|
||||
mm_ratio, _ = self.get_maintenance_ratio_and_amt(pair, stake_amount)
|
||||
|
||||
if self.trading_mode == TradingMode.FUTURES and self.margin_mode == MarginMode.ISOLATED:
|
||||
|
||||
@ -2714,7 +2718,7 @@ class Exchange:
|
||||
raise OperationalException(
|
||||
"Freqtrade does not yet support inverse contracts")
|
||||
|
||||
value = wallet_balance / position
|
||||
value = wallet_balance / amount
|
||||
|
||||
mm_ratio_taker = (mm_ratio + taker_fee_rate)
|
||||
if is_short:
|
||||
|
@ -1734,6 +1734,7 @@ class FreqtradeBot(LoggingMixin):
|
||||
leverage=trade.leverage,
|
||||
pair=trade.pair,
|
||||
amount=trade.amount,
|
||||
stake_amount=trade.stake_amount,
|
||||
open_rate=trade.open_rate,
|
||||
is_short=trade.is_short
|
||||
))
|
||||
|
@ -876,6 +876,7 @@ class Backtesting:
|
||||
pair=pair,
|
||||
open_rate=propose_rate,
|
||||
amount=amount,
|
||||
stake_amount=trade.stake_amount,
|
||||
leverage=leverage,
|
||||
is_short=is_short,
|
||||
))
|
||||
|
@ -4132,7 +4132,8 @@ def test_get_or_calculate_liquidation_price(mocker, default_conf):
|
||||
pair='NEAR/USDT:USDT',
|
||||
open_rate=18.884,
|
||||
is_short=False,
|
||||
position=0.8,
|
||||
amount=0.8,
|
||||
stake_amount=18.884 * 0.8,
|
||||
wallet_balance=0.8,
|
||||
)
|
||||
assert liq_price == 17.47
|
||||
@ -4143,7 +4144,8 @@ def test_get_or_calculate_liquidation_price(mocker, default_conf):
|
||||
pair='NEAR/USDT:USDT',
|
||||
open_rate=18.884,
|
||||
is_short=False,
|
||||
position=0.8,
|
||||
amount=0.8,
|
||||
stake_amount=18.884 * 0.8,
|
||||
wallet_balance=0.8,
|
||||
)
|
||||
assert liq_price == 17.540699999999998
|
||||
@ -4543,7 +4545,8 @@ def test_liquidation_price_is_none(
|
||||
pair='DOGE/USDT',
|
||||
open_rate=open_rate,
|
||||
is_short=is_short,
|
||||
position=71200.81144,
|
||||
amount=71200.81144,
|
||||
stake_amount=open_rate * 71200.81144,
|
||||
wallet_balance=-56354.57,
|
||||
mm_ex_1=0.10,
|
||||
upnl_ex_1=0.0
|
||||
@ -4552,7 +4555,7 @@ def test_liquidation_price_is_none(
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'exchange_name, is_short, trading_mode, margin_mode, wallet_balance, '
|
||||
'mm_ex_1, upnl_ex_1, maintenance_amt, position, open_rate, '
|
||||
'mm_ex_1, upnl_ex_1, maintenance_amt, amount, open_rate, '
|
||||
'mm_ratio, expected',
|
||||
[
|
||||
("binance", False, 'futures', 'isolated', 1535443.01, 0.0,
|
||||
@ -4566,7 +4569,7 @@ def test_liquidation_price_is_none(
|
||||
])
|
||||
def test_liquidation_price(
|
||||
mocker, default_conf, exchange_name, open_rate, is_short, trading_mode,
|
||||
margin_mode, wallet_balance, mm_ex_1, upnl_ex_1, maintenance_amt, position, mm_ratio, expected
|
||||
margin_mode, wallet_balance, mm_ex_1, upnl_ex_1, maintenance_amt, amount, mm_ratio, expected
|
||||
):
|
||||
default_conf['trading_mode'] = trading_mode
|
||||
default_conf['margin_mode'] = margin_mode
|
||||
@ -4580,7 +4583,8 @@ def test_liquidation_price(
|
||||
wallet_balance=wallet_balance,
|
||||
mm_ex_1=mm_ex_1,
|
||||
upnl_ex_1=upnl_ex_1,
|
||||
position=position,
|
||||
amount=amount,
|
||||
stake_amount=open_rate * amount,
|
||||
), 2), expected)
|
||||
|
||||
|
||||
@ -5111,6 +5115,7 @@ def test_get_liquidation_price(
|
||||
pair='ETH/USDT:USDT',
|
||||
open_rate=open_rate,
|
||||
amount=amount,
|
||||
stake_amount=amount * open_rate / leverage,
|
||||
leverage=leverage,
|
||||
is_short=is_short,
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user