Repository: freqtrade/freqtrade

Issue:
price filter logic and calculation
## Step 1: Have you search for this issue before posting it?

If you have discovered a bug in the bot, please [search our issue tracker](https://github.com/freqtrade/freqtrade/issues?q=is%3Aissue). 
If it hasn't been reported, please create a new issue.

## Step 2: Describe your environment

Operating system: Ubuntu 18.04 LTS
Python Version: 3.7.3
CCXT version: ccxt==1.26.12
Branch: Develop
Last Commit ID: c8ccdbcb9a63aefe0a2ea1e1cbd4a7c075b4d5c6

 
 
## Step 3: Describe the problem:

price filter calculation seems not to be accurate

### Steps to reproduce:

Example: 

1) FT log
`2020-04-14 18:06:52,458 - PriceFilter - INFO - Removed BSVBEAR/USDT from whitelist, because 1 unit is 112.200%`

2) prices on FTX are quoted on this precision for BSVBEAR/USDT: 0,89950 

3) CCXT information
for BSVBEAR/USDT at FTX:
`'precision': {'amount': 0.1, 'price': 0.00025}`

4) how is 112% is being calculated?

  
### Observed Results:

if price of 0,89950 be increased by 1 unit (pip), which is 0.00025 = 0.89975  ->> 112%?

### Relevant code exceptions or logs:

  ```
  // paste your log here
  ```



Discussion:

Resolving patch:
diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py
--- a/freqtrade/exchange/exchange.py
+++ b/freqtrade/exchange/exchange.py
@@ -452,6 +452,17 @@ def price_to_precision(self, pair: str, price: float) -> float:
                 price = ceil(big_price) / pow(10, symbol_prec)
         return price
 
+    def price_get_one_pip(self, pair: str, price: float) -> float:
+        """
+        Get's the "1 pip" value for this pair.
+        Used in PriceFilter to calculate the 1pip movements.
+        """
+        precision = self.markets[pair]['precision']['price']
+        if self.precisionMode == TICK_SIZE:
+            return precision
+        else:
+            return 1 / pow(10, precision)
+
     def dry_run_order(self, pair: str, ordertype: str, side: str, amount: float,
                       rate: float, params: Dict = {}) -> Dict[str, Any]:
         order_id = f'dry_run_{side}_{randint(0, 10**6)}'
diff --git a/freqtrade/pairlist/PriceFilter.py b/freqtrade/pairlist/PriceFilter.py
--- a/freqtrade/pairlist/PriceFilter.py
+++ b/freqtrade/pairlist/PriceFilter.py
@@ -35,12 +35,10 @@ def _validate_ticker_lowprice(self, ticker) -> bool:
         """
         Check if if one price-step (pip) is > than a certain barrier.
         :param ticker: ticker dict as returned from ccxt.load_markets()
-        :param precision: Precision
         :return: True if the pair can stay, false if it should be removed
         """
-        precision = self._exchange.markets[ticker['symbol']]['precision']['price']
-
-        compare = ticker['last'] + 1 / pow(10, precision)
+        compare = ticker['last'] + self._exchange.price_get_one_pip(ticker['symbol'],
+                                                                    ticker['last'])
         changeperc = (compare - ticker['last']) / ticker['last']
         if changeperc > self._low_price_ratio:
             logger.info(f"Removed {ticker['symbol']} from whitelist, "


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
@@ -253,6 +253,32 @@ def test_price_to_precision(default_conf, mocker, price, precision_mode, precisi
     assert pytest.approx(exchange.price_to_precision(pair, price)) == expected
 
 
+@pytest.mark.parametrize("price,precision_mode,precision,expected", [
+    (2.34559, 2, 4, 0.0001),
+    (2.34559, 2, 5, 0.00001),
+    (2.34559, 2, 3, 0.001),
+    (2.9999, 2, 3, 0.001),
+    (200.0511, 2, 3, 0.001),
+    # Tests for Tick_size
+    (2.34559, 4, 0.0001, 0.0001),
+    (2.34559, 4, 0.00001, 0.00001),
+    (2.34559, 4, 0.0025, 0.0025),
+    (2.9909, 4, 0.0025, 0.0025),
+    (234.43, 4, 0.5, 0.5),
+    (234.43, 4, 0.0025, 0.0025),
+    (234.43, 4, 0.00013, 0.00013),
+
+])
+def test_price_get_one_pip(default_conf, mocker, price, precision_mode, precision, expected):
+    markets = PropertyMock(return_value={'ETH/BTC': {'precision': {'price': precision}}})
+    exchange = get_patched_exchange(mocker, default_conf, id="binance")
+    mocker.patch('freqtrade.exchange.Exchange.markets', markets)
+    mocker.patch('freqtrade.exchange.Exchange.precisionMode',
+                 PropertyMock(return_value=precision_mode))
+    pair = 'ETH/BTC'
+    assert pytest.approx(exchange.price_get_one_pip(pair, price)) == expected
+
+
 def test_set_sandbox(default_conf, mocker):
     """
     Test working scenario