Repository: freqtrade/freqtrade

Issue:
WARNING - Can't open a new trade for KSM/EUR: stake amount is too small (41.69480436 < 66.464)
Operating system: latest linux mint 64bit
Python Version: latest stable 2021.03.19.
Freqtrade Version: latest stable 2021.03.19.
  
Hi!

I want to disable stoploss and i set it to -200 as a read through previos issues like this, but for two days now i've been getting this error again and again, so the bot basically is not doing anything according to my strategy. I don't understand why this error is still present with stoploss disabled. (The strategy is very quick and does not need any stoploss, it could lose more money with stoploss enabled) 
Thanks in advance for any help!

Here is my config:
Account balance is currently 84 EUR!
The exchange is kraken and rate limit is correctly set to 3100.
Edge is disabled.
{
    "max_open_trades": 2,
    "stake_currency": "EUR",
    "stake_amount": "unlimited",
    "tradable_balance_ratio": 0.99,
    "amend_last_stake_amount": true,
    "fiat_display_currency": "EUR",
    "timeframe": "5m",
    "dry_run": false,
    "dry_run_wallet": 1000,
    "cancel_open_orders_on_exit": false,
    "unfilledtimeout": {
        "buy": 10,
        "sell": 30
    },


Here is the terminal error:
2021-03-19 14:45:32,651 - freqtrade.wallets - INFO - Wallets synced.
2021-03-19 14:45:32,659 - freqtrade.freqtradebot - INFO - Buy signal found: about create a new trade with stake_amount: 41.69480436 ...
2021-03-19 14:45:32,660 - freqtrade.freqtradebot - INFO - Executing Buy for KSM/EUR
2021-03-19 14:45:32,660 - freqtrade.freqtradebot - INFO - Using Last Bid / Last Price
2021-03-19 14:45:35,659 - freqtrade.freqtradebot - WARNING - Can't open a new trade for KSM/EUR: stake amount is too small (41.69480436 < 66.464)
2021-03-19 14:45:35,848 - freqtrade.worker - INFO - Bot heartbeat. PID=24443, version='develop-766c786d', state='RUNNING'

This messeage was the same for many other coins too, like XRP, BTC, UNI etc...


Discussion:
84 (account balance) / max_open_trades (2) < 66 which is the value the bot has calculated for the trade. (LIMIT buy). You either reduce max_open_trades or add more balance to your account.
it's the 2nd time i've seen this with kraken ... i don't think the 66 is justified.

according to the [kraken page](https://support.kraken.com/hc/en-us/articles/205893708-Minimum-order-size-volume-for-trading), the limit should be 0.1 KSM, or 5 EUR.
Now with the current price of KSM (around 326.54) - the minimum tradable limit for manual trades will be around 33€ (0.1 * 326.54).

---

freqtrade will not allow you to buy 0.1 KSM (or 5EUR) unless you use a very tight stoploss, but it'll require some room between the "minimum tradable" and the real value, to allow to place a stoploss below entry should the trade go south (even if you don't use stoploss but rely on sell-signals, you'll still need this room - as every trade has a certain risk of going south, and you'll not want to be stuck in a trade with "can't sell because you're below limit").

the Stoploss of -2 will be "kindof" ignored (this offset is capped at 0.5) - so the correct value should be around 33 + (33 * 0.5) - which will be 49€ (and is therewith still below your available limit).
So am I stuck with the only option to fund my kraken account with more stake money than 84 EUR? Do you have any other ideas? 
What do you guys recommend? 
By the way, thanks for the quick reply and help, this program is awesome though. 
the real limits depend on the pairs you trade.
so while for KSM, the limit kraken is 33E at the moment (+ 50% with a big stoploss), this is caused by the relatively high price.

I'd expect kraken to adjust the limit sometime in the future to the high price - but noone can tell when / if this will happen.

While there is a bug in the calculation causing the 65€ result - the new result (fixing atm) for KSM will be 49€.

Other pairs (e.g. ADA/EUR) would have this (new) limit at 39€ - so by simply picking other pairs you should be good for now (although one lost trade will drop you below the limit again).

You can limit the bot to 1 pair - so it'll have enough money left - but that may or may not play along with your strategy.


Personally, i find kraken's limits at the moment pretty inflated - especially considering that binance limits will be between 15$ and 17$ (including the 50% drop margin) already.

Resolving patch:
diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py
--- a/freqtrade/exchange/exchange.py
+++ b/freqtrade/exchange/exchange.py
@@ -531,16 +531,16 @@ def get_min_pair_stake_amount(self, pair: str, price: float,
             return None
 
         # reserve some percent defined in config (5% default) + stoploss
-        amount_reserve_percent = 1.0 - self._config.get('amount_reserve_percent',
+        amount_reserve_percent = 1.0 + self._config.get('amount_reserve_percent',
                                                         DEFAULT_AMOUNT_RESERVE_PERCENT)
-        amount_reserve_percent += stoploss
+        amount_reserve_percent += abs(stoploss)
         # it should not be more than 50%
-        amount_reserve_percent = max(amount_reserve_percent, 0.5)
+        amount_reserve_percent = max(min(amount_reserve_percent, 1.5), 1)
 
         # The value returned should satisfy both limits: for amount (base currency) and
         # for cost (quote, stake currency), so max() is used here.
         # See also #2575 at github.
-        return max(min_stake_amounts) / amount_reserve_percent
+        return max(min_stake_amounts) * amount_reserve_percent
 
     def dry_run_order(self, pair: str, ordertype: str, side: str, amount: float,
                       rate: float, params: Dict = {}) -> Dict[str, Any]:


Test patch:
diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py
--- a/tests/exchange/test_exchange.py
+++ b/tests/exchange/test_exchange.py
@@ -1,6 +1,7 @@
 import copy
 import logging
 from datetime import datetime, timedelta, timezone
+from math import isclose
 from random import randint
 from unittest.mock import MagicMock, Mock, PropertyMock, patch
 
@@ -370,7 +371,7 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None:
         PropertyMock(return_value=markets)
     )
     result = exchange.get_min_pair_stake_amount('ETH/BTC', 1, stoploss)
-    assert result == 2 / 0.9
+    assert isclose(result, 2 * 1.1)
 
     # min amount is set
     markets["ETH/BTC"]["limits"] = {
@@ -382,7 +383,7 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None:
         PropertyMock(return_value=markets)
     )
     result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss)
-    assert result == 2 * 2 / 0.9
+    assert isclose(result, 2 * 2 * 1.1)
 
     # min amount and cost are set (cost is minimal)
     markets["ETH/BTC"]["limits"] = {
@@ -394,7 +395,7 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None:
         PropertyMock(return_value=markets)
     )
     result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss)
-    assert result == max(2, 2 * 2) / 0.9
+    assert isclose(result, max(2, 2 * 2) * 1.1)
 
     # min amount and cost are set (amount is minial)
     markets["ETH/BTC"]["limits"] = {
@@ -406,7 +407,14 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None:
         PropertyMock(return_value=markets)
     )
     result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss)
-    assert result == max(8, 2 * 2) / 0.9
+    assert isclose(result, max(8, 2 * 2) * 1.1)
+
+    result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, -0.4)
+    assert isclose(result, max(8, 2 * 2) * 1.45)
+
+    # Really big stoploss
+    result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, -1)
+    assert isclose(result, max(8, 2 * 2) * 1.5)
 
 
 def test_get_min_pair_stake_amount_real_data(mocker, default_conf) -> None:
@@ -424,7 +432,7 @@ def test_get_min_pair_stake_amount_real_data(mocker, default_conf) -> None:
         PropertyMock(return_value=markets)
     )
     result = exchange.get_min_pair_stake_amount('ETH/BTC', 0.020405, stoploss)
-    assert round(result, 8) == round(max(0.0001, 0.001 * 0.020405) / 0.9, 8)
+    assert round(result, 8) == round(max(0.0001, 0.001 * 0.020405) * 1.1, 8)
 
 
 def test_set_sandbox(default_conf, mocker):