Repository: freqtrade/freqtrade

Issue:
unable to place stop loss on exchange when low amount of a coin has been buy (due to partially fullfilled)
## Step 3: Describe the problem:

1/The bot place a limit buy order. (unfilledtimeout of the buy = 5 minutes)

> Found open order for Trade(id=17, pair=TFUEL/USDT, amount=26315.78947368, open_rate=0.00760000, open_since=just now)

2/The buy order is partially filled and cancel do to timeout

> Partial buy order timeout for Trade(id=17, pair=TFUEL/USDT, amount=10.20000000, open_rate=0.00760000, open_since=5 minutes ago).

3/the amount is too slow to place a stoploss

> 2019-07-11 07:23:03,825 - freqtrade.freqtradebot - WARNING - Unable to place a stoploss order on exchange: Could not create stop_loss_limit sell order on market TFUEL/USDT.Tried to sell amount 10.2 at rate 0.00715 (total 0.07293).Message: binance {"code":-1013,"msg":"Filter failure: MIN_NOTIONAL"}

4/ the bot crash

```
 2019-07-11 07:38:02,780 - freqtrade - ERROR - Fatal exception!
 Traceback (most recent call last):
   File "/usr/local/lib/python3.7/site-packages/ccxt/base/exchange.py", line 526, in fetch
     response.raise_for_status()
   File "/usr/local/lib/python3.7/site-packages/requests/models.py", line 940, in raise_for_status
     raise HTTPError(http_error_msg, response=self)
 requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://api.binance.com/api/v3/order
 
 During handling of the above exception, another exception occurred:
 
 Traceback (most recent call last):
   File "/freqtrade/freqtrade/exchange/exchange.py", line 370, in create_order
     amount, rate, params)
   File "/usr/local/lib/python3.7/site-packages/ccxt/binance.py", line 703, in create_order
     response = getattr(self, method)(self.extend(request, params))
   File "/usr/local/lib/python3.7/site-packages/ccxt/base/exchange.py", line 421, in inner
     return entry(_self, **inner_kwargs)
   File "/usr/local/lib/python3.7/site-packages/ccxt/binance.py", line 1226, in request
     response = self.fetch2(path, api, method, params, headers, body)
   File "/usr/local/lib/python3.7/site-packages/ccxt/base/exchange.py", line 446, in fetch2
     return self.fetch(request['url'], request['method'], request['headers'], request['body'])
   File "/usr/local/lib/python3.7/site-packages/ccxt/base/exchange.py", line 538, in fetch
     self.handle_errors(response.status_code, response.reason, url, method, headers, http_response, json_response)
   File "/usr/local/lib/python3.7/site-packages/ccxt/binance.py", line 1219, in handle_errors
     raise exceptions[error](self.id + ' ' + body)
 ccxt.base.errors.InvalidOrder: binance {"code":-1013,"msg":"Filter failure: MIN_NOTIONAL"}
 
 During handling of the above exception, another exception occurred:
 
 Traceback (most recent call last):
   File "/freqtrade/freqtrade/main.py", line 52, in main
     worker.run()
   File "/freqtrade/freqtrade/worker.py", line 72, in run
     state = self._worker(old_state=state)
   File "/freqtrade/freqtrade/worker.py", line 110, in _worker
     self._throttle(func=self._process, min_secs=throttle_secs)
   File "/freqtrade/freqtrade/worker.py", line 123, in _throttle
     result = func(*args, **kwargs)
   File "/freqtrade/freqtrade/worker.py", line 133, in _process
     state_changed = self.freqtrade.process()
   File "/freqtrade/freqtrade/freqtradebot.py", line 136, in process
     state_changed |= self.process_maybe_execute_sell(trade)
   File "/freqtrade/freqtrade/freqtradebot.py", line 459, in process_maybe_execute_sell
     result = self.handle_trade(trade)
   File "/freqtrade/freqtrade/freqtradebot.py", line 596, in handle_trade
     if self.check_sell(trade, sell_rate, buy, sell):
   File "/freqtrade/freqtrade/freqtradebot.py", line 711, in check_sell
     self.execute_sell(trade, sell_rate, should_sell.sell_type)
   File "/freqtrade/freqtrade/freqtradebot.py", line 852, in execute_sell
     time_in_force=self.strategy.order_time_in_force['sell']
   File "/freqtrade/freqtrade/exchange/exchange.py", line 412, in sell
     return self.create_order(pair, ordertype, 'sell', amount, rate, params)
   File "/freqtrade/freqtrade/exchange/exchange.py", line 379, in create_order
     f'Could not create {ordertype} {side} order on market {pair}.'
 TypeError: unsupported operand type(s) for *: 'NoneType' and 'float'
```

Excepted behavior :
for example no matter the bot don't succeed place a stoploss on MIN_NOTIONAL just close the trade in the database.

Maybe i can prevent this behavior with FOK (Full Or Kill)

Have a nice day.

unable to place stop loss on exchange when low amount of a coin has been buy (due to partially fullfilled)
## Step 3: Describe the problem:

1/The bot place a limit buy order. (unfilledtimeout of the buy = 5 minutes)

> Found open order for Trade(id=17, pair=TFUEL/USDT, amount=26315.78947368, open_rate=0.00760000, open_since=just now)

2/The buy order is partially filled and cancel do to timeout

> Partial buy order timeout for Trade(id=17, pair=TFUEL/USDT, amount=10.20000000, open_rate=0.00760000, open_since=5 minutes ago).

3/the amount is too slow to place a stoploss

> 2019-07-11 07:23:03,825 - freqtrade.freqtradebot - WARNING - Unable to place a stoploss order on exchange: Could not create stop_loss_limit sell order on market TFUEL/USDT.Tried to sell amount 10.2 at rate 0.00715 (total 0.07293).Message: binance {"code":-1013,"msg":"Filter failure: MIN_NOTIONAL"}

4/ the bot crash

```
 2019-07-11 07:38:02,780 - freqtrade - ERROR - Fatal exception!
 Traceback (most recent call last):
   File "/usr/local/lib/python3.7/site-packages/ccxt/base/exchange.py", line 526, in fetch
     response.raise_for_status()
   File "/usr/local/lib/python3.7/site-packages/requests/models.py", line 940, in raise_for_status
     raise HTTPError(http_error_msg, response=self)
 requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://api.binance.com/api/v3/order
 
 During handling of the above exception, another exception occurred:
 
 Traceback (most recent call last):
   File "/freqtrade/freqtrade/exchange/exchange.py", line 370, in create_order
     amount, rate, params)
   File "/usr/local/lib/python3.7/site-packages/ccxt/binance.py", line 703, in create_order
     response = getattr(self, method)(self.extend(request, params))
   File "/usr/local/lib/python3.7/site-packages/ccxt/base/exchange.py", line 421, in inner
     return entry(_self, **inner_kwargs)
   File "/usr/local/lib/python3.7/site-packages/ccxt/binance.py", line 1226, in request
     response = self.fetch2(path, api, method, params, headers, body)
   File "/usr/local/lib/python3.7/site-packages/ccxt/base/exchange.py", line 446, in fetch2
     return self.fetch(request['url'], request['method'], request['headers'], request['body'])
   File "/usr/local/lib/python3.7/site-packages/ccxt/base/exchange.py", line 538, in fetch
     self.handle_errors(response.status_code, response.reason, url, method, headers, http_response, json_response)
   File "/usr/local/lib/python3.7/site-packages/ccxt/binance.py", line 1219, in handle_errors
     raise exceptions[error](self.id + ' ' + body)
 ccxt.base.errors.InvalidOrder: binance {"code":-1013,"msg":"Filter failure: MIN_NOTIONAL"}
 
 During handling of the above exception, another exception occurred:
 
 Traceback (most recent call last):
   File "/freqtrade/freqtrade/main.py", line 52, in main
     worker.run()
   File "/freqtrade/freqtrade/worker.py", line 72, in run
     state = self._worker(old_state=state)
   File "/freqtrade/freqtrade/worker.py", line 110, in _worker
     self._throttle(func=self._process, min_secs=throttle_secs)
   File "/freqtrade/freqtrade/worker.py", line 123, in _throttle
     result = func(*args, **kwargs)
   File "/freqtrade/freqtrade/worker.py", line 133, in _process
     state_changed = self.freqtrade.process()
   File "/freqtrade/freqtrade/freqtradebot.py", line 136, in process
     state_changed |= self.process_maybe_execute_sell(trade)
   File "/freqtrade/freqtrade/freqtradebot.py", line 459, in process_maybe_execute_sell
     result = self.handle_trade(trade)
   File "/freqtrade/freqtrade/freqtradebot.py", line 596, in handle_trade
     if self.check_sell(trade, sell_rate, buy, sell):
   File "/freqtrade/freqtrade/freqtradebot.py", line 711, in check_sell
     self.execute_sell(trade, sell_rate, should_sell.sell_type)
   File "/freqtrade/freqtrade/freqtradebot.py", line 852, in execute_sell
     time_in_force=self.strategy.order_time_in_force['sell']
   File "/freqtrade/freqtrade/exchange/exchange.py", line 412, in sell
     return self.create_order(pair, ordertype, 'sell', amount, rate, params)
   File "/freqtrade/freqtrade/exchange/exchange.py", line 379, in create_order
     f'Could not create {ordertype} {side} order on market {pair}.'
 TypeError: unsupported operand type(s) for *: 'NoneType' and 'float'
```

Excepted behavior :
for example no matter the bot don't succeed place a stoploss on MIN_NOTIONAL just close the trade in the database.

Maybe i can prevent this behavior with FOK (Full Or Kill)

Have a nice day.



Discussion:
Thanks for reporting.

yes, FOK will prevent this (also IOK - immediately or kill should).

I think this is actually a partial duplicate of #1858. While it didn't crash in that instance, the half-filled orders are a problem we need to adress.
Thanks for reporting.

yes, FOK will prevent this (also IOK - immediately or kill should).

I think this is actually a partial duplicate of #1858. While it didn't crash in that instance, the half-filled orders are a problem we need to adress.

Resolving patch:
diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py
--- a/freqtrade/exchange/exchange.py
+++ b/freqtrade/exchange/exchange.py
@@ -408,12 +408,12 @@ def create_order(self, pair: str, ordertype: str, side: str, amount: float,
         except ccxt.InsufficientFunds as e:
             raise DependencyException(
                 f'Insufficient funds to create {ordertype} {side} order on market {pair}.'
-                f'Tried to {side} amount {amount} at rate {rate} (total {rate * amount}).'
+                f'Tried to {side} amount {amount} at rate {rate}.'
                 f'Message: {e}') from e
         except ccxt.InvalidOrder as e:
             raise DependencyException(
                 f'Could not create {ordertype} {side} order on market {pair}.'
-                f'Tried to {side} amount {amount} at rate {rate} (total {rate * amount}).'
+                f'Tried to {side} amount {amount} at rate {rate}.'
                 f'Message: {e}') from e
         except (ccxt.NetworkError, ccxt.ExchangeError) as e:
             raise TemporaryError(
@@ -472,7 +472,7 @@ def stoploss_limit(self, pair: str, amount: float, stop_price: float, rate: floa
 
         order = self.create_order(pair, ordertype, 'sell', amount, rate, params)
         logger.info('stoploss limit order added for %s. '
-                    'stop price: %s. limit: %s' % (pair, stop_price, rate))
+                    'stop price: %s. limit: %s', pair, stop_price, rate)
         return order
 
     @retrier


Test patch:
diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py
--- a/freqtrade/tests/exchange/test_exchange.py
+++ b/freqtrade/tests/exchange/test_exchange.py
@@ -656,7 +656,13 @@ def test_buy_prod(default_conf, mocker, exchange_name):
     with pytest.raises(DependencyException):
         api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
         exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
-        exchange.buy(pair='ETH/BTC', ordertype=order_type,
+        exchange.buy(pair='ETH/BTC', ordertype='limit',
+                     amount=1, rate=200, time_in_force=time_in_force)
+
+    with pytest.raises(DependencyException):
+        api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
+        exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
+        exchange.buy(pair='ETH/BTC', ordertype='market',
                      amount=1, rate=200, time_in_force=time_in_force)
 
     with pytest.raises(TemporaryError):
@@ -779,7 +785,13 @@ def test_sell_prod(default_conf, mocker, exchange_name):
     with pytest.raises(DependencyException):
         api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
         exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
-        exchange.sell(pair='ETH/BTC', ordertype=order_type, amount=1, rate=200)
+        exchange.sell(pair='ETH/BTC', ordertype='limit', amount=1, rate=200)
+
+    # Market orders don't require price, so the behaviour is slightly different
+    with pytest.raises(DependencyException):
+        api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
+        exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
+        exchange.sell(pair='ETH/BTC', ordertype='market', amount=1, rate=200)
 
     with pytest.raises(TemporaryError):
         api_mock.create_order = MagicMock(side_effect=ccxt.NetworkError("No Connection"))