Repository: freqtrade/freqtrade

Issue:
stoploss on exchange partial fill not handled correctly
## Describe your environment

  * Operating system: Debian 10
  * Python Version: 3.10.10
  * CCXT version: 2.8.17
  * Freqtrade Version: 2023.2
  
## Describe the problem:

It seems that partially filled stoplosses are not cancelled correctly. It should be clear from the log below.

### Relevant code exceptions or logs

  ```
2023-03-23 15:22:55,603 - freqtrade.freqtradebot - INFO - Exit for BAX/USDT detected. Reason: custom_exit
2023-03-23 15:22:55,605 - freqtrade.freqtradebot - INFO - Canceling stoploss on exchange for Trade(id=321, pair=BAX/USDT, amount=80979.70860000, is_short=False, leverage=1.0, open_rate=0.00068480, open_since=2023-03-23 13:22:13)
2023-03-23 15:22:56,598 - freqtrade.wallets - INFO - Wallets synced.
2023-03-23 15:22:56,598 - freqtrade.freqtradebot - WARNING - Unable to exit trade BAX/USDT: Not enough amount to exit trade. Trade-amount: 80979.7086, Wallet: 61902.9074
  ```
stoploss on exchange partial fill not handled correctly
## Describe your environment

  * Operating system: Debian 10
  * Python Version: 3.10.10
  * CCXT version: 2.8.17
  * Freqtrade Version: 2023.2
  
## Describe the problem:

It seems that partially filled stoplosses are not cancelled correctly. It should be clear from the log below.

### Relevant code exceptions or logs

  ```
2023-03-23 15:22:55,603 - freqtrade.freqtradebot - INFO - Exit for BAX/USDT detected. Reason: custom_exit
2023-03-23 15:22:55,605 - freqtrade.freqtradebot - INFO - Canceling stoploss on exchange for Trade(id=321, pair=BAX/USDT, amount=80979.70860000, is_short=False, leverage=1.0, open_rate=0.00068480, open_since=2023-03-23 13:22:13)
2023-03-23 15:22:56,598 - freqtrade.wallets - INFO - Wallets synced.
2023-03-23 15:22:56,598 - freqtrade.freqtradebot - WARNING - Unable to exit trade BAX/USDT: Not enough amount to exit trade. Trade-amount: 80979.7086, Wallet: 61902.9074
  ```


Discussion:
to be honest, nothing in the log suggests that the stoploss is partially filled. All the log says is that there's not enough amount available. This COULD be caused by the exchange - but also by manual actions on the exchange.

can you show the partial fill from the exchange site (i assume it'll show up there in the orders section) ? 

Also, to properly look at this, we'll need the actual responses the exchange provides (it'll obviously assume the same thing happens again or is easily reproducible).
you can enable this via the config setting `"log_responses": true` in the exchange section of the configuration.

Here's a screenshot from the exchange. I'm in GMT+3, hence the difference in time.
![2023-03-24T10:01:56+03:00](https://user-images.githubusercontent.com/128742714/227450625-1ef864b8-42f6-40f1-ac80-fe8fbc4107ff.png)

I'll try to reproduce it and come back to you.
I managed to catch a similar issue, but this time a stoploss was canceled in order to add another one (it's a trailing stoploss).
```
2023-03-24 12:32:17,363 - freqtrade.exchange.exchange - INFO - API fetch_order: {'info': {'id': 'vs9qqp0tiutlea76000pgrft', 'symbol': 'UBX-USDT', 'opType': 'DEAL', 'type': 'limit', 'side': 'sell', 'price': '0.00007636', 'size': '729665.6745', 'funds': '0', 'dealFunds': '1.613410455272', 'dealSize': '21129.0002', 'fee': '0.001613410455272', 'feeCurrency': 'USDT', 'stp': '', 'stop': 'loss', 'stopTriggered': True, 'stopPrice': '0.00007636', 'timeInForce': 'GTC', 'postOnly': False, 'hidden': False, 'iceberg': False, 'visibleSize': '0', 'cancelAfter': -1, 'channel': 'API', 'clientOid': '0f6a6cbd-456d-47f0-b2ba-0ba0a334b7b7', 'remark': None, 'tags': 'partner:ccxt', 'isActive': True, 'cancelExist': False, 'createdAt': 1679661102486, 'tradeType': 'TRADE'}, 'id': 'vs9qqp0tiutlea76000pgrft', 'clientOrderId': '0f6a6cbd-456d-47f0-b2ba-0ba0a334b7b7', 'symbol': 'UBX/USDT', 'type': 'limit', 'timeInForce': 'GTC', 'postOnly': False, 'side': 'sell', 'amount': 729665.6745, 'price': 7.636e-05, 'stopPrice': 7.636e-05, 'triggerPrice': 7.636e-05, 'cost': 1.613410455272, 'filled': 21129.0002, 'remaining': 708536.6743, 'timestamp': 1679661102486, 'datetime': '2023-03-24T12:31:42.486Z', 'fee': {'currency': 'USDT', 'cost': 0.001613410455272}, 'status': 'open', 'lastTradeTimestamp': None, 'average': 7.636e-05, 'trades': [], 'fees': [{'currency': 'USDT', 'cost': 0.001613410455272}], 'reduceOnly': None}
2023-03-24 12:32:17,376 - freqtrade.freqtradebot - INFO - Cancelling current stoploss on exchange for pair UBX/USDT (orderid:vs9qqp0tiutlea76000pgrft) in order to add another one ...
2023-03-24 12:32:17,677 - freqtrade.exchange.exchange - INFO - API cancel_order: {'code': '200000', 'data': {'cancelledOrderIds': ['vs9qqp0tiutlea76000pgrft']}}
2023-03-24 12:32:17,943 - freqtrade.exchange.exchange - INFO - API fetch_order: {'info': {'id': 'vs9qqp0tiutlea76000pgrft', 'symbol': 'UBX-USDT', 'opType': 'DEAL', 'type': 'limit', 'side': 'sell', 'price': '0.00007636', 'size': '729665.6745', 'funds': '0', 'dealFunds': '1.613410455272', 'dealSize': '21129.0002', 'fee': '0.001613410455272', 'feeCurrency': 'USDT', 'stp': '', 'stop': 'loss', 'stopTriggered': True, 'stopPrice': '0.00007636', 'timeInForce': 'GTC', 'postOnly': False, 'hidden': False, 'iceberg': False, 'visibleSize': '0', 'cancelAfter': -1, 'channel': 'API', 'clientOid': '0f6a6cbd-456d-47f0-b2ba-0ba0a334b7b7', 'remark': None, 'tags': 'partner:ccxt', 'isActive': False, 'cancelExist': True, 'createdAt': 1679661102486, 'tradeType': 'TRADE'}, 'id': 'vs9qqp0tiutlea76000pgrft', 'clientOrderId': '0f6a6cbd-456d-47f0-b2ba-0ba0a334b7b7', 'symbol': 'UBX/USDT', 'type': 'limit', 'timeInForce': 'GTC', 'postOnly': False, 'side': 'sell', 'amount': 729665.6745, 'price': 7.636e-05, 'stopPrice': 7.636e-05, 'triggerPrice': 7.636e-05, 'cost': 1.613410455272, 'filled': 21129.0002, 'remaining': 708536.6743, 'timestamp': 1679661102486, 'datetime': '2023-03-24T12:31:42.486Z', 'fee': {'currency': 'USDT', 'cost': 0.001613410455272}, 'status': 'canceled', 'lastTradeTimestamp': None, 'average': 7.636e-05, 'trades': [], 'fees': [{'currency': 'USDT', 'cost': 0.001613410455272}], 'reduceOnly': None}
2023-03-24 12:32:18,228 - freqtrade.exchange.exchange - INFO - API create_stoploss_order: {'info': {'orderId': 'vs9qqp0tj196j6lh000l70k6'}, 'id': 'vs9qqp0tj196j6lh000l70k6', 'clientOrderId': None, 'symbol': 'UBX/USDT', 'type': None, 'timeInForce': None, 'postOnly': None, 'side': None, 'amount': None, 'price': None, 'stopPrice': None, 'triggerPrice': None, 'cost': None, 'filled': None, 'remaining': None, 'timestamp': None, 'datetime': None, 'fee': {'currency': None, 'cost': None}, 'status': 'closed', 'lastTradeTimestamp': None, 'average': None, 'trades': [], 'fees': [{'currency': None, 'cost': None}], 'reduceOnly': None}
2023-03-24 12:32:18,228 - freqtrade.exchange.exchange - INFO - stoploss limit order added for UBX/USDT. stop price: 7.76e-05. limit: 7.76e-05
```

The new stoploss has the wrong amount, and keeps getting canceled by the exchange.
![2023-03-24T15:40:04+03:00](https://user-images.githubusercontent.com/128742714/227533098-3894f588-3124-4f8c-b98a-9659ffc2ff8a.png)

I don't see any logs related to the cancellation, freqtrade just tries to add a stoploss order again and again.
```
2023-03-24 12:34:07,340 - freqtrade.exchange.exchange - INFO - API fetch_order: {'info': {'id': 'vs9qqp0tj196j6lh000l70k6', 'symbol': 'UBX-USDT', 'opType': 'DEAL', 'type': 'limit', 'side': 'sell', 'price': '0.0000776', 'size': '729665.6745', 'funds': None, 'dealFunds': None, 'dealSize': '0', 'fee': '0', 'feeCurrency': 'USDT', 'stp': None, 'stop': 'loss', 'stopTriggered': True, 'stopPrice': '0.0000776', 'timeInForce': 'GTC', 'postOnly': False, 'hidden': False, 'iceberg': False, 'visibleSize': None, 'cancelAfter': -1, 'channel': 'API', 'clientOid': '4bf04d97-57a8-4aef-8267-104ff151c7d9', 'remark': None, 'tags': 'partner:ccxt', 'isActive': False, 'cancelExist': True, 'createdAt': 1679661138128, 'tradeType': 'TRADE'}, 'id': 'vs9qqp0tj196j6lh000l70k6', 'clientOrderId': '4bf04d97-57a8-4aef-8267-104ff151c7d9', 'symbol': 'UBX/USDT', 'type': 'limit', 'timeInForce': 'GTC', 'postOnly': False, 'side': 'sell', 'amount': 729665.6745, 'price': 7.76e-05, 'stopPrice': 7.76e-05, 'triggerPrice': 7.76e-05, 'cost': 0.0, 'filled': 0.0, 'remaining': 729665.6745, 'timestamp': 1679661138128, 'datetime': '2023-03-24T12:32:18.128Z', 'fee': {'currency': 'USDT', 'cost': 0.0}, 'status': 'canceled', 'lastTradeTimestamp': None, 'average': None, 'trades': [], 'fees': [{'currency': 'USDT', 'cost': 0.0}], 'reduceOnly': None}
2023-03-24 12:34:07,620 - freqtrade.exchange.exchange - INFO - API create_stoploss_order: {'info': {'orderId': 'vs9qqp0tj2vijqr7000om8k3'}, 'id': 'vs9qqp0tj2vijqr7000om8k3', 'clientOrderId': None, 'symbol': 'UBX/USDT', 'type': None, 'timeInForce': None, 'postOnly': None, 'side': None, 'amount': None, 'price': None, 'stopPrice': None, 'triggerPrice': None, 'cost': None, 'filled': None, 'remaining': None, 'timestamp': None, 'datetime': None, 'fee': {'currency': None, 'cost': None}, 'status': 'closed', 'lastTradeTimestamp': None, 'average': None, 'trades': [], 'fees': [{'currency': None, 'cost': None}], 'reduceOnly': None}
2023-03-24 12:34:07,621 - freqtrade.exchange.exchange - INFO - stoploss limit order added for UBX/USDT. stop price: 7.76e-05. limit: 7.76e-05
```
Quite honestly - i'm not sure i see the issue here.

it's placing the stoploss just fine. 
now the recancellation seem odd - but are probably due to rounding issues with such low-priced pairs.

btw what exchange are we talking about here? (the UI's all look that identical so you can't really tell from these screenshots).
For me, it doesn't seem right that it is placing an order for the same amount, even though the previous order has been partially filled and the wallet doesn't have the same amount anymore.
![2023-03-24T15:40:04+03:00_filled](https://user-images.githubusercontent.com/128742714/227606053-698b20be-4b47-4017-bb4d-0e18d1d48d41.png)


The exchange is Kucoin. I can try it on Huobi to see if the same thing happens, but it will take some time.

Also, I tried to force exit the trade after that, and it failed:
```
2023-03-24 12:40:47,420 - freqtrade.freqtradebot - INFO - Canceling stoploss on exchange for Trade(id=326, pair=UBX/USDT, amount=729665.67450000, is_short=False, leverage=1.0, open_rate=0.00006938, open_since=2023-03-24 06:51:40)
2023-03-24 12:40:47,755 - freqtrade.freqtradebot - ERROR - Could not cancel stoploss order vs9qqp0tj7t2jqr7000om8mh
Traceback (most recent call last):
  File "/freqtrade/freqtrade/exchange/exchange.py", line 1292, in cancel_order
    order = self._api.cancel_order(order_id, pair, params=params)
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/kucoin.py", line 1494, in cancel_order
    return getattr(self, method)(self.extend(request, params))
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/base/exchange.py", line 505, in inner
    return entry(_self, **inner_kwargs)
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/base/exchange.py", line 2833, in request
    return self.fetch2(path, api, method, params, headers, body, config, context)
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/base/exchange.py", line 2830, in fetch2
    return self.fetch(request['url'], request['method'], request['headers'], request['body'])
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/base/exchange.py", line 667, in fetch
    self.handle_errors(http_status_code, http_status_text, url, method, headers, http_response, json_response, request_headers, request_body)
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/kucoin.py", line 3356, in handle_errors
    self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/base/exchange.py", line 3133, in throw_exactly_matched_exception
    raise exact[string](message)
ccxt.base.errors.InvalidOrder: kucoin order_not_exist_or_not_allow_to_cancel

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/freqtrade/freqtrade/freqtradebot.py", line 847, in cancel_stoploss_on_exchange
    co = self.exchange.cancel_stoploss_order_with_result(
  File "/freqtrade/freqtrade/exchange/exchange.py", line 1358, in cancel_stoploss_order_with_result
    corder = self.cancel_stoploss_order(order_id, pair)
  File "/freqtrade/freqtrade/exchange/exchange.py", line 1308, in cancel_stoploss_order
    return self.cancel_order(order_id, pair, params)
  File "/freqtrade/freqtrade/exchange/common.py", line 164, in wrapper
    return f(*args, **kwargs)
  File "/freqtrade/freqtrade/exchange/exchange.py", line 1297, in cancel_order
    raise InvalidOrderException(
freqtrade.exceptions.InvalidOrderException: Could not cancel order. Message: kucoin order_not_exist_or_not_allow_to_cancel
2023-03-24 12:40:48,175 - freqtrade.wallets - INFO - Wallets synced.
2023-03-24 12:40:48,188 - uvicorn.error - ERROR - Exception in ASGI application
Traceback (most recent call last):
  File "/home/ftuser/.local/lib/python3.10/site-packages/uvicorn/protocols/http/h11_impl.py", line 407, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
  File "/home/ftuser/.local/lib/python3.10/site-packages/uvicorn/middleware/proxy_headers.py", line 78, in __call__
    return await self.app(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/uvicorn/middleware/message_logger.py", line 86, in __call__
    raise exc from None
  File "/home/ftuser/.local/lib/python3.10/site-packages/uvicorn/middleware/message_logger.py", line 82, in __call__
    await self.app(scope, inner_receive, inner_send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/fastapi/applications.py", line 271, in __call__
    await super().__call__(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/applications.py", line 118, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/middleware/errors.py", line 184, in __call__
    raise exc
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/middleware/errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/middleware/cors.py", line 92, in __call__
    await self.simple_response(scope, receive, send, request_headers=headers)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/middleware/cors.py", line 147, in simple_response
    await self.app(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
    raise exc
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "/home/ftuser/.local/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
    raise e
  File "/home/ftuser/.local/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/routing.py", line 706, in __call__
    await route.handle(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/routing.py", line 276, in handle
    await self.app(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/routing.py", line 66, in app
    response = await func(request)
  File "/home/ftuser/.local/lib/python3.10/site-packages/fastapi/routing.py", line 237, in app
    raw_response = await run_endpoint_function(
  File "/home/ftuser/.local/lib/python3.10/site-packages/fastapi/routing.py", line 165, in run_endpoint_function
    return await run_in_threadpool(dependant.call, **values)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/concurrency.py", line 41, in run_in_threadpool
    return await anyio.to_thread.run_sync(func, *args)
  File "/home/ftuser/.local/lib/python3.10/site-packages/anyio/to_thread.py", line 31, in run_sync
    return await get_asynclib().run_sync_in_worker_thread(
  File "/home/ftuser/.local/lib/python3.10/site-packages/anyio/_backends/_asyncio.py", line 937, in run_sync_in_worker_thread
    return await future
  File "/home/ftuser/.local/lib/python3.10/site-packages/anyio/_backends/_asyncio.py", line 867, in run
    result = context.run(func, *args)
  File "/freqtrade/freqtrade/rpc/api_server/api_v1.py", line 174, in forceexit
    return rpc._rpc_force_exit(payload.tradeid, ordertype, amount=payload.amount)
  File "/freqtrade/freqtrade/rpc/rpc.py", line 744, in _rpc_force_exit
    self.__exec_force_exit(trade, ordertype, amount)
  File "/freqtrade/freqtrade/rpc/rpc.py", line 713, in __exec_force_exit
    self._freqtrade.execute_trade_exit(
  File "/freqtrade/freqtrade/freqtradebot.py", line 1578, in execute_trade_exit
    amount = self._safe_exit_amount(trade, trade.pair, sub_trade_amt or trade.amount)
  File "/freqtrade/freqtrade/freqtradebot.py", line 1522, in _safe_exit_amount
    raise DependencyException(
freqtrade.exceptions.DependencyException: Not enough amount to exit trade. Trade-amount: 729665.6745, Wallet: 708536.6743
```
using kucoin explains the re-placements.
their api reports precisions of around between 10e-10 and 10e-13 or so (depending on the pair) - but the UI only renders about 8 of these. So while it looks like all orders are for the same price - they're actually not - and your stoploss will have (slightly) moved.


I still don't understand why you'd get tons of partial fills on stoploss orders - I've never seen / had that before - and i've done quite some trades throughout the different exchanges.
I could understand that it may happen with some (bad) luck - but not twice in a day - that makes it seem that your stop/limit distance might be odd.

---

Please provide the output of the following command for the affected trade:
`freqtrade show-trades --db-url sqlite:///<trades.sqlite> --print-json --trade-ids <tradeid>` 
Please use a "details block" to keep the issue itself kindof readable (see below for details on how to do that). 

<details>
<summary>Expand to see how to do details blocks</summary>

```
<details>
<summary>Expand full </summary>
(wrap in tripple ticks `)
Trades output ...
</details>
```
</details>

The second partial fill happened because I intentionally increased stoploss_on_exchange_limit_ratio to catch the issue.

Also, I want to experiment with short stop/limit distance anyway. The idea is to use stoploss on exchange first, and then sell whatever is left using custom_exit.

I've already deleted the affected trades, will try to reproduce it again.
Here you go:
<details>
<summary>logs: custom exit failed</summary>

```
2023-03-25 00:33:07 - freqtrade.freqtradebot - INFO - Exit for PRE/USDT detected. Reason: custom_exit
2023-03-25 00:33:07 - freqtrade.freqtradebot - INFO - Canceling stoploss on exchange for Trade(id=332, pair=PRE/USDT, amount=524.24240000, is_short=False, leverage=1.0, open_rate=0.09698699, open_since=2023-03-25 00:12:16)
2023-03-25 00:33:07 - freqtrade.exchange.exchange - INFO - API cancel_order: {'code': '200000', 'data': {'cancelledOrderIds': ['vs9dsp0u7o65ea76000ph82k']}}
2023-03-25 00:33:08 - freqtrade.exchange.exchange - INFO - API fetch_order: {'info': {'id': 'vs9dsp0u7o65ea76000ph82k', 'symbol': 'PRE-USDT', 'opType': 'DEAL', 'type': 'limit', 'side': 'sell', 'price': '0.103784', 'size': '524.2424', 'funds': '0', 'dealFunds': '41.0282229888', 'dealSize': '395.3232', 'fee': '0.0410282229888', 'feeCurrency': 'USDT', 'stp': '', 'stop': 'loss', 'stopTriggered': True, 'stopPrice': '0.103887', 'timeInForce': 'GTC', 'postOnly': False, 'hidden': False, 'iceberg': False, 'visibleSize': '0', 'cancelAfter': -1, 'channel': 'API', 'clientOid': 'bc63744c-eeca-4d0b-969a-6096b48bbbc0', 'remark': None, 'tags': 'partner:ccxt', 'isActive': False, 'cancelExist': True, 'createdAt': 1679703588944, 'tradeType': 'TRADE'}, 'id': 'vs9dsp0u7o65ea76000ph82k', 'clientOrderId': 'bc63744c-eeca-4d0b-969a-6096b48bbbc0', 'symbol': 'PRE/USDT', 'type': 'limit', 'timeInForce': 'GTC', 'postOnly': False, 'side': 'sell', 'amount': 524.2424, 'price': 0.103784, 'stopPrice': 0.103887, 'triggerPrice': 0.103887, 'cost': 41.0282229888, 'filled': 395.3232, 'remaining': 128.9192, 'timestamp': 1679703588944, 'datetime': '2023-03-25T00:19:48.944Z', 'fee': {'currency': 'USDT', 'cost': 0.0410282229888}, 'status': 'canceled', 'lastTradeTimestamp': None, 'average': 0.103784, 'trades': [], 'fees': [{'currency': 'USDT', 'cost': 0.0410282229888}], 'reduceOnly': None}
2023-03-25 00:33:08 - freqtrade.wallets - INFO - Wallets synced.
2023-03-25 00:33:08 - freqtrade.freqtradebot - WARNING - Unable to exit trade PRE/USDT: Not enough amount to exit trade. Trade-amount: 524.2424, Wallet: 128.9192
```
</details>
<details>
<summary>logs: force exit failed</summary>

```
2023-03-25 00:39:10 - freqtrade.freqtradebot - INFO - Canceling stoploss on exchange for Trade(id=332, pair=PRE/USDT, amount=524.24240000, is_short=False, leverage=1.0, open_rate=0.09698699, open_since=2023-03-25 00:12:16)
2023-03-25 00:39:10 - freqtrade.freqtradebot - ERROR - Could not cancel stoploss order vs9dsp0u8a5mj6lh000l7dc7
Traceback (most recent call last):
  File "/freqtrade/freqtrade/exchange/exchange.py", line 1292, in cancel_order
    order = self._api.cancel_order(order_id, pair, params=params)
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/kucoin.py", line 1494, in cancel_order
    return getattr(self, method)(self.extend(request, params))
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/base/exchange.py", line 505, in inner
    return entry(_self, **inner_kwargs)
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/base/exchange.py", line 2833, in request
    return self.fetch2(path, api, method, params, headers, body, config, context)
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/base/exchange.py", line 2830, in fetch2
    return self.fetch(request['url'], request['method'], request['headers'], request['body'])
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/base/exchange.py", line 667, in fetch
    self.handle_errors(http_status_code, http_status_text, url, method, headers, http_response, json_response, request_headers, request_body)
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/kucoin.py", line 3356, in handle_errors
    self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/base/exchange.py", line 3133, in throw_exactly_matched_exception
    raise exact[string](message)
ccxt.base.errors.InvalidOrder: kucoin order_not_exist_or_not_allow_to_cancel

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/freqtrade/freqtrade/freqtradebot.py", line 847, in cancel_stoploss_on_exchange
    co = self.exchange.cancel_stoploss_order_with_result(
  File "/freqtrade/freqtrade/exchange/exchange.py", line 1358, in cancel_stoploss_order_with_result
    corder = self.cancel_stoploss_order(order_id, pair)
  File "/freqtrade/freqtrade/exchange/exchange.py", line 1308, in cancel_stoploss_order
    return self.cancel_order(order_id, pair, params)
  File "/freqtrade/freqtrade/exchange/common.py", line 164, in wrapper
    return f(*args, **kwargs)
  File "/freqtrade/freqtrade/exchange/exchange.py", line 1297, in cancel_order
    raise InvalidOrderException(
freqtrade.exceptions.InvalidOrderException: Could not cancel order. Message: kucoin order_not_exist_or_not_allow_to_cancel
2023-03-25 00:39:10 - freqtrade.wallets - INFO - Wallets synced.
2023-03-25 00:39:10 - uvicorn.error - ERROR - Exception in ASGI application

Traceback (most recent call last):
  File "/home/ftuser/.local/lib/python3.10/site-packages/uvicorn/protocols/http/h11_impl.py", line 407, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
  File "/home/ftuser/.local/lib/python3.10/site-packages/uvicorn/middleware/proxy_headers.py", line 78, in __call__
    return await self.app(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/uvicorn/middleware/message_logger.py", line 86, in __call__
    raise exc from None
  File "/home/ftuser/.local/lib/python3.10/site-packages/uvicorn/middleware/message_logger.py", line 82, in __call__
    await self.app(scope, inner_receive, inner_send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/fastapi/applications.py", line 271, in __call__
    await super().__call__(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/applications.py", line 118, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/middleware/errors.py", line 184, in __call__
    raise exc
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/middleware/errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/middleware/cors.py", line 92, in __call__
    await self.simple_response(scope, receive, send, request_headers=headers)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/middleware/cors.py", line 147, in simple_response
    await self.app(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
    raise exc
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "/home/ftuser/.local/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
    raise e
  File "/home/ftuser/.local/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/routing.py", line 706, in __call__
    await route.handle(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/routing.py", line 276, in handle
    await self.app(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/routing.py", line 66, in app
    response = await func(request)
  File "/home/ftuser/.local/lib/python3.10/site-packages/fastapi/routing.py", line 237, in app
    raw_response = await run_endpoint_function(
  File "/home/ftuser/.local/lib/python3.10/site-packages/fastapi/routing.py", line 165, in run_endpoint_function
    return await run_in_threadpool(dependant.call, **values)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/concurrency.py", line 41, in run_in_threadpool
    return await anyio.to_thread.run_sync(func, *args)
  File "/home/ftuser/.local/lib/python3.10/site-packages/anyio/to_thread.py", line 31, in run_sync
    return await get_asynclib().run_sync_in_worker_thread(
  File "/home/ftuser/.local/lib/python3.10/site-packages/anyio/_backends/_asyncio.py", line 937, in run_sync_in_worker_thread
    return await future
  File "/home/ftuser/.local/lib/python3.10/site-packages/anyio/_backends/_asyncio.py", line 867, in run
    result = context.run(func, *args)
  File "/freqtrade/freqtrade/rpc/api_server/api_v1.py", line 174, in forceexit
    return rpc._rpc_force_exit(payload.tradeid, ordertype, amount=payload.amount)
  File "/freqtrade/freqtrade/rpc/rpc.py", line 744, in _rpc_force_exit
    self.__exec_force_exit(trade, ordertype, amount)
  File "/freqtrade/freqtrade/rpc/rpc.py", line 713, in __exec_force_exit
    self._freqtrade.execute_trade_exit(
  File "/freqtrade/freqtrade/freqtradebot.py", line 1578, in execute_trade_exit
    amount = self._safe_exit_amount(trade, trade.pair, sub_trade_amt or trade.amount)
  File "/freqtrade/freqtrade/freqtradebot.py", line 1522, in _safe_exit_amount
    raise DependencyException(
freqtrade.exceptions.DependencyException: Not enough amount to exit trade. Trade-amount: 524.2424, Wallet: 128.9192

```
</details>
<details>
<summary>show-trades</summary>

```
2023-03-25 00:39:46,077 - freqtrade - INFO - freqtrade 2023.2
2023-03-25 00:39:46,078 - freqtrade.loggers - INFO - Verbosity set to 0
2023-03-25 00:39:46,078 - freqtrade.configuration.configuration - INFO - Parameter --db-url detected ...
2023-03-25 00:39:46,097 - freqtrade.configuration.configuration - INFO - Using user-data directory: /freqtrade/user_data ...
2023-03-25 00:39:46,098 - freqtrade.configuration.configuration - INFO - Using data directory: /freqtrade/user_data/data ...
2023-03-25 00:39:46,098 - freqtrade.configuration.configuration - INFO - Parameter --print-json detected ...
2023-03-25 00:39:46,098 - freqtrade.configuration.configuration - INFO - Filtering on trade_ids: ['332']
2023-03-25 00:39:46,099 - freqtrade.configuration.config_validation - INFO - Validating configuration ...
2023-03-25 00:39:46,106 - freqtrade.commands.list_commands - INFO - Using DB: "sqlite:////freqtrade/user_data/tradesv3.sqlite"
2023-03-25 00:39:46,179 - freqtrade.commands.list_commands - INFO - Printing 1 Trades:
[
    {
        "trade_id": 332,
        "pair": "PRE/USDT",
        "base_currency": "PRE",
        "quote_currency": "USDT",
        "is_open": true,
        "exchange": "kucoin",
        "amount": 524.2424,
        "amount_requested": 524.24248067,
        "stake_amount": 50.84469045,
        "max_stake_amount": 50.84469045,
        "strategy": "hhll",
        "enter_tag": null,
        "timeframe": 5,
        "fee_open": 0.001,
        "fee_open_cost": 0.0508446904487,
        "fee_open_currency": "USDT",
        "fee_close": 0.001,
        "fee_close_cost": null,
        "fee_close_currency": null,
        "open_date": "2023-03-25 00:12:16",
        "open_timestamp": 1679703136150,
        "open_rate": 0.09698698626570457,
        "open_rate_requested": 0.097073,
        "open_trade_value": 50.89553514,
        "close_date": null,
        "close_timestamp": null,
        "realized_profit": 0.0,
        "close_rate": null,
        "close_rate_requested": null,
        "close_profit": null,
        "close_profit_pct": null,
        "close_profit_abs": null,
        "trade_duration_s": null,
        "trade_duration": null,
        "profit_ratio": null,
        "profit_pct": null,
        "profit_abs": null,
        "exit_reason": null,
        "exit_order_status": null,
        "stop_loss_abs": 0.103887,
        "stop_loss_ratio": -0.01,
        "stop_loss_pct": -1.0,
        "stoploss_order_id": "vs9dsp0u8aulea76000ph8cd",
        "stoploss_last_update": "2023-03-25 00:39:25",
        "stoploss_last_update_timestamp": 1679704765270,
        "initial_stop_loss_abs": 0.00485,
        "initial_stop_loss_ratio": -0.95,
        "initial_stop_loss_pct": -95.0,
        "min_rate": 0.09698698626570457,
        "max_rate": 0.104936,
        "leverage": 1.0,
        "interest_rate": 0.0,
        "liquidation_price": null,
        "is_short": false,
        "trading_mode": "spot",
        "funding_fees": 0.0,
        "open_order_id": null,
        "orders": [
            {
                "amount": 524.2424,
                "safe_price": 0.09698698626570457,
                "ft_order_side": "buy",
                "order_filled_timestamp": 1679703198245,
                "ft_is_entry": true,
                "pair": "PRE/USDT",
                "order_id": "641e3c5fb2c265000152add6",
                "status": "closed",
                "average": 0.09698699,
                "cost": 50.8446904487,
                "filled": 524.2424,
                "is_open": false,
                "order_date": "2023-03-25 00:12:16",
                "order_timestamp": 1679703136011,
                "order_filled_date": "2023-03-25 00:13:18",
                "order_type": "limit",
                "price": 0.097073,
                "remaining": 0.0
            },
            {
                "amount": 524.2424,
                "safe_price": 0.103784,
                "ft_order_side": "stoploss",
                "order_filled_timestamp": 1679704388053,
                "ft_is_entry": false,
                "pair": "PRE/USDT",
                "order_id": "vs9dsp0u7o65ea76000ph82k",
                "status": "canceled",
                "average": 0.103784,
                "cost": 41.0282229888,
                "filled": 395.3232,
                "is_open": false,
                "order_date": "2023-03-25 00:19:48",
                "order_timestamp": 1679703588944,
                "order_filled_date": "2023-03-25 00:33:08",
                "order_type": "limit",
                "price": 0.103784,
                "remaining": 128.9192
            }
        ]
    }
]
```
</details>
Interesting - the order response does contain the partial filled amount - but i guess one base assumption was that stop orders fill in total - which is what I've seen so far (i NEVER had a stop fill partially on any exchange).

it's therefore very well possible that there's no code to actually handle this.

to be honest, nothing in the log suggests that the stoploss is partially filled. All the log says is that there's not enough amount available. This COULD be caused by the exchange - but also by manual actions on the exchange.

can you show the partial fill from the exchange site (i assume it'll show up there in the orders section) ? 

Also, to properly look at this, we'll need the actual responses the exchange provides (it'll obviously assume the same thing happens again or is easily reproducible).
you can enable this via the config setting `"log_responses": true` in the exchange section of the configuration.

Here's a screenshot from the exchange. I'm in GMT+3, hence the difference in time.
![2023-03-24T10:01:56+03:00](https://user-images.githubusercontent.com/128742714/227450625-1ef864b8-42f6-40f1-ac80-fe8fbc4107ff.png)

I'll try to reproduce it and come back to you.
I managed to catch a similar issue, but this time a stoploss was canceled in order to add another one (it's a trailing stoploss).
```
2023-03-24 12:32:17,363 - freqtrade.exchange.exchange - INFO - API fetch_order: {'info': {'id': 'vs9qqp0tiutlea76000pgrft', 'symbol': 'UBX-USDT', 'opType': 'DEAL', 'type': 'limit', 'side': 'sell', 'price': '0.00007636', 'size': '729665.6745', 'funds': '0', 'dealFunds': '1.613410455272', 'dealSize': '21129.0002', 'fee': '0.001613410455272', 'feeCurrency': 'USDT', 'stp': '', 'stop': 'loss', 'stopTriggered': True, 'stopPrice': '0.00007636', 'timeInForce': 'GTC', 'postOnly': False, 'hidden': False, 'iceberg': False, 'visibleSize': '0', 'cancelAfter': -1, 'channel': 'API', 'clientOid': '0f6a6cbd-456d-47f0-b2ba-0ba0a334b7b7', 'remark': None, 'tags': 'partner:ccxt', 'isActive': True, 'cancelExist': False, 'createdAt': 1679661102486, 'tradeType': 'TRADE'}, 'id': 'vs9qqp0tiutlea76000pgrft', 'clientOrderId': '0f6a6cbd-456d-47f0-b2ba-0ba0a334b7b7', 'symbol': 'UBX/USDT', 'type': 'limit', 'timeInForce': 'GTC', 'postOnly': False, 'side': 'sell', 'amount': 729665.6745, 'price': 7.636e-05, 'stopPrice': 7.636e-05, 'triggerPrice': 7.636e-05, 'cost': 1.613410455272, 'filled': 21129.0002, 'remaining': 708536.6743, 'timestamp': 1679661102486, 'datetime': '2023-03-24T12:31:42.486Z', 'fee': {'currency': 'USDT', 'cost': 0.001613410455272}, 'status': 'open', 'lastTradeTimestamp': None, 'average': 7.636e-05, 'trades': [], 'fees': [{'currency': 'USDT', 'cost': 0.001613410455272}], 'reduceOnly': None}
2023-03-24 12:32:17,376 - freqtrade.freqtradebot - INFO - Cancelling current stoploss on exchange for pair UBX/USDT (orderid:vs9qqp0tiutlea76000pgrft) in order to add another one ...
2023-03-24 12:32:17,677 - freqtrade.exchange.exchange - INFO - API cancel_order: {'code': '200000', 'data': {'cancelledOrderIds': ['vs9qqp0tiutlea76000pgrft']}}
2023-03-24 12:32:17,943 - freqtrade.exchange.exchange - INFO - API fetch_order: {'info': {'id': 'vs9qqp0tiutlea76000pgrft', 'symbol': 'UBX-USDT', 'opType': 'DEAL', 'type': 'limit', 'side': 'sell', 'price': '0.00007636', 'size': '729665.6745', 'funds': '0', 'dealFunds': '1.613410455272', 'dealSize': '21129.0002', 'fee': '0.001613410455272', 'feeCurrency': 'USDT', 'stp': '', 'stop': 'loss', 'stopTriggered': True, 'stopPrice': '0.00007636', 'timeInForce': 'GTC', 'postOnly': False, 'hidden': False, 'iceberg': False, 'visibleSize': '0', 'cancelAfter': -1, 'channel': 'API', 'clientOid': '0f6a6cbd-456d-47f0-b2ba-0ba0a334b7b7', 'remark': None, 'tags': 'partner:ccxt', 'isActive': False, 'cancelExist': True, 'createdAt': 1679661102486, 'tradeType': 'TRADE'}, 'id': 'vs9qqp0tiutlea76000pgrft', 'clientOrderId': '0f6a6cbd-456d-47f0-b2ba-0ba0a334b7b7', 'symbol': 'UBX/USDT', 'type': 'limit', 'timeInForce': 'GTC', 'postOnly': False, 'side': 'sell', 'amount': 729665.6745, 'price': 7.636e-05, 'stopPrice': 7.636e-05, 'triggerPrice': 7.636e-05, 'cost': 1.613410455272, 'filled': 21129.0002, 'remaining': 708536.6743, 'timestamp': 1679661102486, 'datetime': '2023-03-24T12:31:42.486Z', 'fee': {'currency': 'USDT', 'cost': 0.001613410455272}, 'status': 'canceled', 'lastTradeTimestamp': None, 'average': 7.636e-05, 'trades': [], 'fees': [{'currency': 'USDT', 'cost': 0.001613410455272}], 'reduceOnly': None}
2023-03-24 12:32:18,228 - freqtrade.exchange.exchange - INFO - API create_stoploss_order: {'info': {'orderId': 'vs9qqp0tj196j6lh000l70k6'}, 'id': 'vs9qqp0tj196j6lh000l70k6', 'clientOrderId': None, 'symbol': 'UBX/USDT', 'type': None, 'timeInForce': None, 'postOnly': None, 'side': None, 'amount': None, 'price': None, 'stopPrice': None, 'triggerPrice': None, 'cost': None, 'filled': None, 'remaining': None, 'timestamp': None, 'datetime': None, 'fee': {'currency': None, 'cost': None}, 'status': 'closed', 'lastTradeTimestamp': None, 'average': None, 'trades': [], 'fees': [{'currency': None, 'cost': None}], 'reduceOnly': None}
2023-03-24 12:32:18,228 - freqtrade.exchange.exchange - INFO - stoploss limit order added for UBX/USDT. stop price: 7.76e-05. limit: 7.76e-05
```

The new stoploss has the wrong amount, and keeps getting canceled by the exchange.
![2023-03-24T15:40:04+03:00](https://user-images.githubusercontent.com/128742714/227533098-3894f588-3124-4f8c-b98a-9659ffc2ff8a.png)

I don't see any logs related to the cancellation, freqtrade just tries to add a stoploss order again and again.
```
2023-03-24 12:34:07,340 - freqtrade.exchange.exchange - INFO - API fetch_order: {'info': {'id': 'vs9qqp0tj196j6lh000l70k6', 'symbol': 'UBX-USDT', 'opType': 'DEAL', 'type': 'limit', 'side': 'sell', 'price': '0.0000776', 'size': '729665.6745', 'funds': None, 'dealFunds': None, 'dealSize': '0', 'fee': '0', 'feeCurrency': 'USDT', 'stp': None, 'stop': 'loss', 'stopTriggered': True, 'stopPrice': '0.0000776', 'timeInForce': 'GTC', 'postOnly': False, 'hidden': False, 'iceberg': False, 'visibleSize': None, 'cancelAfter': -1, 'channel': 'API', 'clientOid': '4bf04d97-57a8-4aef-8267-104ff151c7d9', 'remark': None, 'tags': 'partner:ccxt', 'isActive': False, 'cancelExist': True, 'createdAt': 1679661138128, 'tradeType': 'TRADE'}, 'id': 'vs9qqp0tj196j6lh000l70k6', 'clientOrderId': '4bf04d97-57a8-4aef-8267-104ff151c7d9', 'symbol': 'UBX/USDT', 'type': 'limit', 'timeInForce': 'GTC', 'postOnly': False, 'side': 'sell', 'amount': 729665.6745, 'price': 7.76e-05, 'stopPrice': 7.76e-05, 'triggerPrice': 7.76e-05, 'cost': 0.0, 'filled': 0.0, 'remaining': 729665.6745, 'timestamp': 1679661138128, 'datetime': '2023-03-24T12:32:18.128Z', 'fee': {'currency': 'USDT', 'cost': 0.0}, 'status': 'canceled', 'lastTradeTimestamp': None, 'average': None, 'trades': [], 'fees': [{'currency': 'USDT', 'cost': 0.0}], 'reduceOnly': None}
2023-03-24 12:34:07,620 - freqtrade.exchange.exchange - INFO - API create_stoploss_order: {'info': {'orderId': 'vs9qqp0tj2vijqr7000om8k3'}, 'id': 'vs9qqp0tj2vijqr7000om8k3', 'clientOrderId': None, 'symbol': 'UBX/USDT', 'type': None, 'timeInForce': None, 'postOnly': None, 'side': None, 'amount': None, 'price': None, 'stopPrice': None, 'triggerPrice': None, 'cost': None, 'filled': None, 'remaining': None, 'timestamp': None, 'datetime': None, 'fee': {'currency': None, 'cost': None}, 'status': 'closed', 'lastTradeTimestamp': None, 'average': None, 'trades': [], 'fees': [{'currency': None, 'cost': None}], 'reduceOnly': None}
2023-03-24 12:34:07,621 - freqtrade.exchange.exchange - INFO - stoploss limit order added for UBX/USDT. stop price: 7.76e-05. limit: 7.76e-05
```
Quite honestly - i'm not sure i see the issue here.

it's placing the stoploss just fine. 
now the recancellation seem odd - but are probably due to rounding issues with such low-priced pairs.

btw what exchange are we talking about here? (the UI's all look that identical so you can't really tell from these screenshots).
For me, it doesn't seem right that it is placing an order for the same amount, even though the previous order has been partially filled and the wallet doesn't have the same amount anymore.
![2023-03-24T15:40:04+03:00_filled](https://user-images.githubusercontent.com/128742714/227606053-698b20be-4b47-4017-bb4d-0e18d1d48d41.png)


The exchange is Kucoin. I can try it on Huobi to see if the same thing happens, but it will take some time.

Also, I tried to force exit the trade after that, and it failed:
```
2023-03-24 12:40:47,420 - freqtrade.freqtradebot - INFO - Canceling stoploss on exchange for Trade(id=326, pair=UBX/USDT, amount=729665.67450000, is_short=False, leverage=1.0, open_rate=0.00006938, open_since=2023-03-24 06:51:40)
2023-03-24 12:40:47,755 - freqtrade.freqtradebot - ERROR - Could not cancel stoploss order vs9qqp0tj7t2jqr7000om8mh
Traceback (most recent call last):
  File "/freqtrade/freqtrade/exchange/exchange.py", line 1292, in cancel_order
    order = self._api.cancel_order(order_id, pair, params=params)
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/kucoin.py", line 1494, in cancel_order
    return getattr(self, method)(self.extend(request, params))
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/base/exchange.py", line 505, in inner
    return entry(_self, **inner_kwargs)
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/base/exchange.py", line 2833, in request
    return self.fetch2(path, api, method, params, headers, body, config, context)
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/base/exchange.py", line 2830, in fetch2
    return self.fetch(request['url'], request['method'], request['headers'], request['body'])
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/base/exchange.py", line 667, in fetch
    self.handle_errors(http_status_code, http_status_text, url, method, headers, http_response, json_response, request_headers, request_body)
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/kucoin.py", line 3356, in handle_errors
    self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/base/exchange.py", line 3133, in throw_exactly_matched_exception
    raise exact[string](message)
ccxt.base.errors.InvalidOrder: kucoin order_not_exist_or_not_allow_to_cancel

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/freqtrade/freqtrade/freqtradebot.py", line 847, in cancel_stoploss_on_exchange
    co = self.exchange.cancel_stoploss_order_with_result(
  File "/freqtrade/freqtrade/exchange/exchange.py", line 1358, in cancel_stoploss_order_with_result
    corder = self.cancel_stoploss_order(order_id, pair)
  File "/freqtrade/freqtrade/exchange/exchange.py", line 1308, in cancel_stoploss_order
    return self.cancel_order(order_id, pair, params)
  File "/freqtrade/freqtrade/exchange/common.py", line 164, in wrapper
    return f(*args, **kwargs)
  File "/freqtrade/freqtrade/exchange/exchange.py", line 1297, in cancel_order
    raise InvalidOrderException(
freqtrade.exceptions.InvalidOrderException: Could not cancel order. Message: kucoin order_not_exist_or_not_allow_to_cancel
2023-03-24 12:40:48,175 - freqtrade.wallets - INFO - Wallets synced.
2023-03-24 12:40:48,188 - uvicorn.error - ERROR - Exception in ASGI application
Traceback (most recent call last):
  File "/home/ftuser/.local/lib/python3.10/site-packages/uvicorn/protocols/http/h11_impl.py", line 407, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
  File "/home/ftuser/.local/lib/python3.10/site-packages/uvicorn/middleware/proxy_headers.py", line 78, in __call__
    return await self.app(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/uvicorn/middleware/message_logger.py", line 86, in __call__
    raise exc from None
  File "/home/ftuser/.local/lib/python3.10/site-packages/uvicorn/middleware/message_logger.py", line 82, in __call__
    await self.app(scope, inner_receive, inner_send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/fastapi/applications.py", line 271, in __call__
    await super().__call__(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/applications.py", line 118, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/middleware/errors.py", line 184, in __call__
    raise exc
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/middleware/errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/middleware/cors.py", line 92, in __call__
    await self.simple_response(scope, receive, send, request_headers=headers)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/middleware/cors.py", line 147, in simple_response
    await self.app(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
    raise exc
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "/home/ftuser/.local/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
    raise e
  File "/home/ftuser/.local/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/routing.py", line 706, in __call__
    await route.handle(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/routing.py", line 276, in handle
    await self.app(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/routing.py", line 66, in app
    response = await func(request)
  File "/home/ftuser/.local/lib/python3.10/site-packages/fastapi/routing.py", line 237, in app
    raw_response = await run_endpoint_function(
  File "/home/ftuser/.local/lib/python3.10/site-packages/fastapi/routing.py", line 165, in run_endpoint_function
    return await run_in_threadpool(dependant.call, **values)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/concurrency.py", line 41, in run_in_threadpool
    return await anyio.to_thread.run_sync(func, *args)
  File "/home/ftuser/.local/lib/python3.10/site-packages/anyio/to_thread.py", line 31, in run_sync
    return await get_asynclib().run_sync_in_worker_thread(
  File "/home/ftuser/.local/lib/python3.10/site-packages/anyio/_backends/_asyncio.py", line 937, in run_sync_in_worker_thread
    return await future
  File "/home/ftuser/.local/lib/python3.10/site-packages/anyio/_backends/_asyncio.py", line 867, in run
    result = context.run(func, *args)
  File "/freqtrade/freqtrade/rpc/api_server/api_v1.py", line 174, in forceexit
    return rpc._rpc_force_exit(payload.tradeid, ordertype, amount=payload.amount)
  File "/freqtrade/freqtrade/rpc/rpc.py", line 744, in _rpc_force_exit
    self.__exec_force_exit(trade, ordertype, amount)
  File "/freqtrade/freqtrade/rpc/rpc.py", line 713, in __exec_force_exit
    self._freqtrade.execute_trade_exit(
  File "/freqtrade/freqtrade/freqtradebot.py", line 1578, in execute_trade_exit
    amount = self._safe_exit_amount(trade, trade.pair, sub_trade_amt or trade.amount)
  File "/freqtrade/freqtrade/freqtradebot.py", line 1522, in _safe_exit_amount
    raise DependencyException(
freqtrade.exceptions.DependencyException: Not enough amount to exit trade. Trade-amount: 729665.6745, Wallet: 708536.6743
```
using kucoin explains the re-placements.
their api reports precisions of around between 10e-10 and 10e-13 or so (depending on the pair) - but the UI only renders about 8 of these. So while it looks like all orders are for the same price - they're actually not - and your stoploss will have (slightly) moved.


I still don't understand why you'd get tons of partial fills on stoploss orders - I've never seen / had that before - and i've done quite some trades throughout the different exchanges.
I could understand that it may happen with some (bad) luck - but not twice in a day - that makes it seem that your stop/limit distance might be odd.

---

Please provide the output of the following command for the affected trade:
`freqtrade show-trades --db-url sqlite:///<trades.sqlite> --print-json --trade-ids <tradeid>` 
Please use a "details block" to keep the issue itself kindof readable (see below for details on how to do that). 

<details>
<summary>Expand to see how to do details blocks</summary>

```
<details>
<summary>Expand full </summary>
(wrap in tripple ticks `)
Trades output ...
</details>
```
</details>

The second partial fill happened because I intentionally increased stoploss_on_exchange_limit_ratio to catch the issue.

Also, I want to experiment with short stop/limit distance anyway. The idea is to use stoploss on exchange first, and then sell whatever is left using custom_exit.

I've already deleted the affected trades, will try to reproduce it again.
Here you go:
<details>
<summary>logs: custom exit failed</summary>

```
2023-03-25 00:33:07 - freqtrade.freqtradebot - INFO - Exit for PRE/USDT detected. Reason: custom_exit
2023-03-25 00:33:07 - freqtrade.freqtradebot - INFO - Canceling stoploss on exchange for Trade(id=332, pair=PRE/USDT, amount=524.24240000, is_short=False, leverage=1.0, open_rate=0.09698699, open_since=2023-03-25 00:12:16)
2023-03-25 00:33:07 - freqtrade.exchange.exchange - INFO - API cancel_order: {'code': '200000', 'data': {'cancelledOrderIds': ['vs9dsp0u7o65ea76000ph82k']}}
2023-03-25 00:33:08 - freqtrade.exchange.exchange - INFO - API fetch_order: {'info': {'id': 'vs9dsp0u7o65ea76000ph82k', 'symbol': 'PRE-USDT', 'opType': 'DEAL', 'type': 'limit', 'side': 'sell', 'price': '0.103784', 'size': '524.2424', 'funds': '0', 'dealFunds': '41.0282229888', 'dealSize': '395.3232', 'fee': '0.0410282229888', 'feeCurrency': 'USDT', 'stp': '', 'stop': 'loss', 'stopTriggered': True, 'stopPrice': '0.103887', 'timeInForce': 'GTC', 'postOnly': False, 'hidden': False, 'iceberg': False, 'visibleSize': '0', 'cancelAfter': -1, 'channel': 'API', 'clientOid': 'bc63744c-eeca-4d0b-969a-6096b48bbbc0', 'remark': None, 'tags': 'partner:ccxt', 'isActive': False, 'cancelExist': True, 'createdAt': 1679703588944, 'tradeType': 'TRADE'}, 'id': 'vs9dsp0u7o65ea76000ph82k', 'clientOrderId': 'bc63744c-eeca-4d0b-969a-6096b48bbbc0', 'symbol': 'PRE/USDT', 'type': 'limit', 'timeInForce': 'GTC', 'postOnly': False, 'side': 'sell', 'amount': 524.2424, 'price': 0.103784, 'stopPrice': 0.103887, 'triggerPrice': 0.103887, 'cost': 41.0282229888, 'filled': 395.3232, 'remaining': 128.9192, 'timestamp': 1679703588944, 'datetime': '2023-03-25T00:19:48.944Z', 'fee': {'currency': 'USDT', 'cost': 0.0410282229888}, 'status': 'canceled', 'lastTradeTimestamp': None, 'average': 0.103784, 'trades': [], 'fees': [{'currency': 'USDT', 'cost': 0.0410282229888}], 'reduceOnly': None}
2023-03-25 00:33:08 - freqtrade.wallets - INFO - Wallets synced.
2023-03-25 00:33:08 - freqtrade.freqtradebot - WARNING - Unable to exit trade PRE/USDT: Not enough amount to exit trade. Trade-amount: 524.2424, Wallet: 128.9192
```
</details>
<details>
<summary>logs: force exit failed</summary>

```
2023-03-25 00:39:10 - freqtrade.freqtradebot - INFO - Canceling stoploss on exchange for Trade(id=332, pair=PRE/USDT, amount=524.24240000, is_short=False, leverage=1.0, open_rate=0.09698699, open_since=2023-03-25 00:12:16)
2023-03-25 00:39:10 - freqtrade.freqtradebot - ERROR - Could not cancel stoploss order vs9dsp0u8a5mj6lh000l7dc7
Traceback (most recent call last):
  File "/freqtrade/freqtrade/exchange/exchange.py", line 1292, in cancel_order
    order = self._api.cancel_order(order_id, pair, params=params)
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/kucoin.py", line 1494, in cancel_order
    return getattr(self, method)(self.extend(request, params))
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/base/exchange.py", line 505, in inner
    return entry(_self, **inner_kwargs)
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/base/exchange.py", line 2833, in request
    return self.fetch2(path, api, method, params, headers, body, config, context)
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/base/exchange.py", line 2830, in fetch2
    return self.fetch(request['url'], request['method'], request['headers'], request['body'])
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/base/exchange.py", line 667, in fetch
    self.handle_errors(http_status_code, http_status_text, url, method, headers, http_response, json_response, request_headers, request_body)
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/kucoin.py", line 3356, in handle_errors
    self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
  File "/home/ftuser/.local/lib/python3.10/site-packages/ccxt/base/exchange.py", line 3133, in throw_exactly_matched_exception
    raise exact[string](message)
ccxt.base.errors.InvalidOrder: kucoin order_not_exist_or_not_allow_to_cancel

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/freqtrade/freqtrade/freqtradebot.py", line 847, in cancel_stoploss_on_exchange
    co = self.exchange.cancel_stoploss_order_with_result(
  File "/freqtrade/freqtrade/exchange/exchange.py", line 1358, in cancel_stoploss_order_with_result
    corder = self.cancel_stoploss_order(order_id, pair)
  File "/freqtrade/freqtrade/exchange/exchange.py", line 1308, in cancel_stoploss_order
    return self.cancel_order(order_id, pair, params)
  File "/freqtrade/freqtrade/exchange/common.py", line 164, in wrapper
    return f(*args, **kwargs)
  File "/freqtrade/freqtrade/exchange/exchange.py", line 1297, in cancel_order
    raise InvalidOrderException(
freqtrade.exceptions.InvalidOrderException: Could not cancel order. Message: kucoin order_not_exist_or_not_allow_to_cancel
2023-03-25 00:39:10 - freqtrade.wallets - INFO - Wallets synced.
2023-03-25 00:39:10 - uvicorn.error - ERROR - Exception in ASGI application

Traceback (most recent call last):
  File "/home/ftuser/.local/lib/python3.10/site-packages/uvicorn/protocols/http/h11_impl.py", line 407, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
  File "/home/ftuser/.local/lib/python3.10/site-packages/uvicorn/middleware/proxy_headers.py", line 78, in __call__
    return await self.app(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/uvicorn/middleware/message_logger.py", line 86, in __call__
    raise exc from None
  File "/home/ftuser/.local/lib/python3.10/site-packages/uvicorn/middleware/message_logger.py", line 82, in __call__
    await self.app(scope, inner_receive, inner_send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/fastapi/applications.py", line 271, in __call__
    await super().__call__(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/applications.py", line 118, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/middleware/errors.py", line 184, in __call__
    raise exc
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/middleware/errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/middleware/cors.py", line 92, in __call__
    await self.simple_response(scope, receive, send, request_headers=headers)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/middleware/cors.py", line 147, in simple_response
    await self.app(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
    raise exc
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "/home/ftuser/.local/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
    raise e
  File "/home/ftuser/.local/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/routing.py", line 706, in __call__
    await route.handle(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/routing.py", line 276, in handle
    await self.app(scope, receive, send)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/routing.py", line 66, in app
    response = await func(request)
  File "/home/ftuser/.local/lib/python3.10/site-packages/fastapi/routing.py", line 237, in app
    raw_response = await run_endpoint_function(
  File "/home/ftuser/.local/lib/python3.10/site-packages/fastapi/routing.py", line 165, in run_endpoint_function
    return await run_in_threadpool(dependant.call, **values)
  File "/home/ftuser/.local/lib/python3.10/site-packages/starlette/concurrency.py", line 41, in run_in_threadpool
    return await anyio.to_thread.run_sync(func, *args)
  File "/home/ftuser/.local/lib/python3.10/site-packages/anyio/to_thread.py", line 31, in run_sync
    return await get_asynclib().run_sync_in_worker_thread(
  File "/home/ftuser/.local/lib/python3.10/site-packages/anyio/_backends/_asyncio.py", line 937, in run_sync_in_worker_thread
    return await future
  File "/home/ftuser/.local/lib/python3.10/site-packages/anyio/_backends/_asyncio.py", line 867, in run
    result = context.run(func, *args)
  File "/freqtrade/freqtrade/rpc/api_server/api_v1.py", line 174, in forceexit
    return rpc._rpc_force_exit(payload.tradeid, ordertype, amount=payload.amount)
  File "/freqtrade/freqtrade/rpc/rpc.py", line 744, in _rpc_force_exit
    self.__exec_force_exit(trade, ordertype, amount)
  File "/freqtrade/freqtrade/rpc/rpc.py", line 713, in __exec_force_exit
    self._freqtrade.execute_trade_exit(
  File "/freqtrade/freqtrade/freqtradebot.py", line 1578, in execute_trade_exit
    amount = self._safe_exit_amount(trade, trade.pair, sub_trade_amt or trade.amount)
  File "/freqtrade/freqtrade/freqtradebot.py", line 1522, in _safe_exit_amount
    raise DependencyException(
freqtrade.exceptions.DependencyException: Not enough amount to exit trade. Trade-amount: 524.2424, Wallet: 128.9192

```
</details>
<details>
<summary>show-trades</summary>

```
2023-03-25 00:39:46,077 - freqtrade - INFO - freqtrade 2023.2
2023-03-25 00:39:46,078 - freqtrade.loggers - INFO - Verbosity set to 0
2023-03-25 00:39:46,078 - freqtrade.configuration.configuration - INFO - Parameter --db-url detected ...
2023-03-25 00:39:46,097 - freqtrade.configuration.configuration - INFO - Using user-data directory: /freqtrade/user_data ...
2023-03-25 00:39:46,098 - freqtrade.configuration.configuration - INFO - Using data directory: /freqtrade/user_data/data ...
2023-03-25 00:39:46,098 - freqtrade.configuration.configuration - INFO - Parameter --print-json detected ...
2023-03-25 00:39:46,098 - freqtrade.configuration.configuration - INFO - Filtering on trade_ids: ['332']
2023-03-25 00:39:46,099 - freqtrade.configuration.config_validation - INFO - Validating configuration ...
2023-03-25 00:39:46,106 - freqtrade.commands.list_commands - INFO - Using DB: "sqlite:////freqtrade/user_data/tradesv3.sqlite"
2023-03-25 00:39:46,179 - freqtrade.commands.list_commands - INFO - Printing 1 Trades:
[
    {
        "trade_id": 332,
        "pair": "PRE/USDT",
        "base_currency": "PRE",
        "quote_currency": "USDT",
        "is_open": true,
        "exchange": "kucoin",
        "amount": 524.2424,
        "amount_requested": 524.24248067,
        "stake_amount": 50.84469045,
        "max_stake_amount": 50.84469045,
        "strategy": "hhll",
        "enter_tag": null,
        "timeframe": 5,
        "fee_open": 0.001,
        "fee_open_cost": 0.0508446904487,
        "fee_open_currency": "USDT",
        "fee_close": 0.001,
        "fee_close_cost": null,
        "fee_close_currency": null,
        "open_date": "2023-03-25 00:12:16",
        "open_timestamp": 1679703136150,
        "open_rate": 0.09698698626570457,
        "open_rate_requested": 0.097073,
        "open_trade_value": 50.89553514,
        "close_date": null,
        "close_timestamp": null,
        "realized_profit": 0.0,
        "close_rate": null,
        "close_rate_requested": null,
        "close_profit": null,
        "close_profit_pct": null,
        "close_profit_abs": null,
        "trade_duration_s": null,
        "trade_duration": null,
        "profit_ratio": null,
        "profit_pct": null,
        "profit_abs": null,
        "exit_reason": null,
        "exit_order_status": null,
        "stop_loss_abs": 0.103887,
        "stop_loss_ratio": -0.01,
        "stop_loss_pct": -1.0,
        "stoploss_order_id": "vs9dsp0u8aulea76000ph8cd",
        "stoploss_last_update": "2023-03-25 00:39:25",
        "stoploss_last_update_timestamp": 1679704765270,
        "initial_stop_loss_abs": 0.00485,
        "initial_stop_loss_ratio": -0.95,
        "initial_stop_loss_pct": -95.0,
        "min_rate": 0.09698698626570457,
        "max_rate": 0.104936,
        "leverage": 1.0,
        "interest_rate": 0.0,
        "liquidation_price": null,
        "is_short": false,
        "trading_mode": "spot",
        "funding_fees": 0.0,
        "open_order_id": null,
        "orders": [
            {
                "amount": 524.2424,
                "safe_price": 0.09698698626570457,
                "ft_order_side": "buy",
                "order_filled_timestamp": 1679703198245,
                "ft_is_entry": true,
                "pair": "PRE/USDT",
                "order_id": "641e3c5fb2c265000152add6",
                "status": "closed",
                "average": 0.09698699,
                "cost": 50.8446904487,
                "filled": 524.2424,
                "is_open": false,
                "order_date": "2023-03-25 00:12:16",
                "order_timestamp": 1679703136011,
                "order_filled_date": "2023-03-25 00:13:18",
                "order_type": "limit",
                "price": 0.097073,
                "remaining": 0.0
            },
            {
                "amount": 524.2424,
                "safe_price": 0.103784,
                "ft_order_side": "stoploss",
                "order_filled_timestamp": 1679704388053,
                "ft_is_entry": false,
                "pair": "PRE/USDT",
                "order_id": "vs9dsp0u7o65ea76000ph82k",
                "status": "canceled",
                "average": 0.103784,
                "cost": 41.0282229888,
                "filled": 395.3232,
                "is_open": false,
                "order_date": "2023-03-25 00:19:48",
                "order_timestamp": 1679703588944,
                "order_filled_date": "2023-03-25 00:33:08",
                "order_type": "limit",
                "price": 0.103784,
                "remaining": 128.9192
            }
        ]
    }
]
```
</details>
Interesting - the order response does contain the partial filled amount - but i guess one base assumption was that stop orders fill in total - which is what I've seen so far (i NEVER had a stop fill partially on any exchange).

it's therefore very well possible that there's no code to actually handle this.


Resolving patch:
diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py
--- a/freqtrade/freqtradebot.py
+++ b/freqtrade/freqtradebot.py
@@ -853,7 +853,8 @@ def cancel_stoploss_on_exchange(self, trade: Trade) -> Trade:
                 logger.info(f"Canceling stoploss on exchange for {trade}")
                 co = self.exchange.cancel_stoploss_order_with_result(
                     trade.stoploss_order_id, trade.pair, trade.amount)
-                trade.update_order(co)
+                self.update_trade_state(trade, trade.stoploss_order_id, co, stoploss_order=True)
+
                 # Reset stoploss order id.
                 trade.stoploss_order_id = None
             except InvalidOrderException:
@@ -1171,7 +1172,8 @@ def handle_stoploss_on_exchange(self, trade: Trade) -> bool:
             logger.warning('Unable to fetch stoploss order: %s', exception)
 
         if stoploss_order:
-            trade.update_order(stoploss_order)
+            self.update_trade_state(trade, trade.stoploss_order_id, stoploss_order,
+                                    stoploss_order=True)
 
         # We check if stoploss order is fulfilled
         if stoploss_order and stoploss_order['status'] in ('closed', 'triggered'):
diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py
--- a/freqtrade/persistence/trade_model.py
+++ b/freqtrade/persistence/trade_model.py
@@ -692,21 +692,24 @@ def update_trade(self, order: Order) -> None:
             else:
                 logger.warning(
                     f'Got different open_order_id {self.open_order_id} != {order.order_id}')
-            amount_tr = amount_to_contract_precision(self.amount, self.amount_precision,
-                                                     self.precision_mode, self.contract_size)
-            if isclose(order.safe_amount_after_fee, amount_tr, abs_tol=MATH_CLOSE_PREC):
-                self.close(order.safe_price)
-            else:
-                self.recalc_trade_from_orders()
-        elif order.ft_order_side == 'stoploss' and order.status not in ('canceled', 'open'):
+
+        elif order.ft_order_side == 'stoploss' and order.status not in ('open', ):
             self.stoploss_order_id = None
             self.close_rate_requested = self.stop_loss
             self.exit_reason = ExitType.STOPLOSS_ON_EXCHANGE.value
             if self.is_open:
                 logger.info(f'{order.order_type.upper()} is hit for {self}.')
-            self.close(order.safe_price)
         else:
             raise ValueError(f'Unknown order type: {order.order_type}')
+
+        if order.ft_order_side != self.entry_side:
+            amount_tr = amount_to_contract_precision(self.amount, self.amount_precision,
+                                                     self.precision_mode, self.contract_size)
+            if isclose(order.safe_amount_after_fee, amount_tr, abs_tol=MATH_CLOSE_PREC):
+                self.close(order.safe_price)
+            else:
+                self.recalc_trade_from_orders()
+
         Trade.commit()
 
     def close(self, rate: float, *, show_msg: bool = True) -> None:


Test patch:
diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py
--- a/tests/test_freqtradebot.py
+++ b/tests/test_freqtradebot.py
@@ -1290,6 +1290,137 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_
     assert trade.exit_reason == str(ExitType.EMERGENCY_EXIT)
 
 
+@pytest.mark.parametrize("is_short", [False, True])
+def test_handle_stoploss_on_exchange_partial(
+        mocker, default_conf_usdt, fee, is_short, limit_order) -> None:
+    stop_order_dict = {'id': "101", "status": "open"}
+    stoploss = MagicMock(return_value=stop_order_dict)
+    enter_order = limit_order[entry_side(is_short)]
+    exit_order = limit_order[exit_side(is_short)]
+    patch_RPCManager(mocker)
+    patch_exchange(mocker)
+    mocker.patch.multiple(
+        EXMS,
+        fetch_ticker=MagicMock(return_value={
+            'bid': 1.9,
+            'ask': 2.2,
+            'last': 1.9
+        }),
+        create_order=MagicMock(side_effect=[
+            enter_order,
+            exit_order,
+        ]),
+        get_fee=fee,
+        create_stoploss=stoploss
+    )
+    freqtrade = FreqtradeBot(default_conf_usdt)
+    patch_get_signal(freqtrade, enter_short=is_short, enter_long=not is_short)
+
+    freqtrade.enter_positions()
+    trade = Trade.session.scalars(select(Trade)).first()
+    trade.is_short = is_short
+    trade.is_open = True
+    trade.open_order_id = None
+    trade.stoploss_order_id = None
+
+    assert freqtrade.handle_stoploss_on_exchange(trade) is False
+    assert stoploss.call_count == 1
+    assert trade.stoploss_order_id == "101"
+    assert trade.amount == 30
+    stop_order_dict.update({'id': "102"})
+    # Stoploss on exchange is cancelled on exchange, but filled partially.
+    # Must update trade amount to guarantee successful exit.
+    stoploss_order_hit = MagicMock(return_value={
+        'id': "101",
+        'status': 'canceled',
+        'type': 'stop_loss_limit',
+        'price': 3,
+        'average': 2,
+        'filled': trade.amount / 2,
+        'remaining': trade.amount / 2,
+        'amount': enter_order['amount'],
+    })
+    mocker.patch(f'{EXMS}.fetch_stoploss_order', stoploss_order_hit)
+    assert freqtrade.handle_stoploss_on_exchange(trade) is False
+    # Stoploss filled partially ...
+    assert trade.amount == 15
+
+    assert trade.stoploss_order_id == "102"
+
+
+@pytest.mark.parametrize("is_short", [False, True])
+def test_handle_stoploss_on_exchange_partial_cancel_here(
+        mocker, default_conf_usdt, fee, is_short, limit_order, caplog) -> None:
+    stop_order_dict = {'id': "101", "status": "open"}
+    default_conf_usdt['trailing_stop'] = True
+    stoploss = MagicMock(return_value=stop_order_dict)
+    enter_order = limit_order[entry_side(is_short)]
+    exit_order = limit_order[exit_side(is_short)]
+    patch_RPCManager(mocker)
+    patch_exchange(mocker)
+    mocker.patch.multiple(
+        EXMS,
+        fetch_ticker=MagicMock(return_value={
+            'bid': 1.9,
+            'ask': 2.2,
+            'last': 1.9
+        }),
+        create_order=MagicMock(side_effect=[
+            enter_order,
+            exit_order,
+        ]),
+        get_fee=fee,
+        create_stoploss=stoploss
+    )
+    freqtrade = FreqtradeBot(default_conf_usdt)
+    patch_get_signal(freqtrade, enter_short=is_short, enter_long=not is_short)
+
+    freqtrade.enter_positions()
+    trade = Trade.session.scalars(select(Trade)).first()
+    trade.is_short = is_short
+    trade.is_open = True
+    trade.open_order_id = None
+    trade.stoploss_order_id = None
+
+    assert freqtrade.handle_stoploss_on_exchange(trade) is False
+    assert stoploss.call_count == 1
+    assert trade.stoploss_order_id == "101"
+    assert trade.amount == 30
+    stop_order_dict.update({'id': "102"})
+    # Stoploss on exchange is open.
+    # Freqtrade cancels the stop - but cancel returns a partial filled order.
+    stoploss_order_hit = MagicMock(return_value={
+        'id': "101",
+        'status': 'open',
+        'type': 'stop_loss_limit',
+        'price': 3,
+        'average': 2,
+        'filled': 0,
+        'remaining': trade.amount,
+        'amount': enter_order['amount'],
+    })
+    stoploss_order_cancel = MagicMock(return_value={
+        'id': "101",
+        'status': 'canceled',
+        'type': 'stop_loss_limit',
+        'price': 3,
+        'average': 2,
+        'filled': trade.amount / 2,
+        'remaining': trade.amount / 2,
+        'amount': enter_order['amount'],
+    })
+    mocker.patch(f'{EXMS}.fetch_stoploss_order', stoploss_order_hit)
+    mocker.patch(f'{EXMS}.cancel_stoploss_order_with_result', stoploss_order_cancel)
+    trade.stoploss_last_update = arrow.utcnow().shift(minutes=-10).datetime
+
+    assert freqtrade.handle_stoploss_on_exchange(trade) is False
+    # Canceled Stoploss filled partially ...
+    assert log_has_re('Cancelling current stoploss on exchange.*', caplog)
+
+    assert trade.stoploss_order_id == "102"
+    assert trade.amount == 15
+
+
 @pytest.mark.parametrize("is_short", [False, True])
 def test_handle_sle_cancel_cant_recreate(mocker, default_conf_usdt, fee, caplog, is_short,
                                          limit_order) -> None: