Repository: freqtrade/freqtrade

Issue:
trailing_stop = True not selling?
## Step 1: Have you search for this issue before posting it?
Yes

## Step 2: Describe your environment

  * Operating system: ubuntu server
  * Python Version: 3.8
  * CCXT version: ccxt==1.21.56
  * Branch: Develop
  * Last Commit ID: 2f82122fc40caf428d48f7ab942c8dc49c3ee8f1
  
## Step 3: Describe the problem:
trailing stop-loss not selling

Should it not have sold the trade already?
Trade ID: 1 (since 7 hours ago)
Current Pair: EOS/BTC
Amount: 14.59 (0.006 BTC)
Open Rate: 0.00041110
Current Rate: **0.00042120**
Current Profit: 2.25%
Initial Stoploss: 0.00040987 (-0.30%)
Stoploss: **0.00042472** (-0.30%)

Trade ID: 2 (since 6 hours ago)
Current Pair: BNB/BTC
Amount: 3.02 (0.006 BTC)
Open Rate: 0.00198260
Current Rate: **0.00200150**
Current Profit: 0.75%
Initial Stoploss: 0.00197665 (-0.30%)
Stoploss: **0.00200178** (-0.30%)

Trade ID: 3 (since 4 hours ago)
Current Pair: DASH/BTC
Amount: 0.504 (0.006 BTC)
Open Rate: 0.01188600
Current Rate: **0.01288400**
Current Profit: 8.18%
Initial Stoploss: 0.01185034 (-0.30%)
Stoploss: **0.01327705** (-0.30%)

The price was above the stop-loss at one point but it didn't sell. I'm running in dry-mode so it should not be a problem that the sell did not occur.
**Config:**
stoploss = -0.003

# Trailing stoploss
trailing_stop = True
trailing_only_offset_is_reached = False
trailing_stop_positive = 0.003
#trailing_stop_positive_offset = 0.20  # Disabled / not configure

### Steps to reproduce:
Not sure :-(
  
### Observed Results:
It just keeps on not selling.

### Relevant code exceptions or logs:

  ```
  // paste your log here
  ```



Discussion:
Additional info from Slack, for 1st trade, to review the pair chart for the timerange of the trade:

* Binance: Buying EOS/BTC
at rate 0.00041110
(0.006000 BTC
at 11:48 CET
or 2020-01-20 10:48 UTC

* 1m timeframe used.
* dry run

are you using stoploss_on_exchange ?
do the logs show something of interrest (or just "Bot Heartbeat")? I think especially around the buy / trade entry it shoudl be interresting.

In addition to that, an excerpt / output from the database would be nice 
(`sqlite3 databasefile` `select * from trades where id < 4;`)

Also, has the bot been stopped between these trades?


Now irrespectible of this problem - i don't think a stoploss of 0.3% will work ... you need to consider that after buying, you're already down by 0.2% without the price moving by 1pip (assuming binance, which has a default 0.1% fee, which is applied on both buy and sell), so you're giving your trades 0.1% room to move lower ... which will have you stopped out on 90% of the trades...
some additional info. it just did a buy again and the stoploss seems to look ok but it's not selling:
Trade ID: 4 (since 11 minutes ago)
Current Pair: ETC/BTC
Amount: 5.87 (0.006 BTC)
Open Rate: **0.00102070**
Current Rate: **0.00101710**
Current Profit: -0.55%
Initial Stoploss: 0.00101764 (-0.30%)
Stoploss: **0.00101883** (-0.30%)
> are you using stoploss_on_exchange ?
> do the logs show something of interrest (or just "Bot Heartbeat")? I think especially around the buy / trade entry it shoudl be interresting.
> 
> In addition to that, an excerpt / output from the database would be nice
> (`sqlite3 databasefile` `select * from trades where id < 4;`)
> 
> Also, has the bot been stopped between these trades?
> 
> Now irrespectible of this problem - i don't think a stoploss of 0.3% will work ... you need to consider that after buying, you're already down by 0.2% without the price moving by 1pip (assuming binance, which has a default 0.1% fee, which is applied on both buy and sell), so you're giving your trades 0.1% room to move lower ... which will have you stopped out on 90% of the trades...

'stoploss_on_exchange': True
yes. is it not working with dry-run?
> yes. is it not working with dry-run?

well it should be ... but it's an important info for debugging, otherwise we'd look at the wrong spot.

Until it's fixed (assuming it's a bug for now), disabling `stoploss_on_exchange` will be a good and valid approach though, as it adds no benefit during dry-runs.


i will test it and see if it sells right away
Seems to work as it sold directly after config re-load with stoploss_on_exchange = False
Binance: Selling ETC/BTC
Rate: 0.00101650
Amount: 5.87000000
Open Rate: 0.00102070
Current Rate: 0.00101650
Sell Reason: trailing_stop_loss
Duration: 0:18:27 (18.4 min)
Profit: -0.61% (loss: -0.00003661 BTC

Resolving patch:
diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py
--- a/freqtrade/strategy/interface.py
+++ b/freqtrade/strategy/interface.py
@@ -389,9 +389,11 @@ def stop_loss_reached(self, current_rate: float, trade: Trade,
                 trade.adjust_stop_loss(high or current_rate, stop_loss_value)
 
         # evaluate if the stoploss was hit if stoploss is not on exchange
+        # in Dry-Run, this handles stoploss logic as well, as the logic will not be different to
+        # regular stoploss handling.
         if ((self.stoploss is not None) and
             (trade.stop_loss >= current_rate) and
-                (not self.order_types.get('stoploss_on_exchange'))):
+                (not self.order_types.get('stoploss_on_exchange') or self.config['dry_run'])):
 
             sell_type = SellType.STOP_LOSS
 


Test patch:
diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py
--- a/tests/test_freqtradebot.py
+++ b/tests/test_freqtradebot.py
@@ -1318,6 +1318,14 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee, caplog,
                                                 rate=0.00002344 * 0.95 * 0.99,
                                                 stop_price=0.00002344 * 0.95)
 
+    # price fell below stoploss, so dry-run sells trade.
+    mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', MagicMock(return_value={
+        'bid': 0.00002144,
+        'ask': 0.00002146,
+        'last': 0.00002144
+    }))
+    assert freqtrade.handle_trade(trade) is True
+
 
 def test_handle_stoploss_on_exchange_trailing_error(mocker, default_conf, fee, caplog,
                                                     limit_buy_order, limit_sell_order) -> None: