From dd8cce00a42d1ff2e631f65e6188eb1d35d4b547 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Mon, 2 Aug 2021 20:05:48 -0600 Subject: [PATCH] Split tradingmode into tradingmode and collateral, moved functions out of liqformula class --- freqtrade/enums/__init__.py | 1 + freqtrade/enums/collateral.py | 9 ++ freqtrade/enums/liqformula.py | 124 ++++++++++++----------- freqtrade/enums/tradingmode.py | 8 +- tests/leverage/test_liquidation_price.py | 64 +++++++----- 5 files changed, 117 insertions(+), 89 deletions(-) create mode 100644 freqtrade/enums/collateral.py diff --git a/freqtrade/enums/__init__.py b/freqtrade/enums/__init__.py index 87e9dfb6b..8398c91f1 100644 --- a/freqtrade/enums/__init__.py +++ b/freqtrade/enums/__init__.py @@ -1,5 +1,6 @@ # flake8: noqa: F401 from freqtrade.enums.backteststate import BacktestState +from freqtrade.enums.collateral import Collateral from freqtrade.enums.interestmode import InterestMode from freqtrade.enums.liqformula import LiqFormula from freqtrade.enums.rpcmessagetype import RPCMessageType diff --git a/freqtrade/enums/collateral.py b/freqtrade/enums/collateral.py new file mode 100644 index 000000000..474189902 --- /dev/null +++ b/freqtrade/enums/collateral.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class Collateral(Enum): + """ + Bot application states + """ + CROSS = "cross" + ISOLATED = "isolated" diff --git a/freqtrade/enums/liqformula.py b/freqtrade/enums/liqformula.py index 0720fbd1e..48157f5c2 100644 --- a/freqtrade/enums/liqformula.py +++ b/freqtrade/enums/liqformula.py @@ -1,12 +1,14 @@ # from decimal import Decimal from enum import Enum -# from math import ceil -from typing import Optional +from freqtrade.enums.collateral import Collateral from freqtrade.enums.tradingmode import TradingMode from freqtrade.exceptions import OperationalException +# from math import ceil + + class LiqFormula(Enum): """Equations to calculate liquidation price""" @@ -15,72 +17,72 @@ class LiqFormula(Enum): FTX = "FTX" NONE = None - def _exception(self, trading_mode: TradingMode, freq_specific: Optional[bool] = True): - """ - Raises an exception if exchange used doesn't support desired leverage mode - :param trading_mode: cross, isolated, cross_futures or isolated_futures - :param freq_specific: - False if the exchange does not support this leverage mode - True if only freqtrade doesn't support it - """ - if freq_specific: - raise OperationalException( - f"Freqtrade does not support {trading_mode.value} on {self.name}") - else: - raise OperationalException(f"{self.name} does not support {trading_mode.value} trading") - - def _binance(self, trading_mode: TradingMode): - # TODO-lev: Additional arguments, fill in formulas - - if trading_mode == TradingMode.CROSS_MARGIN: - # TODO-lev: perform a calculation based on this formula - # https://www.binance.com/en/support/faq/f6b010588e55413aa58b7d63ee0125ed - self._exception(trading_mode) - elif trading_mode == TradingMode.ISOLATED_MARGIN: - self._exception(trading_mode) # Likely won't be implemented - elif trading_mode == TradingMode.CROSS_FUTURES: - # TODO-lev: perform a calculation based on this formula - # https://www.binance.com/en/support/faq/b3c689c1f50a44cabb3a84e663b81d93 - self._exception(trading_mode) - elif trading_mode == TradingMode.ISOLATED_FUTURES: - # TODO-lev: perform a calculation based on this formula - # https://www.binance.com/en/support/faq/b3c689c1f50a44cabb3a84e663b81d93 - self._exception(trading_mode) - else: - self._exception(trading_mode) - - def _kraken(self, trading_mode: TradingMode): - # TODO-lev: Additional arguments, fill in formulas - - if trading_mode == TradingMode.CROSS_MARGIN: - self._exception(trading_mode) - # TODO-lev: perform a calculation based on this formula - # https://support.kraken.com/hc/en-us/articles/203325763-Margin-Call-Level-and-Margin-Liquidation-Level - elif trading_mode == TradingMode.CROSS_FUTURES: - # TODO-lev: implement - self._exception(trading_mode) - elif trading_mode == TradingMode.ISOLATED_MARGIN or \ - trading_mode == TradingMode.ISOLATED_FUTURES: - self._exception(trading_mode, True) - else: - self._exception(trading_mode) - - def _ftx(self, trading_mode: TradingMode): - # TODO-lev: Additional arguments, fill in formulas - self._exception(trading_mode) - def __call__(self, **k): trading_mode: TradingMode = k['trading_mode'] - if trading_mode == TradingMode.SPOT or self.name == "NONE": return None + collateral: Collateral = k['collateral'] + if self.name == "BINANCE": - return self._binance(trading_mode) + return binance(trading_mode, collateral) elif self.name == "KRAKEN": - return self._kraken(trading_mode) + return kraken(trading_mode, collateral) elif self.name == "FTX": - return self._ftx(trading_mode) + return ftx(trading_mode, collateral) else: - self._exception(trading_mode) + exception(self.name, trading_mode, collateral) + + +def exception(name: str, trading_mode: TradingMode, collateral: Collateral): + """ + Raises an exception if exchange used doesn't support desired leverage mode + :param trading_mode: cross, isolated, cross_futures or isolated_futures + """ + raise OperationalException( + f"{name} does not support {collateral.value} {trading_mode.value} trading") + + +def binance(name: str, trading_mode: TradingMode, collateral: Collateral): + # TODO-lev: Additional arguments, fill in formulas + + if trading_mode == TradingMode.MARGIN and collateral == Collateral.CROSS: + # TODO-lev: perform a calculation based on this formula + # https://www.binance.com/en/support/faq/f6b010588e55413aa58b7d63ee0125ed + exception(name, trading_mode, collateral) + elif trading_mode == TradingMode.FUTURES and collateral == Collateral.CROSS: + # TODO-lev: perform a calculation based on this formula + # https://www.binance.com/en/support/faq/b3c689c1f50a44cabb3a84e663b81d93 + exception(name, trading_mode, collateral) + elif trading_mode == TradingMode.FUTURES and collateral == Collateral.ISOLATED: + # TODO-lev: perform a calculation based on this formula + # https://www.binance.com/en/support/faq/b3c689c1f50a44cabb3a84e663b81d93 + exception(name, trading_mode, collateral) + + # If nothing was returned + exception(name, trading_mode, collateral) + + +def kraken(name: str, trading_mode: TradingMode, collateral: Collateral): + # TODO-lev: Additional arguments, fill in formulas + + if collateral == Collateral.CROSS: + if trading_mode == TradingMode.MARGIN: + exception(name, trading_mode, collateral) + # TODO-lev: perform a calculation based on this formula + # https://support.kraken.com/hc/en-us/articles/203325763-Margin-Call-Level-and-Margin-Liquidation-Level + elif trading_mode == TradingMode.FUTURES: + exception(name, trading_mode, collateral) + + # If nothing was returned + exception(name, trading_mode, collateral) + + +def ftx(name: str, trading_mode: TradingMode, collateral: Collateral): + if collateral == Collateral.CROSS: + # TODO-lev: Additional arguments, fill in formulas + exception(name, trading_mode, collateral) + + # If nothing was returned + exception(name, trading_mode, collateral) diff --git a/freqtrade/enums/tradingmode.py b/freqtrade/enums/tradingmode.py index d8d1fec00..4a5756e4b 100644 --- a/freqtrade/enums/tradingmode.py +++ b/freqtrade/enums/tradingmode.py @@ -4,10 +4,8 @@ from enum import Enum class TradingMode(Enum): """ Enum to distinguish between - spot, cross margin, isolated margin, futures or any other trading method + spot, margin, futures or any other trading method """ SPOT = "spot" - CROSS_MARGIN = "cross margin" - ISOLATED_MARGIN = "isolated margin" - CROSS_FUTURES = "cross futures" - ISOLATED_FUTURES = "isolated futures" + MARGIN = "margin" + FUTURES = "futures" diff --git a/tests/leverage/test_liquidation_price.py b/tests/leverage/test_liquidation_price.py index ba3005794..03e3b0950 100644 --- a/tests/leverage/test_liquidation_price.py +++ b/tests/leverage/test_liquidation_price.py @@ -1,4 +1,4 @@ -from freqtrade.enums import LiqFormula, TradingMode +from freqtrade.enums import Collateral, LiqFormula, TradingMode # from freqtrade.exceptions import OperationalException @@ -7,37 +7,55 @@ from freqtrade.enums import LiqFormula, TradingMode def test_liquidation_formula(): spot = TradingMode.SPOT - cross_margin = TradingMode.CROSS_MARGIN - isolated_margin = TradingMode.ISOLATED_MARGIN - cross_futures = TradingMode.CROSS_FUTURES - isolated_futures = TradingMode.ISOLATED_FUTURES + margin = TradingMode.MARGIN + futures = TradingMode.FUTURES + cross = Collateral.CROSS + isolated = Collateral.ISOLATED + + # NONE assert LiqFormula.NONE(trading_mode=spot) is None - assert LiqFormula.NONE(trading_mode=cross_margin) is None - assert LiqFormula.NONE(trading_mode=isolated_margin) is None - assert LiqFormula.NONE(trading_mode=cross_futures) is None - assert LiqFormula.NONE(trading_mode=isolated_futures) is None + assert LiqFormula.NONE(trading_mode=margin, collateral=cross) is None + assert LiqFormula.NONE(trading_mode=margin, collateral=isolated) is None + assert LiqFormula.NONE(trading_mode=futures, collateral=cross) is None + assert LiqFormula.NONE(trading_mode=futures, collateral=isolated) is None + # Binance assert LiqFormula.BINANCE(trading_mode=spot) is None + assert LiqFormula.BINANCE(trading_mode=spot, collateral=cross) is None + assert LiqFormula.BINANCE(trading_mode=spot, collateral=isolated) is None # TODO-lev: Uncomment these assertions and make them real calculation tests # TODO-lev: Replace 1.0 with real value - # assert LiqFormula.BINANCE(trading_mode=cross_margin) == 1.0 - # assert LiqFormula.BINANCE(trading_mode=isolated_margin) == 1.0 - # assert LiqFormula.BINANCE(trading_mode=cross_futures) == 1.0 - # assert LiqFormula.BINANCE(trading_mode=isolated_futures) == 1.0 + # assert LiqFormula.BINANCE(trading_mode=margin, collateral=cross) == 1.0 + # assert LiqFormula.BINANCE(trading_mode=margin, collateral=isolated) == 1.0 + # assert LiqFormula.BINANCE(trading_mode=futures, collateral=cross) == 1.0 + # Binance supports isolated margin, but freqtrade likely won't for a while on Binance + # assert LiqFormula.BINANCE(trading_mode=margin, collateral=isolated) == 1.0 + # Kraken assert LiqFormula.KRAKEN(trading_mode=spot) is None + assert LiqFormula.KRAKEN(trading_mode=spot, collateral=cross) is None + assert LiqFormula.KRAKEN(trading_mode=spot, collateral=isolated) is None # TODO-lev: Uncomment these assertions and make them real calculation tests - # assert LiqFormula.KRAKEN(trading_mode=cross_margin) == 1.0 - # LiqFormula.KRAKEN(trading_mode=isolated_margin) - # asset exception thrown #TODO-lev: Check that exception is thrown - # assert LiqFormula.KRAKEN(trading_mode=cross_futures) == 1.0 - # LiqFormula.KRAKEN(trading_mode=isolated_futures) - # asset exception thrown #TODO-lev: Check that exception is thrown + # assert LiqFormula.KRAKEN(trading_mode=margin, collateral=cross) == 1.0 + # assert LiqFormula.KRAKEN(trading_mode=margin, collateral=isolated) == 1.0 + # LiqFormula.KRAKEN(trading_mode=futures, collateral=cross) + # assert exception thrown #TODO-lev: Check that exception is thrown + + # LiqFormula.KRAKEN(trading_mode=futures, collateral=isolated) + # assert exception thrown #TODO-lev: Check that exception is thrown + + # FTX assert LiqFormula.FTX(trading_mode=spot) is None + assert LiqFormula.FTX(trading_mode=spot, collateral=cross) is None + assert LiqFormula.FTX(trading_mode=spot, collateral=isolated) is None # TODO-lev: Uncomment these assertions and make them real calculation tests - # assert LiqFormula.FTX(trading_mode=cross_margin) == 1.0 - # assert LiqFormula.FTX(trading_mode=isolated_margin) == 1.0 - # assert LiqFormula.FTX(trading_mode=cross_futures) == 1.0 - # assert LiqFormula.FTX(trading_mode=isolated_futures) == 1.0 + # assert LiqFormula.FTX(trading_mode=margin, collateral=cross) == 1.0 + # assert LiqFormula.FTX(trading_mode=margin, collateral=isolated) == 1.0 + + # LiqFormula.KRAKEN(trading_mode=futures, collateral=cross) + # assert exception thrown #TODO-lev: Check that exception is thrown + + # LiqFormula.KRAKEN(trading_mode=futures, collateral=isolated) + # assert exception thrown #TODO-lev: Check that exception is thrown