cleaned up liquidation price methods

This commit is contained in:
Sam Germain
2022-01-29 02:06:56 -06:00
parent ede9012fcc
commit 143c37d36f
5 changed files with 79 additions and 191 deletions

View File

@@ -277,18 +277,15 @@ class Binance(Exchange):
# The lowest notional_floor for any pair in loadLeverageBrackets is always 0 because it
# describes the min amount for a bracket, and the lowest bracket will always go down to 0
def liquidation_price_helper(
def liquidation_price(
self,
open_rate: float, # Entry price of position
is_short: bool,
leverage: float,
mm_ratio: float,
position: float, # Absolute value of position size
trading_mode: TradingMode,
collateral: Collateral,
maintenance_amt: Optional[float] = None, # (Binance)
wallet_balance: Optional[float] = None, # (Binance and Gateio)
wallet_balance: float, # Or margin balance
taker_fee_rate: Optional[float] = None, # (Gateio & Okex)
maintenance_amt: Optional[float] = None, # (Binance)
mm_ex_1: Optional[float] = 0.0, # (Binance) Cross only
upnl_ex_1: Optional[float] = 0.0, # (Binance) Cross only
) -> Optional[float]:
@@ -299,19 +296,15 @@ class Binance(Exchange):
:param exchange_name:
:param open_rate: (EP1) Entry price of position
:param is_short: True if the trade is a short, false otherwise
:param leverage: The amount of leverage on the trade
:param mm_ratio: (MMR)
# Binance's formula specifies maintenance margin rate which is mm_ratio * 100%
:param position: Absolute value of position size (in base currency)
:param trading_mode: SPOT, MARGIN, FUTURES, etc.
:param collateral: Either ISOLATED or CROSS
:param maintenance_amt: (CUM) Maintenance Amount of position
:param wallet_balance: (WB)
Cross-Margin Mode: crossWalletBalance
Isolated-Margin Mode: isolatedWalletBalance
# * Not required by Binance
:param taker_fee_rate:
:param taker_fee_rate: # * Not required by Binance
:param maintenance_amt:
# * Only required for Cross
:param mm_ex_1: (TMM)
@@ -321,31 +314,32 @@ class Binance(Exchange):
Cross-Margin Mode: Unrealized PNL of all other contracts, excluding Contract 1.
Isolated-Margin Mode: 0
"""
if trading_mode == TradingMode.SPOT:
if self.trading_mode == TradingMode.SPOT:
return None
elif (self.collateral is None):
raise OperationalException('Binance.collateral must be set for liquidation_price')
if not collateral:
if (maintenance_amt is None):
raise OperationalException(
"Parameter collateral is required by liquidation_price when trading_mode is "
f"{trading_mode}"
f"Parameter maintenance_amt is required by Binance.liquidation_price"
f"for {self.collateral.value} {self.trading_mode.value}"
)
if (
(wallet_balance is None or maintenance_amt is None or position is None) or
(collateral == Collateral.CROSS and (mm_ex_1 is None or upnl_ex_1 is None))
):
required_params = "wallet_balance, maintenance_amt, position"
if collateral == Collateral.CROSS:
required_params += ", mm_ex_1, upnl_ex_1"
if (self.collateral == Collateral.CROSS and (mm_ex_1 is None or upnl_ex_1 is None)):
raise OperationalException(
f"Parameters {required_params} are required by Binance.liquidation_price"
f"for {collateral.name} {trading_mode.name}"
f"Parameters mm_ex_1 and upnl_ex_1 are required by Binance.liquidation_price"
f"for {self.collateral.value} {self.trading_mode.value}"
)
side_1 = -1 if is_short else 1
position = abs(position)
cross_vars = upnl_ex_1 - mm_ex_1 if collateral == Collateral.CROSS else 0.0 # type: ignore
cross_vars = (
upnl_ex_1 - mm_ex_1 # type: ignore
if self.collateral == Collateral.CROSS else
0.0
)
if trading_mode == TradingMode.FUTURES:
if self.trading_mode == TradingMode.FUTURES:
return (
(
(wallet_balance + cross_vars + maintenance_amt) -
@@ -356,4 +350,4 @@ class Binance(Exchange):
)
raise OperationalException(
f"Binance does not support {collateral.value} Mode {trading_mode.value} trading ")
f"Binance does not support {self.collateral.value} {self.trading_mode.value} trading")

View File

@@ -2018,135 +2018,62 @@ class Exchange:
self,
open_rate: float, # Entry price of position
is_short: bool,
leverage: float,
mm_ratio: float,
position: float, # Absolute value of position size
trading_mode: TradingMode,
collateral: Optional[Collateral] = Collateral.ISOLATED,
maintenance_amt: Optional[float] = None, # (Binance)
wallet_balance: Optional[float] = None, # (Binance and Gateio)
wallet_balance: float, # Or margin balance
taker_fee_rate: Optional[float] = None, # (Gateio & Okex)
maintenance_amt: Optional[float] = None, # (Binance)
mm_ex_1: Optional[float] = 0.0, # (Binance) Cross only
upnl_ex_1: Optional[float] = 0.0, # (Binance) Cross only
) -> Optional[float]:
"""
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
: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 leverage: The amount of leverage on the trade
:param mm_ratio: (MMR)
Okex: [assets in the position - (liability +interest) * mark price] /
(maintenance margin + liquidation fee)
# * Note: Binance's formula specifies maintenance margin rate which is mm_ratio * 100%
:param position: Absolute value of position size (in base currency)
:param mm_ratio:
:param trading_mode: SPOT, MARGIN, FUTURES, etc.
:param collateral: Either ISOLATED or CROSS
# * Binance
:param maintenance_amt: (CUM) Maintenance Amount of position
# * Binance and Gateio
:param wallet_balance: (WB)
:param wallet_balance: Amount of collateral in the wallet being used to trade
Cross-Margin Mode: crossWalletBalance
Isolated-Margin Mode: isolatedWalletBalance
# * Gateio & Okex
:param taker_fee_rate:
# * Cross only (Binance)
:param mm_ex_1: (TMM)
Cross-Margin Mode: Maintenance Margin of all other contracts, excluding Contract 1
Isolated-Margin Mode: 0
:param upnl_ex_1: (UPNL)
Cross-Margin Mode: Unrealized PNL of all other contracts, excluding Contract 1.
Isolated-Margin Mode: 0
# * Not required by Gateio or OKX
:param maintenance_amt:
:param mm_ex_1:
:param upnl_ex_1:
"""
if trading_mode == TradingMode.SPOT:
if self.trading_mode == TradingMode.SPOT:
return None
elif (self.collateral is None):
raise OperationalException('Binance.collateral must be set for liquidation_price')
if not collateral:
if (not taker_fee_rate):
raise OperationalException(
"Parameter collateral is required by liquidation_price when trading_mode is "
f"{trading_mode}"
f"Parameter taker_fee_rate is required by {self.name}.liquidation_price"
)
return self.liquidation_price_helper(
open_rate=open_rate,
is_short=is_short,
leverage=leverage,
mm_ratio=mm_ratio,
position=position,
trading_mode=trading_mode,
collateral=collateral,
maintenance_amt=maintenance_amt,
wallet_balance=wallet_balance,
taker_fee_rate=taker_fee_rate,
mm_ex_1=mm_ex_1,
upnl_ex_1=upnl_ex_1,
)
if self.trading_mode == TradingMode.FUTURES and self.collateral == Collateral.ISOLATED:
# if is_inverse:
# raise OperationalException(
# "Freqtrade does not support inverse contracts at the moment")
def liquidation_price_helper(
self,
open_rate: float, # Entry price of position
is_short: bool,
leverage: float,
mm_ratio: float,
position: float, # Absolute value of position size
wallet_balance: float, # Or margin balance
trading_mode: TradingMode,
collateral: Collateral,
taker_fee_rate: Optional[float] = None, # (Gateio & Okex)
maintenance_amt: Optional[float] = None, # (Binance)
mm_ex_1: Optional[float] = 0.0, # (Binance) Cross only
upnl_ex_1: Optional[float] = 0.0, # (Binance) Cross only
) -> Optional[float]:
"""
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
value = wallet_balance / position
:param exchange_name:
:param open_rate: Entry price of position
:param is_short: True if the trade is a short, false otherwise
:param leverage: The amount of leverage on the trade
:param position: Absolute value of position size (in base currency)
:param mm_ratio:
:param trading_mode: SPOT, MARGIN, FUTURES, etc.
:param collateral: Either ISOLATED or CROSS
:param wallet_balance: Amount of collateral in the wallet being used to trade
Cross-Margin Mode: crossWalletBalance
Isolated-Margin Mode: isolatedWalletBalance
:param taker_fee_rate:
# * Not required by Gateio or OKX
:param maintenance_amt:
:param mm_ex_1:
:param upnl_ex_1:
"""
if trading_mode == TradingMode.SPOT:
return None
if (not taker_fee_rate):
raise OperationalException(
f"Parameter taker_fee_rate is required by {self.name}.liquidation_price"
)
if trading_mode == TradingMode.FUTURES and collateral == Collateral.ISOLATED:
# if is_inverse:
# raise OperationalException(
# "Freqtrade does not support inverse contracts at the moment")
value = wallet_balance / position
mm_ratio_taker = (mm_ratio + taker_fee_rate)
if is_short:
return (open_rate + value) / (1 + mm_ratio_taker)
else:
return (open_rate - value) / (1 - mm_ratio_taker)
mm_ratio_taker = (mm_ratio + taker_fee_rate)
if is_short:
return (open_rate + value) / (1 + mm_ratio_taker)
else:
raise OperationalException(
f"{self.name} does not support {collateral.value} {trading_mode.value}")
return (open_rate - value) / (1 - mm_ratio_taker)
else:
raise OperationalException(
f"{self.name} does not support {self.collateral.value} {self.trading_mode.value}")
def is_exchange_known_ccxt(exchange_name: str, ccxt_module: CcxtModuleType = None) -> bool:

View File

@@ -1,8 +1,6 @@
import logging
from typing import Dict, List, Optional, Tuple
from typing import Dict, List, Tuple
from freqtrade.enums import Collateral, TradingMode
from freqtrade.exceptions import OperationalException
from freqtrade.exchange import Exchange

View File

@@ -626,16 +626,13 @@ class FreqtradeBot(LoggingMixin):
isolated_liq = self.exchange.liquidation_price(
open_rate=open_rate,
is_short=is_short,
leverage=leverage,
trading_mode=self.trading_mode,
collateral=Collateral.ISOLATED,
mm_ex_1=0.0,
upnl_ex_1=0.0,
mm_ratio=mm_ratio,
position=amount,
wallet_balance=(amount * open_rate)/leverage, # TODO: Update for cross
taker_fee_rate=taker_fee_rate,
maintenance_amt=maintenance_amt,
mm_ratio=mm_ratio,
taker_fee_rate=taker_fee_rate
mm_ex_1=0.0,
upnl_ex_1=0.0,
)
else:
isolated_liq = self.exchange.get_liquidation_price(pair)