move exchange-specific order-parsing to exchange class
Related to stoploss_on_exchange in combination with trailing stoploss. Binance contains stopPrice in the info, while kraken returns the same value as "price".
This commit is contained in:
		| @@ -32,6 +32,13 @@ class Binance(Exchange): | |||||||
|  |  | ||||||
|         return super().get_order_book(pair, limit) |         return super().get_order_book(pair, limit) | ||||||
|  |  | ||||||
|  |     def stoploss_adjust(self, stop_loss: float, order: Dict) -> bool: | ||||||
|  |         """ | ||||||
|  |         Verify stop_loss against stoploss-order value (limit or price) | ||||||
|  |         Returns True if adjustment is necessary. | ||||||
|  |         """ | ||||||
|  |         return order['type'] == 'stop_loss_limit' and stop_loss > float(order['info']['stopPrice']) | ||||||
|  |  | ||||||
|     def stoploss(self, pair: str, amount: float, stop_price: float, order_types: Dict) -> Dict: |     def stoploss(self, pair: str, amount: float, stop_price: float, order_types: Dict) -> Dict: | ||||||
|         """ |         """ | ||||||
|         creates a stoploss limit order. |         creates a stoploss limit order. | ||||||
|   | |||||||
| @@ -282,8 +282,8 @@ class Exchange: | |||||||
|         quote_currencies = self.get_quote_currencies() |         quote_currencies = self.get_quote_currencies() | ||||||
|         if stake_currency not in quote_currencies: |         if stake_currency not in quote_currencies: | ||||||
|             raise OperationalException( |             raise OperationalException( | ||||||
|                     f"{stake_currency} is not available as stake on {self.name}. " |                 f"{stake_currency} is not available as stake on {self.name}. " | ||||||
|                     f"Available currencies are: {', '.join(quote_currencies)}") |                 f"Available currencies are: {', '.join(quote_currencies)}") | ||||||
|  |  | ||||||
|     def validate_pairs(self, pairs: List[str]) -> None: |     def validate_pairs(self, pairs: List[str]) -> None: | ||||||
|         """ |         """ | ||||||
| @@ -460,7 +460,7 @@ class Exchange: | |||||||
|                 "status": "closed", |                 "status": "closed", | ||||||
|                 "filled": closed_order["amount"], |                 "filled": closed_order["amount"], | ||||||
|                 "remaining": 0 |                 "remaining": 0 | ||||||
|                 }) |             }) | ||||||
|         if closed_order["type"] in ["stop_loss_limit"]: |         if closed_order["type"] in ["stop_loss_limit"]: | ||||||
|             closed_order["info"].update({"stopPrice": closed_order["price"]}) |             closed_order["info"].update({"stopPrice": closed_order["price"]}) | ||||||
|         self._dry_run_open_orders[closed_order["id"]] = closed_order |         self._dry_run_open_orders[closed_order["id"]] = closed_order | ||||||
| @@ -519,6 +519,13 @@ class Exchange: | |||||||
|  |  | ||||||
|         return self.create_order(pair, ordertype, 'sell', amount, rate, params) |         return self.create_order(pair, ordertype, 'sell', amount, rate, params) | ||||||
|  |  | ||||||
|  |     def stoploss_adjust(self, stop_loss: float, order: Dict) -> bool: | ||||||
|  |         """ | ||||||
|  |         Verify stop_loss against stoploss-order value (limit or price) | ||||||
|  |         Returns True if adjustment is necessary. | ||||||
|  |         """ | ||||||
|  |         raise OperationalException(f"stoploss is not implemented for {self.name}.") | ||||||
|  |  | ||||||
|     def stoploss(self, pair: str, amount: float, stop_price: float, order_types: Dict) -> Dict: |     def stoploss(self, pair: str, amount: float, stop_price: float, order_types: Dict) -> Dict: | ||||||
|         """ |         """ | ||||||
|         creates a stoploss order. |         creates a stoploss order. | ||||||
|   | |||||||
| @@ -51,6 +51,13 @@ class Kraken(Exchange): | |||||||
|         except ccxt.BaseError as e: |         except ccxt.BaseError as e: | ||||||
|             raise OperationalException(e) from e |             raise OperationalException(e) from e | ||||||
|  |  | ||||||
|  |     def stoploss_adjust(self, stop_loss: float, order: Dict) -> bool: | ||||||
|  |         """ | ||||||
|  |         Verify stop_loss against stoploss-order value (limit or price) | ||||||
|  |         Returns True if adjustment is necessary. | ||||||
|  |         """ | ||||||
|  |         return order['type'] == 'stop-loss' and stop_loss > float(order['price']) | ||||||
|  |  | ||||||
|     def stoploss(self, pair: str, amount: float, stop_price: float, order_types: Dict) -> Dict: |     def stoploss(self, pair: str, amount: float, stop_price: float, order_types: Dict) -> Dict: | ||||||
|         """ |         """ | ||||||
|         Creates a stoploss market order. |         Creates a stoploss market order. | ||||||
|   | |||||||
| @@ -718,8 +718,7 @@ class FreqtradeBot: | |||||||
|         :param order: Current on exchange stoploss order |         :param order: Current on exchange stoploss order | ||||||
|         :return: None |         :return: None | ||||||
|         """ |         """ | ||||||
|  |         if self.exchange.stoploss_adjust(trade.stop_loss, order): | ||||||
|         if trade.stop_loss > float(order['info']['stopPrice']): |  | ||||||
|             # we check if the update is neccesary |             # we check if the update is neccesary | ||||||
|             update_beat = self.strategy.order_types.get('stoploss_on_exchange_interval', 60) |             update_beat = self.strategy.order_types.get('stoploss_on_exchange_interval', 60) | ||||||
|             if (datetime.utcnow() - trade.stoploss_last_update).total_seconds() >= update_beat: |             if (datetime.utcnow() - trade.stoploss_last_update).total_seconds() >= update_beat: | ||||||
|   | |||||||
| @@ -92,3 +92,17 @@ def test_stoploss_order_dry_run_binance(default_conf, mocker): | |||||||
|     assert order['type'] == order_type |     assert order['type'] == order_type | ||||||
|     assert order['price'] == 220 |     assert order['price'] == 220 | ||||||
|     assert order['amount'] == 1 |     assert order['amount'] == 1 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_stoploss_adjust_binance(mocker, default_conf): | ||||||
|  |     exchange = get_patched_exchange(mocker, default_conf, id='binance') | ||||||
|  |     order = { | ||||||
|  |         'type': 'stop_loss_limit', | ||||||
|  |         'price': 1500, | ||||||
|  |         'info': {'stopPrice': 1500}, | ||||||
|  |     } | ||||||
|  |     assert exchange.stoploss_adjust(1501, order) | ||||||
|  |     assert not exchange.stoploss_adjust(1499, order) | ||||||
|  |     # Test with invalid order case | ||||||
|  |     order['type'] = 'stop_loss' | ||||||
|  |     assert not exchange.stoploss_adjust(1501, order) | ||||||
|   | |||||||
| @@ -1763,6 +1763,9 @@ def test_stoploss_order_unsupported_exchange(default_conf, mocker): | |||||||
|     with pytest.raises(OperationalException, match=r"stoploss is not implemented .*"): |     with pytest.raises(OperationalException, match=r"stoploss is not implemented .*"): | ||||||
|         exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}) |         exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}) | ||||||
|  |  | ||||||
|  |     with pytest.raises(OperationalException, match=r"stoploss is not implemented .*"): | ||||||
|  |         exchange.stoploss_adjust(1, {}) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_merge_ft_has_dict(default_conf, mocker): | def test_merge_ft_has_dict(default_conf, mocker): | ||||||
|     mocker.patch.multiple('freqtrade.exchange.Exchange', |     mocker.patch.multiple('freqtrade.exchange.Exchange', | ||||||
|   | |||||||
| @@ -236,3 +236,16 @@ def test_stoploss_order_dry_run_kraken(default_conf, mocker): | |||||||
|     assert order['type'] == order_type |     assert order['type'] == order_type | ||||||
|     assert order['price'] == 220 |     assert order['price'] == 220 | ||||||
|     assert order['amount'] == 1 |     assert order['amount'] == 1 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_stoploss_adjust_kraken(mocker, default_conf): | ||||||
|  |     exchange = get_patched_exchange(mocker, default_conf, id='kraken') | ||||||
|  |     order = { | ||||||
|  |         'type': 'stop-loss', | ||||||
|  |         'price': 1500, | ||||||
|  |     } | ||||||
|  |     assert exchange.stoploss_adjust(1501, order) | ||||||
|  |     assert not exchange.stoploss_adjust(1499, order) | ||||||
|  |     # Test with invalid order case ... | ||||||
|  |     order['type'] = 'stop_loss_limit' | ||||||
|  |     assert not exchange.stoploss_adjust(1501, order) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user