moved liquidation_price method to exchange classes

This commit is contained in:
Sam Germain
2022-01-22 20:03:38 -06:00
parent 5a97760bd1
commit 0c13e387fe
10 changed files with 358 additions and 527 deletions

View File

@@ -2015,6 +2015,114 @@ class Exchange:
# TODO-lev: return the real amounts
return (0, 0.4)
def liquidation_price(
self,
open_rate: float, # Entry price of position
is_short: bool,
leverage: float,
trading_mode: TradingMode,
mm_ratio: float,
collateral: Optional[Collateral] = Collateral.ISOLATED,
maintenance_amt: Optional[float] = None, # (Binance)
position: Optional[float] = None, # (Binance and Gateio) Absolute value of position size
wallet_balance: Optional[float] = None, # (Binance and Gateio)
taker_fee_rate: Optional[float] = None, # (Gateio & Okex)
liability: Optional[float] = None, # (Okex)
interest: Optional[float] = None, # (Okex)
position_assets: Optional[float] = None, # * (Okex) Might be same as position
mm_ex_1: Optional[float] = 0.0, # (Binance) Cross only
upnl_ex_1: Optional[float] = 0.0, # (Binance) Cross only
) -> Optional[float]:
"""
: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 trading_mode: SPOT, MARGIN, FUTURES, etc.
:param position: Absolute value of position size (in base currency)
: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 collateral: Either ISOLATED or CROSS
# * Binance
:param maintenance_amt: (CUM) Maintenance Amount of position
# * Binance and Gateio
:param wallet_balance: (WB)
Cross-Margin Mode: crossWalletBalance
Isolated-Margin Mode: isolatedWalletBalance
:param position: Absolute value of position size (in base currency)
# * Gateio & Okex
:param taker_fee_rate:
# * Okex
:param liability:
Initial liabilities + deducted interest
• Long positions: Liability is calculated in quote currency.
• Short positions: Liability is calculated in trading currency.
:param interest:
Interest that has not been deducted yet.
:param position_assets:
Total position assets on-hold by pending order
# * 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
"""
if trading_mode == TradingMode.SPOT:
return None
if not collateral:
raise OperationalException(
"Parameter collateral is required by liquidation_price when trading_mode is "
f"{trading_mode}"
)
return self.liquidation_price_helper(
open_rate,
is_short,
leverage,
trading_mode,
mm_ratio,
collateral,
maintenance_amt,
position,
wallet_balance,
taker_fee_rate,
liability,
interest,
position_assets,
mm_ex_1,
upnl_ex_1,
)
def liquidation_price_helper(
self,
open_rate: float,
is_short: bool,
leverage: float,
trading_mode: TradingMode,
mm_ratio: float,
collateral: Collateral,
maintenance_amt: Optional[float] = None,
position: Optional[float] = None,
wallet_balance: Optional[float] = None,
taker_fee_rate: Optional[float] = None,
liability: Optional[float] = None,
interest: Optional[float] = None,
position_assets: Optional[float] = None,
mm_ex_1: Optional[float] = 0.0,
upnl_ex_1: Optional[float] = 0.0,
) -> Optional[float]:
raise OperationalException(f"liquidation_price is not implemented for {self.name}")
def is_exchange_known_ccxt(exchange_name: str, ccxt_module: CcxtModuleType = None) -> bool:
return exchange_name in ccxt_exchanges(ccxt_module)

View File

@@ -51,3 +51,78 @@ class Gateio(Exchange):
"""
info = self.markets[pair]['info']
return (float(info['maintenance_rate']), None)
def liquidation_price_helper(
self,
open_rate: float, # Entry price of position
is_short: bool,
leverage: float,
trading_mode: TradingMode,
mm_ratio: float,
collateral: Collateral,
maintenance_amt: Optional[float] = None, # (Binance)
position: Optional[float] = None, # (Binance and Gateio) Absolute value of position size
wallet_balance: Optional[float] = None, # (Binance and Gateio)
taker_fee_rate: Optional[float] = None, # (Gateio & Okex)
liability: Optional[float] = None, # (Okex)
interest: Optional[float] = None, # (Okex)
position_assets: Optional[float] = None, # * (Okex) Might be same as position
mm_ex_1: Optional[float] = 0.0, # (Binance) Cross only
upnl_ex_1: Optional[float] = 0.0, # (Binance) Cross only
) -> Optional[float]:
"""
PERPETUAL: https://www.gate.io/help/futures/perpetual/22160/calculation-of-liquidation-price
: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 trading_mode: SPOT, MARGIN, FUTURES, etc.
:param position: Absolute value of position size (in base currency)
:param mm_ratio:
:param collateral: Either ISOLATED or CROSS
:param maintenance_amt: # * Not required by Gateio
:param wallet_balance:
Cross-Margin Mode: crossWalletBalance
Isolated-Margin Mode: isolatedWalletBalance
:param position: Absolute value of position size (in base currency)
:param taker_fee_rate:
# * Not required by Gateio
:param liability:
:param interest:
:param position_assets:
:param mm_ex_1:
:param upnl_ex_1:
"""
if trading_mode == TradingMode.SPOT:
return None
if not collateral:
raise OperationalException(
"Parameter collateral is required by liquidation_price when trading_mode is "
f"{trading_mode}"
)
if (not wallet_balance or not position or not taker_fee_rate):
raise OperationalException(
"Parameters wallet_balance, position, taker_fee_rate"
"are required by Gateio.liquidation_price"
)
if trading_mode == TradingMode.FUTURES and collateral == Collateral.ISOLATED:
# if is_inverse:
# # ! Not implemented
# 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)
else:
raise OperationalException(
f"Gateio does not support {collateral.value} Mode {trading_mode.value} trading ")

View File

@@ -1,7 +1,8 @@
import logging
from typing import Dict, List, Tuple
from typing import Dict, List, Optional, Tuple
from freqtrade.enums import Collateral, TradingMode
from freqtrade.exceptions import OperationalException
from freqtrade.exchange import Exchange
@@ -26,3 +27,67 @@ class Okex(Exchange):
# (TradingMode.FUTURES, Collateral.CROSS),
# (TradingMode.FUTURES, Collateral.ISOLATED)
]
def liquidation_price_helper(
self,
open_rate: float, # Entry price of position
is_short: bool,
leverage: float,
trading_mode: TradingMode,
mm_ratio: float,
collateral: Collateral,
maintenance_amt: Optional[float] = None, # Not required
position: Optional[float] = None, # Not required
wallet_balance: Optional[float] = None, # Not required
taker_fee_rate: Optional[float] = None, # * required
liability: Optional[float] = None, # * required
interest: Optional[float] = None, # * required
position_assets: Optional[float] = None, # * required (Might be same as position)
mm_ex_1: Optional[float] = 0.0, # Not required
upnl_ex_1: Optional[float] = 0.0, # Not required
) -> Optional[float]:
"""
PERPETUAL: 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 is_short: True if the trade is a short, false otherwise
:param leverage: The amount of leverage on the trade
:param trading_mode: SPOT, MARGIN, FUTURES, etc.
:param position: Absolute value of position size (in base currency)
:param mm_ratio:
Okex: [assets in the position - (liability +interest) * mark price] /
(maintenance margin + liquidation fee)
:param collateral: Either ISOLATED or CROSS
:param maintenance_amt: # * Not required by Okex
:param wallet_balance: # * Not required by Okex
:param position: # * Not required by Okex
:param taker_fee_rate:
:param liability:
Initial liabilities + deducted interest
• Long positions: Liability is calculated in quote currency.
• Short positions: Liability is calculated in trading currency.
:param interest: Interest that has not been deducted yet.
:param position_assets: Total position assets on-hold by pending order
:param mm_ex_1: # * Not required by Okex
:param upnl_ex_1: # * Not required by Okex
"""
if (not liability or not interest or not taker_fee_rate or not position_assets):
raise OperationalException(
"Parameters liability, interest, taker_fee_rate, position_assets"
"are required by Okex.liquidation_price"
)
if trading_mode == TradingMode.FUTURES and collateral == Collateral.ISOLATED:
if is_short:
return (liability + interest) * (1 + mm_ratio) * (1 + taker_fee_rate)
else:
return (
(liability + interest) * (1 + mm_ratio) * (1 + taker_fee_rate) /
position_assets
)
else:
raise OperationalException(
f"Okex does not support {collateral.value} Mode {trading_mode.value} trading")