From 2b1a8f2fbbcb309af0c5028ea6a641c2ef37ddd1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 5 Mar 2022 13:57:54 +0100 Subject: [PATCH] Update binance stoploss to use correct stop order for futures --- freqtrade/exchange/binance.py | 1 + freqtrade/exchange/exchange.py | 5 +++++ tests/exchange/test_binance.py | 19 ++++++++++--------- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/freqtrade/exchange/binance.py b/freqtrade/exchange/binance.py index 8cd5ab9ed..6607c15b7 100644 --- a/freqtrade/exchange/binance.py +++ b/freqtrade/exchange/binance.py @@ -22,6 +22,7 @@ class Binance(Exchange): _ft_has: Dict = { "stoploss_on_exchange": True, "stoploss_order_types": {"limit": "stop_loss_limit"}, + "stoploss_order_types_futures": {"limit": "stop"}, "order_time_in_force": ['gtc', 'fok', 'ioc'], "time_in_force_parameter": "timeInForce", "ohlcv_candle_limit": 1000, diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index fca555abd..cf0ef62c0 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1011,6 +1011,11 @@ class Exchange: def _get_stop_order_type(self, user_order_type) -> Tuple[str, str]: available_order_Types: Dict[str, str] = self._ft_has["stoploss_order_types"] + if self.trading_mode == TradingMode.FUTURES: + # Optionally use different order type for stop order + available_order_Types = self._ft_has.get('stoploss_order_types_futures', + self._ft_has["stoploss_order_types"]) + if user_order_type in available_order_Types.keys(): ordertype = available_order_Types[user_order_type] else: diff --git a/tests/exchange/test_binance.py b/tests/exchange/test_binance.py index f6016a2fc..c3950e459 100644 --- a/tests/exchange/test_binance.py +++ b/tests/exchange/test_binance.py @@ -11,6 +11,7 @@ from tests.conftest import get_mock_coro, get_patched_exchange, log_has_re from tests.exchange.test_exchange import ccxt_exceptionhandlers +@pytest.mark.parametrize('trademode', [TradingMode.FUTURES, TradingMode.SPOT]) @pytest.mark.parametrize('limitratio,expected,side', [ (None, 220 * 0.99, "sell"), (0.99, 220 * 0.99, "sell"), @@ -19,16 +20,10 @@ from tests.exchange.test_exchange import ccxt_exceptionhandlers (0.99, 220 * 1.01, "buy"), (0.98, 220 * 1.02, "buy"), ]) -def test_stoploss_order_binance( - default_conf, - mocker, - limitratio, - expected, - side -): +def test_stoploss_order_binance(default_conf, mocker, limitratio, expected, side, trademode): api_mock = MagicMock() order_id = 'test_prod_buy_{}'.format(randint(0, 10 ** 6)) - order_type = 'stop_loss_limit' + order_type = 'stop_loss_limit' if trademode == TradingMode.SPOT else 'stop' api_mock.create_order = MagicMock(return_value={ 'id': order_id, @@ -37,6 +32,8 @@ def test_stoploss_order_binance( } }) default_conf['dry_run'] = False + default_conf['margin_mode'] = MarginMode.ISOLATED + default_conf['trading_mode'] = trademode mocker.patch('freqtrade.exchange.Exchange.amount_to_precision', lambda s, x, y: y) mocker.patch('freqtrade.exchange.Exchange.price_to_precision', lambda s, x, y: y) @@ -72,7 +69,11 @@ def test_stoploss_order_binance( assert api_mock.create_order.call_args_list[0][1]['amount'] == 1 # Price should be 1% below stopprice assert api_mock.create_order.call_args_list[0][1]['price'] == expected - assert api_mock.create_order.call_args_list[0][1]['params'] == {'stopPrice': 220} + if trademode == TradingMode.SPOT: + params_dict = {'stopPrice': 220} + else: + params_dict = {'stopPrice': 220, 'reduceOnly': True} + assert api_mock.create_order.call_args_list[0][1]['params'] == params_dict # test exception handling with pytest.raises(DependencyException):