liquidation_price formula organize and comment clean up

This commit is contained in:
Sam Germain 2022-01-13 04:33:34 -06:00
parent 387a9fbf36
commit 7abffee755

View File

@ -12,69 +12,59 @@ def liquidation_price(
trading_mode: TradingMode, trading_mode: TradingMode,
mm_ratio: float, mm_ratio: float,
collateral: Optional[Collateral] = Collateral.ISOLATED, collateral: Optional[Collateral] = Collateral.ISOLATED,
maintenance_amt: Optional[float] = None, # (Binance)
# Binance position: Optional[float] = None, # (Binance and Gateio) Absolute value of position size
maintenance_amt: Optional[float] = None, wallet_balance: Optional[float] = None, # (Binance and Gateio)
taker_fee_rate: Optional[float] = None, # (Gateio & Okex)
# Binance and Gateio liability: Optional[float] = None, # (Okex)
wallet_balance: Optional[float] = None, interest: Optional[float] = None, # (Okex)
position: Optional[float] = None, # Absolute value of position size position_assets: Optional[float] = None, # * (Okex) Might be same as position
mm_ex_1: Optional[float] = 0.0, # (Binance) Cross only
# Gateio & Okex upnl_ex_1: Optional[float] = 0.0, # (Binance) Cross only
taker_fee_rate: Optional[float] = None,
# Okex
liability: Optional[float] = None,
interest: Optional[float] = None,
position_assets: Optional[float] = None, # * Might be same as position
# * Cross only
mm_ex_1: Optional[float] = 0.0, # Cross only
upnl_ex_1: Optional[float] = 0.0, # Cross only
) -> Optional[float]: ) -> Optional[float]:
''' """
wallet_balance :param exchange_name:
In Cross margin mode, WB is crossWalletBalance :param open_rate: (EP1) Entry price of position
In Isolated margin mode, WB is isolatedWalletBalance of the isolated position, :param is_short: True if the trade is a short, false otherwise
TMM=0, UPNL=0, substitute the position quantity, MMR, cum into the formula to calculate. :param leverage: The amount of leverage on the trade
Under the cross margin mode, the same ticker/symbol, :param trading_mode: SPOT, MARGIN, FUTURES, etc.
both long and short position share the same liquidation price except in the isolated mode. :param position: Absolute value of position size (in base currency)
Under the isolated mode, each isolated position will have different liquidation prices :param mm_ratio: (MMR)
depending on the margin allocated to the positions. Okex: [assets in the position - (liability +interest) * mark price] /
position (maintenance margin + liquidation fee)
Absolute value of position size (in base currency)
# Binance
maintenance_amt (cumb)
Maintenance Amount of position
# Gateio & okex & binance
mm_ratio
[assets in the position - (liability +interest) * mark price] /
(maintenance margin + liquidation fee) (okex)
# * Note: Binance's formula specifies maintenance margin rate which is mm_ratio * 100% # * Note: Binance's formula specifies maintenance margin rate which is mm_ratio * 100%
:param collateral: Either ISOLATED or CROSS
# Gateio & okex # * Binance
taker_fee_rate :param maintenance_amt: (CUM) Maintenance Amount of position
# Okex # * Binance and Gateio
liability :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 Initial liabilities + deducted interest
Long positions: Liability is calculated in quote currency. Long positions: Liability is calculated in quote currency.
Short positions: Liability is calculated in trading currency. Short positions: Liability is calculated in trading currency.
interest :param interest:
Interest that has not been deducted yet. Interest that has not been deducted yet.
position_assets :param position_assets:
Total position assets on-hold by pending order Total position assets on-hold by pending order
# * Cross only # * Cross only (Binance)
mm_ex_1 :param mm_ex_1: (TMM)
Maintenance Margin of all other contracts, excluding Contract 1 Cross-Margin Mode: Maintenance Margin of all other contracts, excluding Contract 1
If it is an isolated margin mode, then TMM=0UPNL=0 Isolated-Margin Mode: 0
upnl_ex_1 :param upnl_ex_1: (UPNL)
Unrealized PNL of all other contracts, excluding Contract 1 Cross-Margin Mode: Unrealized PNL of all other contracts, excluding Contract 1.
If it is an isolated margin mode, then UPNL=0 Isolated-Margin Mode: 0
''' """
if trading_mode == TradingMode.SPOT: if trading_mode == TradingMode.SPOT:
return None return None
@ -85,20 +75,14 @@ def liquidation_price(
) )
if exchange_name.lower() == "binance": if exchange_name.lower() == "binance":
if ( if (wallet_balance is None or maintenance_amt is None or position is None):
wallet_balance is None or
# mm_ex_1 is None or # * Cross only # mm_ex_1 is None or # * Cross only
# upnl_ex_1 is None or # * Cross only # upnl_ex_1 is None or # * Cross only
maintenance_amt is None or
position is None or
mm_ratio is None
):
raise OperationalException( raise OperationalException(
f"Parameters wallet_balance, mm_ex_1, upnl_ex_1, " f"Parameters wallet_balance, maintenance_amt, position"
f"maintenance_amt, position, mm_ratio " f"are required by liquidation_price when exchange is {exchange_name.lower()}"
f"is required by liquidation_price when exchange is {exchange_name.lower()}") )
# Suppress incompatible type "Optional[...]"; expected "..." as the check exists above.
# Suppress incompatible type "Optional[float]"; expected "float" as the check exists above.
return binance( return binance(
open_rate=open_rate, open_rate=open_rate,
is_short=is_short, is_short=is_short,
@ -111,21 +95,12 @@ def liquidation_price(
maintenance_amt=maintenance_amt, # type: ignore maintenance_amt=maintenance_amt, # type: ignore
position=position, position=position,
mm_ratio=mm_ratio, mm_ratio=mm_ratio,
) # type: ignore )
elif exchange_name.lower() == "kraken":
return kraken(open_rate, is_short, leverage, trading_mode, collateral)
elif exchange_name.lower() == "ftx":
return ftx(open_rate, is_short, leverage, trading_mode, collateral)
elif exchange_name.lower() == "gateio": elif exchange_name.lower() == "gateio":
if ( if (not wallet_balance or not position or not taker_fee_rate):
not wallet_balance or
not position or
not mm_ratio or
not taker_fee_rate
):
raise OperationalException( raise OperationalException(
f"{exchange_name} {collateral} {trading_mode} requires parameters " f"Parameters wallet_balance, position, taker_fee_rate"
f"wallet_balance, contract_size, num_contracts, mm_ratio and taker_fee" f"are required by liquidation_price when exchange is {exchange_name.lower()}"
) )
else: else:
return gateio( return gateio(
@ -139,16 +114,10 @@ def liquidation_price(
taker_fee_rate=taker_fee_rate taker_fee_rate=taker_fee_rate
) )
elif exchange_name.lower() == "okex": elif exchange_name.lower() == "okex":
if ( if (not liability or not interest or not taker_fee_rate or not position_assets):
not mm_ratio or
not liability or
not interest or
not taker_fee_rate or
not position_assets
):
raise OperationalException( raise OperationalException(
f"{exchange_name} {collateral} {trading_mode} requires parameters " f"Parameters liability, interest, taker_fee_rate, position_assets"
f"mm_ratio, liability, interest, taker_fee_rate, position_assets" f"are required by liquidation_price when exchange is {exchange_name.lower()}"
) )
else: else:
return okex( return okex(
@ -161,9 +130,11 @@ def liquidation_price(
taker_fee_rate=taker_fee_rate, taker_fee_rate=taker_fee_rate,
position_assets=position_assets, position_assets=position_assets,
) )
raise OperationalException( elif exchange_name.lower() == "ftx":
f"liquidation_price is not implemented for {exchange_name}" return ftx(open_rate, is_short, leverage, trading_mode, collateral)
) elif exchange_name.lower() == "kraken":
return kraken(open_rate, is_short, leverage, trading_mode, collateral)
raise OperationalException(f"liquidation_price is not implemented for {exchange_name}")
def exception( def exception(
@ -172,10 +143,10 @@ def exception(
collateral: Collateral, collateral: Collateral,
): ):
""" """
Raises an exception if exchange used doesn't support desired leverage mode Raises an exception if exchange used doesn't support desired leverage mode
:param exchange: Name of the exchange :param exchange: Name of the exchange
:param trading_mode: spot, margin, futures :param trading_mode: spot, margin, futures
:param collateral: cross, isolated :param collateral: cross, isolated
""" """
raise OperationalException( raise OperationalException(
@ -187,132 +158,79 @@ def binance(
is_short: bool, is_short: bool,
leverage: float, leverage: float,
trading_mode: TradingMode, trading_mode: TradingMode,
mm_ratio: float,
collateral: Collateral, collateral: Collateral,
maintenance_amt: float,
wallet_balance: float, wallet_balance: float,
position: float,
mm_ex_1: float, mm_ex_1: float,
upnl_ex_1: float, upnl_ex_1: float,
maintenance_amt: float,
position: float,
mm_ratio: float,
): ):
""" """
Calculates the liquidation price on Binance MARGIN: https://www.binance.com/en/support/faq/f6b010588e55413aa58b7d63ee0125ed
PERPETUAL: https://www.binance.com/en/support/faq/b3c689c1f50a44cabb3a84e663b81d93
:param open_rate: (EP1) Entry Price of position (one-way mode)
:param is_short: true or false :param is_short: true or false
:param leverage: leverage in float :param leverage: leverage in float
:param trading_mode: spot, margin, futures :param trading_mode: SPOT, MARGIN, FUTURES
:param collateral: cross, isolated :param mm_ratio: (MMR) Maintenance margin rate of position (one-way mode)
:param wallet_balance: Wallet Balance is crossWalletBalance in Cross-Margin Mode. :param collateral: CROSS, ISOLATED
Wallet Balance is isolatedWalletBalance in Isolated Margin Mode :param maintenance_amt: (CUM) Maintenance Amount of position (one-way mode)
:param mm_ex_1: Maintenance Margin of all other contracts,
excluding Contract 1. If it is an isolated margin mode, then TMM=0
:param upnl_ex_1: Unrealized PNL of all other contracts, excluding Contract 1.
If it is an isolated margin mode, then UPNL=0
:param maintenance_amt: Maintenance Amount of position (one-way mode)
:param position: Absolute value of position size (one-way mode) :param position: Absolute value of position size (one-way mode)
:param open_rate: Entry Price of position (one-way mode) :param wallet_balance: (WB)
:param mm_ratio: Maintenance margin rate of position (one-way mode) Cross-Margin Mode: crossWalletBalance
Isolated-Margin Mode: isolatedWalletBalance
TMM=0, UPNL=0, substitute the position quantity, MMR, cum into the formula to calculate.
Under the cross margin mode, the same ticker/symbol,
both long and short position share the same liquidation price except in isolated mode.
Under the isolated mode, each isolated position will have different liquidation prices
depending on the margin allocated to the positions.
: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
""" """
wb = wallet_balance
tmm_1 = 0.0 if collateral == Collateral.ISOLATED else mm_ex_1
upnl_1 = 0.0 if collateral == Collateral.ISOLATED else upnl_ex_1
cum_b = maintenance_amt
side_1 = -1 if is_short else 1 side_1 = -1 if is_short else 1
position = abs(position) position = abs(position)
ep1 = open_rate cross_vars = upnl_ex_1 - mm_ex_1 if collateral == Collateral.CROSS else 0.0
mmr_b = mm_ratio
if trading_mode == TradingMode.MARGIN and collateral == Collateral.CROSS: if trading_mode == TradingMode.MARGIN and collateral == Collateral.CROSS:
# https://www.binance.com/en/support/faq/f6b010588e55413aa58b7d63ee0125ed # ! Not Implemented
exception("binance", trading_mode, collateral) exception("binance", trading_mode, collateral)
elif trading_mode == TradingMode.FUTURES and collateral == Collateral.ISOLATED: if trading_mode == TradingMode.FUTURES:
# https://www.binance.com/en/support/faq/b3c689c1f50a44cabb3a84e663b81d93 return (wallet_balance + cross_vars + maintenance_amt - (side_1 * position * open_rate)) / (
# Liquidation Price of USDⓈ-M Futures Contracts Isolated (position * mm_ratio) - (side_1 * position))
# Isolated margin mode, then TMM=0UPNL=0
return (wb + cum_b - side_1 * position * ep1) / (
position * mmr_b - side_1 * position)
elif trading_mode == TradingMode.FUTURES and collateral == Collateral.CROSS:
# https://www.binance.com/en/support/faq/b3c689c1f50a44cabb3a84e663b81d93
# Liquidation Price of USDⓈ-M Futures Contracts Cross
# Isolated margin mode, then TMM=0UPNL=0
# * Untested
return (wb - tmm_1 + upnl_1 + cum_b - side_1 * position * ep1) / (
position * mmr_b - side_1 * position)
# If nothing was returned
exception("binance", trading_mode, collateral) exception("binance", trading_mode, collateral)
def kraken(
open_rate: float,
is_short: bool,
leverage: float,
trading_mode: TradingMode,
collateral: Collateral
# ...
):
"""
Calculates the liquidation price on Kraken
:param trading_mode: spot, margin, futures
:param collateral: cross, isolated
"""
if collateral == Collateral.CROSS:
if trading_mode == TradingMode.MARGIN:
exception("kraken", trading_mode, collateral)
# https://support.kraken.com/hc/en-us/articles/203325763-Margin-Call-Level-and-Margin-Liquidation-Level
elif trading_mode == TradingMode.FUTURES:
exception("kraken", trading_mode, collateral)
# If nothing was returned
exception("kraken", trading_mode, collateral)
def ftx(
open_rate: float,
is_short: bool,
leverage: float,
trading_mode: TradingMode,
collateral: Collateral
# ...
):
"""
Calculates the liquidation price on FTX
:param trading_mode: spot, margin, futures
:param collateral: cross, isolated
"""
if collateral == Collateral.CROSS:
exception("ftx", trading_mode, collateral)
# If nothing was returned
exception("ftx", trading_mode, collateral)
def gateio( def gateio(
open_rate: float, open_rate: float,
is_short: bool, is_short: bool,
trading_mode: TradingMode, trading_mode: TradingMode,
collateral: Collateral,
wallet_balance: float,
position: float,
mm_ratio: float, mm_ratio: float,
collateral: Collateral,
position: float,
wallet_balance: float,
taker_fee_rate: float, taker_fee_rate: float,
is_inverse: bool = False is_inverse: bool = False
): ):
""" """
Calculates the liquidation price on Gate.io PERPETUAL: https://www.gate.io/help/futures/perpetual/22160/calculation-of-liquidation-price
:param open_rate: Entry Price of position :param open_rate: Entry Price of position
:param is_short: True for short trades :param is_short: True for short trades
:param trading_mode: spot, margin, futures :param trading_mode: SPOT, MARGIN, FUTURES
:param collateral: cross, isolated :param mm_ratio: Viewed in contract details
:param wallet_balance: Also called margin :param collateral: CROSS, ISOLATED
:param position: size of position in base currency :param position: size of position in base currency
contract_size / num_contracts contract_size / num_contracts
contract_size: How much one contract is worth contract_size: How much one contract is worth
num_contracts: Also called position num_contracts: Also called position
:param mm_ratio: Viewed in contract details :param wallet_balance: Also called margin
:param taker_fee_rate: :param taker_fee_rate:
:param is_inverse: True if settle currency matches base currency :param is_inverse: True if settle currency matches base currency
@ -320,16 +238,13 @@ def gateio(
'±' in the formula refers to the direction of the contract, '±' in the formula refers to the direction of the contract,
go long refers to '-' go long refers to '-'
go short refers to '+' go short refers to '+'
Position refers to the number of contracts.
Maintenance Margin Ratio and Contract Multiplier can be viewed in the Contract Details.
https://www.gate.io/help/futures/perpetual/22160/calculation-of-liquidation-price
""" """
if trading_mode == TradingMode.FUTURES and collateral == Collateral.ISOLATED: if trading_mode == TradingMode.FUTURES and collateral == Collateral.ISOLATED:
if is_inverse: if is_inverse:
raise OperationalException( # ! Not implemented
"Freqtrade does not support inverse contracts at the moment") raise OperationalException("Freqtrade does not support inverse contracts at the moment")
value = wallet_balance / position value = wallet_balance / position
mm_ratio_taker = (mm_ratio + taker_fee_rate) mm_ratio_taker = (mm_ratio + taker_fee_rate)
@ -344,24 +259,40 @@ def gateio(
def okex( def okex(
is_short: bool, is_short: bool,
trading_mode: TradingMode, trading_mode: TradingMode,
mm_ratio: float,
collateral: Collateral, collateral: Collateral,
taker_fee_rate: float,
liability: float, liability: float,
interest: float, interest: float,
mm_ratio: float,
taker_fee_rate: float,
position_assets: float position_assets: float
): ):
''' '''
https://www.okex.com/support/hc/en-us/articles/ PERPETUAL: https://www.okex.com/support/hc/en-us/articles/
360053909592-VI-Introduction-to-the-isolated-mode-of-Single-Multi-currency-Portfolio-margin 360053909592-VI-Introduction-to-the-isolated-mode-of-Single-Multi-currency-Portfolio-margin
Initial liabilities + deducted interest :param is_short: True if the position is short, false otherwise
Long positions: Liability is calculated in quote currency. :param trading_mode: SPOT, MARGIN, FUTURES
Short positions: Liability is calculated in trading currency. :param mm_ratio:
interest: Interest that has not been deducted yet. long: [position_assets - (liability + interest) / mark_price] / (maintenance_margin + fees)
Margin ratio short: [position_assets - (liability + interest) * mark_price] / (maintenance_margin + fees)
Long: [position_assets - (liability + interest) / mark_price] / (maintenance_margin + fees) :param collateral: CROSS, ISOLATED
Short: [position_assets - (liability + interest) * mark_price] / (maintenance_margin + fees) :param taker_fee_rate:
:param liability: Initial liabilities + deducted interest
long: Liability is calculated in quote currency
short: 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
Total: The number of positive assets on the position (including margin).
long: with trading currency as position asset.
short: with quote currency as position asset.
Est. liquidation price
long: (liability + interest* (1 + maintenance margin ratio) *
(1 + taker fee rate) / position assets
short: (liability + interest* (1 + maintenance margin ratio) *
(1 + taker fee rate)
''' '''
if trading_mode == TradingMode.FUTURES and collateral == Collateral.ISOLATED: if trading_mode == TradingMode.FUTURES and collateral == Collateral.ISOLATED:
if is_short: if is_short:
@ -371,18 +302,55 @@ def okex(
else: else:
exception("okex", trading_mode, collateral) exception("okex", trading_mode, collateral)
# if __name__ == '__main__':
# print(liquidation_price( def ftx(
# "binance", open_rate: float,
# 32481.980, is_short: bool,
# False, leverage: float,
# 1, trading_mode: TradingMode,
# TradingMode.FUTURES, collateral: Collateral
# Collateral.ISOLATED, # ...
# 1535443.01, ):
# 356512.508, """
# 0.0, # ! Not Implemented
# 16300.000, Calculates the liquidation price on FTX
# 109.488, :param open_rate: Entry price of position
# 0.025 :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 collateral: Either ISOLATED or CROSS
"""
if collateral == Collateral.CROSS:
exception("ftx", trading_mode, collateral)
# If nothing was returned
exception("ftx", trading_mode, collateral)
def kraken(
open_rate: float,
is_short: bool,
leverage: float,
trading_mode: TradingMode,
collateral: Collateral
# ...
):
"""
# ! Not Implemented
MARGIN: https://support.kraken.com/hc/en-us/articles/203325763-Margin-Call-Level-and-Margin-Liquidation-Level
: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 collateral: Either ISOLATED or CROSS
"""
if collateral == Collateral.CROSS:
if trading_mode == TradingMode.MARGIN:
exception("kraken", trading_mode, collateral)
elif trading_mode == TradingMode.FUTURES:
exception("kraken", trading_mode, collateral)
# If nothing was returned
exception("kraken", trading_mode, collateral)