From b3477c4802a5b79d254de7398f17946ed6a264ec Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Tue, 1 Feb 2022 21:57:07 -0600 Subject: [PATCH 1/5] _api.fetch_funding_history argument pair->symbol --- freqtrade/exchange/exchange.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 4c5cf0226..5d7a75a42 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1786,7 +1786,7 @@ class Exchange: try: funding_history = self._api.fetch_funding_history( - pair=pair, + symbol=pair, since=since ) return sum(fee['amount'] for fee in funding_history) From 386be2d889287674c0acd5d75a74ae2383bd58c9 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Tue, 1 Feb 2022 22:23:05 -0600 Subject: [PATCH 2/5] set reduceOnly for futures exit orders --- freqtrade/exchange/binance.py | 12 ++++++++++-- freqtrade/exchange/exchange.py | 29 ++++++++++++++++++++++++----- freqtrade/exchange/ftx.py | 2 ++ freqtrade/exchange/kraken.py | 12 ++++++++++-- freqtrade/freqtradebot.py | 2 ++ 5 files changed, 48 insertions(+), 9 deletions(-) diff --git a/freqtrade/exchange/binance.py b/freqtrade/exchange/binance.py index 7d50e2c57..c04947bdf 100644 --- a/freqtrade/exchange/binance.py +++ b/freqtrade/exchange/binance.py @@ -86,14 +86,22 @@ class Binance(Exchange): try: params = self._params.copy() params.update({'stopPrice': stop_price}) + if self.trading_mode == TradingMode.FUTURES: + params.update({'reduceOnly': True}) amount = self.amount_to_precision(pair, amount) rate = self.price_to_precision(pair, rate) self._lev_prep(pair, leverage) - order = self._api.create_order(symbol=pair, type=ordertype, side=side, - amount=amount, price=rate, params=params) + order = self._api.create_order( + symbol=pair, + type=ordertype, + side=side, + amount=amount, + price=rate, + params=params + ) logger.info('stoploss limit order added for %s. ' 'stop price: %s. limit: %s', pair, stop_price, rate) self._log_exchange_response('create_stoploss_order', order) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 5d7a75a42..b28858ebd 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -882,21 +882,38 @@ class Exchange: self.set_margin_mode(pair, self.margin_mode) self._set_leverage(leverage, pair) - def _get_params(self, ordertype: str, leverage: float, time_in_force: str = 'gtc') -> Dict: + def _get_params( + self, + ordertype: str, + leverage: float, + reduceOnly: bool, + time_in_force: str = 'gtc', + ) -> Dict: params = self._params.copy() if time_in_force != 'gtc' and ordertype != 'market': param = self._ft_has.get('time_in_force_parameter', '') params.update({param: time_in_force}) + if reduceOnly: + params.update({'reduceOnly': True}) return params - def create_order(self, pair: str, ordertype: str, side: str, amount: float, - rate: float, leverage: float = 1.0, time_in_force: str = 'gtc') -> Dict: + def create_order( + self, + pair: str, + ordertype: str, + side: str, + amount: float, + rate: float, + reduceOnly: bool = False, + leverage: float = 1.0, + time_in_force: str = 'gtc', + ) -> Dict: # TODO-lev: remove default for leverage if self._config['dry_run']: dry_order = self.create_dry_run_order(pair, ordertype, side, amount, rate, leverage) return dry_order - params = self._get_params(ordertype, leverage, time_in_force) + params = self._get_params(ordertype, leverage, reduceOnly, time_in_force) try: # Set the precision for amount and price(rate) as accepted by the exchange @@ -905,7 +922,9 @@ class Exchange: or self._api.options.get("createMarketBuyOrderRequiresPrice", False)) rate_for_order = self.price_to_precision(pair, rate) if needs_price else None - self._lev_prep(pair, leverage) + if not reduceOnly: + self._lev_prep(pair, leverage) + order = self._api.create_order( pair, ordertype, diff --git a/freqtrade/exchange/ftx.py b/freqtrade/exchange/ftx.py index 88e906a56..143be73ac 100644 --- a/freqtrade/exchange/ftx.py +++ b/freqtrade/exchange/ftx.py @@ -70,6 +70,8 @@ class Ftx(Exchange): if order_types.get('stoploss', 'market') == 'limit': # set orderPrice to place limit order, otherwise it's a market order params['orderPrice'] = limit_rate + if self.trading_mode == TradingMode.FUTURES: + params.update({'reduceOnly': True}) params['stopPrice'] = stop_price amount = self.amount_to_precision(pair, amount) diff --git a/freqtrade/exchange/kraken.py b/freqtrade/exchange/kraken.py index 308a6feab..3516f41d5 100644 --- a/freqtrade/exchange/kraken.py +++ b/freqtrade/exchange/kraken.py @@ -101,6 +101,8 @@ class Kraken(Exchange): Stoploss market orders is the only stoploss type supported by kraken. """ params = self._params.copy() + if self.trading_mode == TradingMode.FUTURES: + params.update({'reduceOnly': True}) if order_types.get('stoploss', 'market') == 'limit': ordertype = "stop-loss-limit" @@ -159,8 +161,14 @@ class Kraken(Exchange): """ return - def _get_params(self, ordertype: str, leverage: float, time_in_force: str = 'gtc') -> Dict: - params = super()._get_params(ordertype, leverage, time_in_force) + def _get_params( + self, + ordertype: str, + leverage: float, + reduceOnly: bool, + time_in_force: str = 'gtc' + ) -> Dict: + params = super()._get_params(ordertype, leverage, reduceOnly, time_in_force) if leverage > 1.0: params['leverage'] = leverage return params diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 38d80ab7a..6f39c23f7 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -699,6 +699,7 @@ class FreqtradeBot(LoggingMixin): side=side, amount=amount, rate=enter_limit_requested, + reduceOnly=False, time_in_force=time_in_force, leverage=leverage ) @@ -1422,6 +1423,7 @@ class FreqtradeBot(LoggingMixin): side=trade.exit_side, amount=amount, rate=limit, + reduceOnly=self.trading_mode == TradingMode.FUTURES, time_in_force=time_in_force ) except InsufficientFundsError as e: From 8a64f6a27f2ee688bd02c374651aee82c58568ee Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Tue, 1 Feb 2022 22:24:48 -0600 Subject: [PATCH 3/5] exchange.set_margin_mode param swap --- freqtrade/exchange/exchange.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index b28858ebd..f5d2c6b2d 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1880,7 +1880,7 @@ class Exchange: return try: - self._api.set_margin_mode(pair, margin_mode.value, params) + self._api.set_margin_mode(margin_mode.value, pair, params) except ccxt.DDoSProtection as e: raise DDosProtection(e) from e except (ccxt.NetworkError, ccxt.ExchangeError) as e: From 8e51360f75b80e54b0577ba233adb4a6c8d116f5 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Tue, 1 Feb 2022 22:29:04 -0600 Subject: [PATCH 4/5] exchange._set_leverage rounds leverage --- freqtrade/exchange/binance.py | 2 +- freqtrade/exchange/exchange.py | 2 +- freqtrade/exchange/kraken.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/freqtrade/exchange/binance.py b/freqtrade/exchange/binance.py index c04947bdf..21baa9124 100644 --- a/freqtrade/exchange/binance.py +++ b/freqtrade/exchange/binance.py @@ -228,7 +228,7 @@ class Binance(Exchange): return try: - self._api.set_leverage(symbol=pair, leverage=leverage) + self._api.set_leverage(symbol=pair, leverage=round(leverage)) except ccxt.DDoSProtection as e: raise DDosProtection(e) from e except (ccxt.NetworkError, ccxt.ExchangeError) as e: diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index f5d2c6b2d..a284780ea 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1853,7 +1853,7 @@ class Exchange: return try: - self._api.set_leverage(symbol=pair, leverage=leverage) + self._api.set_leverage(symbol=pair, leverage=round(leverage)) except ccxt.DDoSProtection as e: raise DDosProtection(e) from e except (ccxt.NetworkError, ccxt.ExchangeError) as e: diff --git a/freqtrade/exchange/kraken.py b/freqtrade/exchange/kraken.py index 3516f41d5..0c3fe4e7b 100644 --- a/freqtrade/exchange/kraken.py +++ b/freqtrade/exchange/kraken.py @@ -170,7 +170,7 @@ class Kraken(Exchange): ) -> Dict: params = super()._get_params(ordertype, leverage, reduceOnly, time_in_force) if leverage > 1.0: - params['leverage'] = leverage + params['leverage'] = round(leverage) return params def calculate_funding_fees( From a741356d652840252dc1d0a5cd8cced50a4b77f9 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Wed, 2 Feb 2022 00:28:57 -0600 Subject: [PATCH 5/5] okex._lev_prep, removing rounding from default set_leverage --- freqtrade/exchange/binance.py | 2 +- freqtrade/exchange/exchange.py | 11 ++++++++--- freqtrade/exchange/ftx.py | 2 +- freqtrade/exchange/okex.py | 21 ++++++++++++++++++++- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/freqtrade/exchange/binance.py b/freqtrade/exchange/binance.py index 21baa9124..ef5c65f5b 100644 --- a/freqtrade/exchange/binance.py +++ b/freqtrade/exchange/binance.py @@ -93,7 +93,7 @@ class Binance(Exchange): rate = self.price_to_precision(pair, rate) - self._lev_prep(pair, leverage) + self._lev_prep(pair, leverage, side) order = self._api.create_order( symbol=pair, type=ordertype, diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index a284780ea..2b35417d3 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -877,7 +877,12 @@ class Exchange: # Order handling - def _lev_prep(self, pair: str, leverage: float): + def _lev_prep( + self, + pair: str, + leverage: float, + side: str # buy or sell + ): if self.trading_mode != TradingMode.SPOT: self.set_margin_mode(pair, self.margin_mode) self._set_leverage(leverage, pair) @@ -923,7 +928,7 @@ class Exchange: rate_for_order = self.price_to_precision(pair, rate) if needs_price else None if not reduceOnly: - self._lev_prep(pair, leverage) + self._lev_prep(pair, leverage, side) order = self._api.create_order( pair, @@ -1853,7 +1858,7 @@ class Exchange: return try: - self._api.set_leverage(symbol=pair, leverage=round(leverage)) + self._api.set_leverage(symbol=pair, leverage=leverage) except ccxt.DDoSProtection as e: raise DDosProtection(e) from e except (ccxt.NetworkError, ccxt.ExchangeError) as e: diff --git a/freqtrade/exchange/ftx.py b/freqtrade/exchange/ftx.py index 143be73ac..be2e19c66 100644 --- a/freqtrade/exchange/ftx.py +++ b/freqtrade/exchange/ftx.py @@ -76,7 +76,7 @@ class Ftx(Exchange): params['stopPrice'] = stop_price amount = self.amount_to_precision(pair, amount) - self._lev_prep(pair, leverage) + self._lev_prep(pair, leverage, side) order = self._api.create_order(symbol=pair, type=ordertype, side=side, amount=amount, params=params) self._log_exchange_response('create_stoploss_order', order) diff --git a/freqtrade/exchange/okex.py b/freqtrade/exchange/okex.py index b6252ed1e..3c774cc9a 100644 --- a/freqtrade/exchange/okex.py +++ b/freqtrade/exchange/okex.py @@ -3,7 +3,7 @@ from typing import Dict, List, Tuple from freqtrade.enums import MarginMode, TradingMode from freqtrade.exchange import Exchange - +from freqtrade.exceptions import OperationalException logger = logging.getLogger(__name__) @@ -26,3 +26,22 @@ class Okex(Exchange): # (TradingMode.FUTURES, MarginMode.CROSS), # (TradingMode.FUTURES, MarginMode.ISOLATED) ] + + def _lev_prep( + self, + pair: str, + leverage: float, + side: str # buy or sell + ): + if self.trading_mode != TradingMode.SPOT: + if self.margin_mode is None: + raise OperationalException( + f"{self.name}.margin_mode must be set for {self.trading_mode.value}" + ) + self._api.set_leverage( + leverage, + pair, + params={ + "mgnMode": self.margin_mode.value, + "posSide": "long" if side == "buy" else "short", + })