Repository: freqtrade/freqtrade

Issue:
Stoploss on exchange calculation
## Describe your environment

  * Python Version: Python 3.7.0 (`python -V`)
   * Branch:  Develop
  * Last Commit ID: 0d152eb90745241ad294ec65f7cbd52012f44305
  
## Describe the problem:

I think the calculation of stoploss_on_exchange should be changed, or at least a warning should be added.

Currently, we calculate the stop-price as `trade.open_rate * (1 + stoploss)`.
As limit (which is the rate the trade really sells) is then calculated by using `stop_price * 0.99`.

This leads to the trade risking 6% of my capital even though I only configured stoploss at a risk of 5%.

Real calculation example:

```
open_rate = 0.005272
stoploss = -0.05
stop_price = open_rate * (1 + stoploss)
print(f"stop_price: {stop_price}")
limit_price = stop_price * 0.99
print(f"limit_price: {limit_price}")
```

I think we should either increase the offset price (stop_price = stop_price * 1.01) - or use a lower multiplier than 1% for the limit.

Stoploss on exchange calculation
## Describe your environment

  * Python Version: Python 3.7.0 (`python -V`)
   * Branch:  Develop
  * Last Commit ID: 0d152eb90745241ad294ec65f7cbd52012f44305
  
## Describe the problem:

I think the calculation of stoploss_on_exchange should be changed, or at least a warning should be added.

Currently, we calculate the stop-price as `trade.open_rate * (1 + stoploss)`.
As limit (which is the rate the trade really sells) is then calculated by using `stop_price * 0.99`.

This leads to the trade risking 6% of my capital even though I only configured stoploss at a risk of 5%.

Real calculation example:

```
open_rate = 0.005272
stoploss = -0.05
stop_price = open_rate * (1 + stoploss)
print(f"stop_price: {stop_price}")
limit_price = stop_price * 0.99
print(f"limit_price: {limit_price}")
```

I think we should either increase the offset price (stop_price = stop_price * 1.01) - or use a lower multiplier than 1% for the limit.



Discussion:
>which is the rate the trade really sells

Not true as far as I know. limit price is the price you just don't want to sell below it. it is your limit. but the order engine matches best price once the stop price is hit. so limit price is just a guard in case volume is zero so your coin is sold radically below the market. 

Ex:
Spot at 100. 
Stop at 90.
Limit at 80. 

Spot reaches 90, there is an ask at 89 in the orderbook. your position is sold (if the volume matches of course) at 89. 

That's the reason why "average" price is almost always above the limit price.

But that being said, the arbitrary 0.99 should be revised anyway I think ...
you say almost always - but my risk (in your example) is 20%, not the 10% I am willing to risk according to the configuration...


I am not sure, your risk is more “stoploss is missed” because no buyer at
your price is in front ...

On Sun 31 Mar 2019 at 15:32, Matthias <notifications@github.com> wrote:

> you say almost always - but my risk (in your example) is 20%, not the 10%
> I am willing to risk according to the configuration...
>
> —
> You are receiving this because you commented.
>
>
> Reply to this email directly, view it on GitHub
> <https://github.com/freqtrade/freqtrade/issues/1717#issuecomment-478342461>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AA5VLage2UcTvhz6u3pHc73GJzR7QedCks5vcLjigaJpZM4cURK->
> .
>

Limit much below the price emulates stoploss (market)

On Sun 31 Mar 2019 at 15:46, misagh shakeri <misagh.shakeri@gmail.com>
wrote:

> I am not sure, your risk is more “stoploss is missed” because no buyer at
> your price is in front ...
>
> On Sun 31 Mar 2019 at 15:32, Matthias <notifications@github.com> wrote:
>
>> you say almost always - but my risk (in your example) is 20%, not the 10%
>> I am willing to risk according to the configuration...
>>
>> —
>> You are receiving this because you commented.
>>
>>
>> Reply to this email directly, view it on GitHub
>> <https://github.com/freqtrade/freqtrade/issues/1717#issuecomment-478342461>,
>> or mute the thread
>> <https://github.com/notifications/unsubscribe-auth/AA5VLage2UcTvhz6u3pHc73GJzR7QedCks5vcLjigaJpZM4cURK->
>> .
>>
>

Where do you get that information from @mishaker ? I am pretty sure that it is as Matthias says, the limit price is just the price for the limit order that is created when the stop price is reached. But I'm happy to stand corrected.. In any case, the 99% should probably be adjustable. I like Matthias suggestion of increasing the stop price, that way your capital at risk is actually whatever you define as stop loss.
Look at this order as an example: 

```json
{
    "info": {
      "symbol": "LRCETH",
      "orderId": 28216487,
      "clientOrderId": "HqduBD7i9ghwKPq9fqKRg8",
      "price": "0.00044664",
      "origQty": "508.00000000",
      "executedQty": "508.00000000",
      "cummulativeQuoteQty": "0.22914864",
      "status": "FILLED",
      "timeInForce": "GTC",
      "type": "STOP_LOSS_LIMIT",
      "side": "SELL",
      "stopPrice": "0.00045115",
      "icebergQty": "0.00000000",
      "time": 1547715915652,
      "updateTime": 1547716875612,
      "isWorking": true
    },
    "id": "28216487",
    "timestamp": 1547715915652,
    "datetime": "2019-01-17T09:05:15.652Z",
    "lastTradeTimestamp": null,
    "symbol": "LRC/ETH",
    "type": "stop_loss_limit",
    "side": "sell",
    "price": 0.00044664,
    "amount": 508.0,
    "cost": 0.22914864,
    "average": 0.00045107999999999997,
    "filled": 508.0,
    "remaining": 0.0,
    "status": "closed",
    "fee": null,
    "trades": null
  }
```

`Stop Price` is 0.00045115
`Limit Price` is 0.00044664 (which is 1% below the stop price) 

When stop price was breached, order engine tried to match with the best bids **under condition that they are above limit price.**

Thus if you look at `average` it is 0.00045108 (less than 0.1% below the stop price) 

Limit price is just a guard. it is the price below it you don't want to sell your asset anymore. so if you put it to zero then stoploss limit order would become a stoploss order (HINT: this is technically true but binance detects it and reject your stoploss limit with 0 as limit).

the risk of setting limit price as your stop price is that your real stop price is above what you actually wanted so a prey to stop hunters.
I would prefer to lose 12 or 13% because it fell too far instead of 100% in case my stop-loss is not accepted...
Interesting, in the ccxt [docs](https://github.com/ccxt/ccxt/wiki/Manual#order-structure) the "average" key is not even mentioned in the order structure:

```java
{
    'id':                '12345-67890:09876/54321', // string
    'datetime':          '2017-08-17 12:42:48.000', // ISO8601 datetime of 'timestamp' with milliseconds
    'timestamp':          1502962946216, // order placing/opening Unix timestamp in milliseconds
    'lastTradeTimestamp': 1502962956216, // Unix timestamp of the most recent trade on this order
    'status':     'open',         // 'open', 'closed', 'canceled'
    'symbol':     'ETH/BTC',      // symbol
    'type':       'limit',        // 'market', 'limit'
    'side':       'buy',          // 'buy', 'sell'
    'price':       0.06917684,    // float price in quote currency
    'amount':      1.5,           // ordered amount of base currency
    'filled':      1.1,           // filled amount of base currency
    'remaining':   0.4,           // remaining amount to fill
    'cost':        0.076094524,   // 'filled' * 'price' (filling price used where available)
    'trades':    [ ... ],         // a list of order trades/executions
    'fee': {                      // fee info, if available
        'currency': 'BTC',        // which currency the fee is (usually quote)
        'cost': 0.0009,           // the fee amount in that currency
        'rate': 0.002,            // the fee rate (if available)
    },
    'info': { ... },              // the original unparsed order structure as is
}
```

From your example, I'd say you're right, but it doesn't seem like this is universally true. I think on Kraken, for example, the limit stop price is like a traditional limit price. Unfortunately, I was a bit short on time lately and haven't been able to work on the implementation more, so I can't say for sure right now.
@iuvbio ccxt fills `cost`with average if I am not mistaken (double check needed).  
For kraken, I am pretty much sure it is the same behaviour but anyway for now stoploss limit on exchange is supported only for binance ...
>I would prefer to lose 12 or 13% because it fell too far instead of 100% in case my stop-loss is not accepted...
@xmatthias 

Yes and that's why I think we maybe want to make that 0.99 configurable ?
configurable - absolutely. I'm just not sure into what direction the calculation should go.

Assume the limit is blown - so it's not sold - but it never comes back close to the buy-rate - then i lost 50% or more ... i'll prefer a market sell on stoploss over that.
yep, then would use stoploss not stoploss limit I guess. I think differently about it. I'd rather wait till volume is back instead of FOMO selling.
well - you say volume is back - but even if volume is back, it may be back at 20% of it's original value - so you just lost 80% ... 
no, if the volume is zero at this moment your market order is fulfilled anyway but FAR below the last best bid. if you wait sometime a fraction of second then your order is likely to be fulfilled with a reasonable price. 
You are talking about market falling radically. I understand you. but I am talking about volume holes. I don't want my stoploss market order to be executed in those holes as the price is far below the last spot. so I would put my limit even to 10% but not less. if you believe the market can go radically even below that, then ok you use stoploss without limit. 
My experience is that volume holes are much more probable than shake outs more 10% or so in a few minutes ... 
The value of limit (0.99 \ 1%) should be configurable by the user.
>which is the rate the trade really sells

Not true as far as I know. limit price is the price you just don't want to sell below it. it is your limit. but the order engine matches best price once the stop price is hit. so limit price is just a guard in case volume is zero so your coin is sold radically below the market. 

Ex:
Spot at 100. 
Stop at 90.
Limit at 80. 

Spot reaches 90, there is an ask at 89 in the orderbook. your position is sold (if the volume matches of course) at 89. 

That's the reason why "average" price is almost always above the limit price.

But that being said, the arbitrary 0.99 should be revised anyway I think ...
you say almost always - but my risk (in your example) is 20%, not the 10% I am willing to risk according to the configuration...


I am not sure, your risk is more “stoploss is missed” because no buyer at
your price is in front ...

On Sun 31 Mar 2019 at 15:32, Matthias <notifications@github.com> wrote:

> you say almost always - but my risk (in your example) is 20%, not the 10%
> I am willing to risk according to the configuration...
>
> —
> You are receiving this because you commented.
>
>
> Reply to this email directly, view it on GitHub
> <https://github.com/freqtrade/freqtrade/issues/1717#issuecomment-478342461>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AA5VLage2UcTvhz6u3pHc73GJzR7QedCks5vcLjigaJpZM4cURK->
> .
>

Limit much below the price emulates stoploss (market)

On Sun 31 Mar 2019 at 15:46, misagh shakeri <misagh.shakeri@gmail.com>
wrote:

> I am not sure, your risk is more “stoploss is missed” because no buyer at
> your price is in front ...
>
> On Sun 31 Mar 2019 at 15:32, Matthias <notifications@github.com> wrote:
>
>> you say almost always - but my risk (in your example) is 20%, not the 10%
>> I am willing to risk according to the configuration...
>>
>> —
>> You are receiving this because you commented.
>>
>>
>> Reply to this email directly, view it on GitHub
>> <https://github.com/freqtrade/freqtrade/issues/1717#issuecomment-478342461>,
>> or mute the thread
>> <https://github.com/notifications/unsubscribe-auth/AA5VLage2UcTvhz6u3pHc73GJzR7QedCks5vcLjigaJpZM4cURK->
>> .
>>
>

Where do you get that information from @mishaker ? I am pretty sure that it is as Matthias says, the limit price is just the price for the limit order that is created when the stop price is reached. But I'm happy to stand corrected.. In any case, the 99% should probably be adjustable. I like Matthias suggestion of increasing the stop price, that way your capital at risk is actually whatever you define as stop loss.
Look at this order as an example: 

```json
{
    "info": {
      "symbol": "LRCETH",
      "orderId": 28216487,
      "clientOrderId": "HqduBD7i9ghwKPq9fqKRg8",
      "price": "0.00044664",
      "origQty": "508.00000000",
      "executedQty": "508.00000000",
      "cummulativeQuoteQty": "0.22914864",
      "status": "FILLED",
      "timeInForce": "GTC",
      "type": "STOP_LOSS_LIMIT",
      "side": "SELL",
      "stopPrice": "0.00045115",
      "icebergQty": "0.00000000",
      "time": 1547715915652,
      "updateTime": 1547716875612,
      "isWorking": true
    },
    "id": "28216487",
    "timestamp": 1547715915652,
    "datetime": "2019-01-17T09:05:15.652Z",
    "lastTradeTimestamp": null,
    "symbol": "LRC/ETH",
    "type": "stop_loss_limit",
    "side": "sell",
    "price": 0.00044664,
    "amount": 508.0,
    "cost": 0.22914864,
    "average": 0.00045107999999999997,
    "filled": 508.0,
    "remaining": 0.0,
    "status": "closed",
    "fee": null,
    "trades": null
  }
```

`Stop Price` is 0.00045115
`Limit Price` is 0.00044664 (which is 1% below the stop price) 

When stop price was breached, order engine tried to match with the best bids **under condition that they are above limit price.**

Thus if you look at `average` it is 0.00045108 (less than 0.1% below the stop price) 

Limit price is just a guard. it is the price below it you don't want to sell your asset anymore. so if you put it to zero then stoploss limit order would become a stoploss order (HINT: this is technically true but binance detects it and reject your stoploss limit with 0 as limit).

the risk of setting limit price as your stop price is that your real stop price is above what you actually wanted so a prey to stop hunters.
I would prefer to lose 12 or 13% because it fell too far instead of 100% in case my stop-loss is not accepted...
Interesting, in the ccxt [docs](https://github.com/ccxt/ccxt/wiki/Manual#order-structure) the "average" key is not even mentioned in the order structure:

```java
{
    'id':                '12345-67890:09876/54321', // string
    'datetime':          '2017-08-17 12:42:48.000', // ISO8601 datetime of 'timestamp' with milliseconds
    'timestamp':          1502962946216, // order placing/opening Unix timestamp in milliseconds
    'lastTradeTimestamp': 1502962956216, // Unix timestamp of the most recent trade on this order
    'status':     'open',         // 'open', 'closed', 'canceled'
    'symbol':     'ETH/BTC',      // symbol
    'type':       'limit',        // 'market', 'limit'
    'side':       'buy',          // 'buy', 'sell'
    'price':       0.06917684,    // float price in quote currency
    'amount':      1.5,           // ordered amount of base currency
    'filled':      1.1,           // filled amount of base currency
    'remaining':   0.4,           // remaining amount to fill
    'cost':        0.076094524,   // 'filled' * 'price' (filling price used where available)
    'trades':    [ ... ],         // a list of order trades/executions
    'fee': {                      // fee info, if available
        'currency': 'BTC',        // which currency the fee is (usually quote)
        'cost': 0.0009,           // the fee amount in that currency
        'rate': 0.002,            // the fee rate (if available)
    },
    'info': { ... },              // the original unparsed order structure as is
}
```

From your example, I'd say you're right, but it doesn't seem like this is universally true. I think on Kraken, for example, the limit stop price is like a traditional limit price. Unfortunately, I was a bit short on time lately and haven't been able to work on the implementation more, so I can't say for sure right now.
@iuvbio ccxt fills `cost`with average if I am not mistaken (double check needed).  
For kraken, I am pretty much sure it is the same behaviour but anyway for now stoploss limit on exchange is supported only for binance ...
>I would prefer to lose 12 or 13% because it fell too far instead of 100% in case my stop-loss is not accepted...
@xmatthias 

Yes and that's why I think we maybe want to make that 0.99 configurable ?
configurable - absolutely. I'm just not sure into what direction the calculation should go.

Assume the limit is blown - so it's not sold - but it never comes back close to the buy-rate - then i lost 50% or more ... i'll prefer a market sell on stoploss over that.
yep, then would use stoploss not stoploss limit I guess. I think differently about it. I'd rather wait till volume is back instead of FOMO selling.
well - you say volume is back - but even if volume is back, it may be back at 20% of it's original value - so you just lost 80% ... 
no, if the volume is zero at this moment your market order is fulfilled anyway but FAR below the last best bid. if you wait sometime a fraction of second then your order is likely to be fulfilled with a reasonable price. 
You are talking about market falling radically. I understand you. but I am talking about volume holes. I don't want my stoploss market order to be executed in those holes as the price is far below the last spot. so I would put my limit even to 10% but not less. if you believe the market can go radically even below that, then ok you use stoploss without limit. 
My experience is that volume holes are much more probable than shake outs more 10% or so in a few minutes ... 
The value of limit (0.99 \ 1%) should be configurable by the user.

Resolving patch:
diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py
--- a/freqtrade/freqtradebot.py
+++ b/freqtrade/freqtradebot.py
@@ -634,8 +634,8 @@ def create_stoploss_order(self, trade: Trade, stop_price: float, rate: float) ->
         Force-sells the pair (using EmergencySell reason) in case of Problems creating the order.
         :return: True if the order succeeded, and False in case of problems.
         """
-        # Limit price threshold: As limit price should always be below price
-        LIMIT_PRICE_PCT = 0.99
+        # Limit price threshold: As limit price should always be below stop-price
+        LIMIT_PRICE_PCT = self.strategy.order_types.get('stoploss_on_exchange_limit_ratio', 0.99)
 
         try:
             stoploss_order = self.exchange.stoploss_limit(pair=trade.pair, amount=trade.amount,


Test patch: