Repository: freqtrade/freqtrade
Pull request: Validate stake-currency against pairlist
## Summary
We should verify that only correct pairs are in the whitelist.
Otherwise backtesting may have irritating results (#2622) - and it'll result in the static-pairlist outputting "removing pair from whtitelist" once per iteration for all incompatible pairs.

Closes #2622

## Quick changelog

- Check that pairlist only contains pairs with correct stake-currency


Problem statement:
Issue about stake_currency during Backtesting/Hyperopt
When I do a backtest (or Hyperopting) with USDT as the stake currency and XXX/USDT as pair-Iist (& EUR as fiat currency), I have a total profit in "USDT" of 1.5 USDT and a total profit growth of 1254%, but that doesn't seem normal to have 1.2 USDT for a growth of 1202% (stake amount = 0.002) and then when I switch the stake currency to BTC it doesn't change the result at all, it doesn't appear as an error to use BTC as stake currency when the entire pair list is in XXX/USDT, so I guess when the bot backtest or hyperopt it automatically calculates by default the result in BTC not USDT.
Maybe I misinterpreted something but it would be better for data analysis to have results calculated in the assigned stake currency. 

I will display below the two backtests I performed to show you that I changed only the stake currency but that the result are the same.

```
========================================================= BACKTESTING REPORT ========================================================
| pair       |   buy count |   avg profit % |   cum profit % |   tot profit USDT |   tot profit % | avg duration    |   profit |   loss |
|:-----------|------------:|---------------:|---------------:|------------------:|---------------:|:----------------|---------:|-------:|
| ADA/USDT   |        4785 |           0.78 |        3720.55 |        0.07448529 |          74.41 | 0:56:00         |     4263 |    522 |
| ALGO/USDT  |        1551 |           1.21 |        1875.68 |        0.03755117 |          37.51 | 0:27:00         |     1375 |    176 |
| BNB/USDT   |        6120 |           1.02 |        6263.58 |        0.12539648 |         125.27 | 0:55:00         |     5495 |    625 |
| BTC/USDT   |        5077 |           0.69 |        3505.82 |        0.07018654 |          70.12 | 1:44:00         |     4618 |    459 |
| EOS/USDT   |        4176 |           0.76 |        3173.61 |        0.06353585 |          63.47 | 1:07:00         |     3735 |    441 |
| ETC/USDT   |        3621 |           0.70 |        2529.19 |        0.05063424 |          50.58 | 1:30:00         |     3240 |    381 |
| ETH/USDT   |        6089 |           0.78 |        4741.06 |        0.09491616 |          94.82 | 1:07:00         |     5486 |    603 |
| FET/USDT   |        2626 |           1.22 |        3200.65 |        0.06407706 |          64.01 | 0:29:00         |     2351 |    275 |
| LINK/USDT  |        2849 |           1.21 |        3456.53 |        0.06919992 |          69.13 | 0:39:00         |     2556 |    293 |
| MATIC/USDT |        2079 |           1.71 |        3558.81 |        0.07124735 |          71.18 | 0:29:00         |     1851 |    228 |
| LTC/USDT   |        5724 |           0.89 |        5075.19 |        0.10160560 |         101.50 | 0:58:00         |     5153 |    571 |
| ONT/USDT   |        4620 |           1.04 |        4811.29 |        0.09632222 |          96.23 | 0:47:00         |     4119 |    501 |
| USDC/USDT  |         100 |          13.00 |        1299.88 |        0.02602355 |          26.00 | 3 days, 9:35:00 |       94 |      6 |
| TRX/USDT   |        4282 |           0.86 |        3665.99 |        0.07339311 |          73.32 | 0:59:00         |     3848 |    434 |
| VET/USDT   |        4069 |           0.96 |        3911.15 |        0.07830090 |          78.22 | 0:53:00         |     3655 |    414 |
| XLM/USDT   |        3948 |           0.73 |        2896.41 |        0.05798620 |          57.93 | 1:18:00         |     3495 |    453 |
| XRP/USDT   |        3608 |           0.68 |        2462.77 |        0.04930478 |          49.26 | 1:46:00         |     3199 |    409 |
| TOTAL      |       65324 |           0.92 |       60148.18 |        1.20416642 |        1202.96 | 1:11:00         |    58533 |   6791 |
========================================================= SELL REASON STATS =========================================================
```
Exact same backtest but with BTC instead of USDT (nothing changed):

```
=========================================================BACKTESTING REPORT ========================================================
| pair       |   buy count |   avg profit % |   cum profit % |   tot profit BTC |   tot profit % | avg duration    |   profit |   loss |
|:-----------|------------:|---------------:|---------------:|-----------------:|---------------:|:----------------|---------:|-------:|
| ADA/USDT   |        4785 |           0.78 |        3720.55 |       0.07448529 |          74.41 | 0:56:00         |     4263 |    522 |
| ALGO/USDT  |        1551 |           1.21 |        1875.68 |       0.03755117 |          37.51 | 0:27:00         |     1375 |    176 |
| BNB/USDT   |        6120 |           1.02 |        6263.58 |       0.12539648 |         125.27 | 0:55:00         |     5495 |    625 |
| BTC/USDT   |        5077 |           0.69 |        3505.82 |       0.07018654 |          70.12 | 1:44:00         |     4618 |    459 |
| EOS/USDT   |        4176 |           0.76 |        3173.61 |       0.06353585 |          63.47 | 1:07:00         |     3735 |    441 |
| ETC/USDT   |        3621 |           0.70 |        2529.19 |       0.05063424 |          50.58 | 1:30:00         |     3240 |    381 |
| ETH/USDT   |        6089 |           0.78 |        4741.06 |       0.09491616 |          94.82 | 1:07:00         |     5486 |    603 |
| FET/USDT   |        2626 |           1.22 |        3200.65 |       0.06407706 |          64.01 | 0:29:00         |     2351 |    275 |
| LINK/USDT  |        2849 |           1.21 |        3456.53 |       0.06919992 |          69.13 | 0:39:00         |     2556 |    293 |
| MATIC/USDT |        2079 |           1.71 |        3558.81 |       0.07124735 |          71.18 | 0:29:00         |     1851 |    228 |
| LTC/USDT   |        5724 |           0.89 |        5075.19 |       0.10160560 |         101.50 | 0:58:00         |     5153 |    571 |
| ONT/USDT   |        4620 |           1.04 |        4811.29 |       0.09632222 |          96.23 | 0:47:00         |     4119 |    501 |
| USDC/USDT  |         100 |          13.00 |        1299.88 |       0.02602355 |          26.00 | 3 days, 9:35:00 |       94 |      6 |
| TRX/USDT   |        4282 |           0.86 |        3665.99 |       0.07339311 |          73.32 | 0:59:00         |     3848 |    434 |
| VET/USDT   |        4069 |           0.96 |        3911.15 |       0.07830090 |          78.22 | 0:53:00         |     3655 |    414 |
| XLM/USDT   |        3948 |           0.73 |        2896.41 |       0.05798620 |          57.93 | 1:18:00         |     3495 |    453 |
| XRP/USDT   |        3608 |           0.68 |        2462.77 |       0.04930478 |          49.26 | 1:46:00         |     3199 |    409 |
| TOTAL      |       65324 |           0.92 |       60148.18 |       1.20416642 |        1202.96 | 1:11:00         |    58533 |   6791 |
========================================================= SELL REASON STATS =========================================================
```

Hints from issue discussion:
Please:

Fill the fields:
  * Operating system: ____
  * Python Version: _____ (`python -V`)
  * CCXT version: _____ (`pip freeze | grep ccxt`)
  * Branch: Master | Develop
  * Last Commit ID: _____ (`git log --format="%H" -n 1`)

Attach the output of both commands (with their complete log) along with commands you are running.

`stake_amount` is not really relevant for backtesting other than displaying it in the column.
What counts is the pairlist - since you use USDT pairs, the result will be in USDT.

The 2nd case should simply fail with "invalid configuration" (you use BTC stake, but use USDT pairs - which is invalid) - but apparently it doesn't for backtesting / hyperopt (it will fail for trading operations though!).

Apart from that... 
I don't think your configuration makes much sense, anyway - when switching stake to  USDT, you will not use a stake-amount of 0.002 - that's a common BTC stake, but you will probably not be able to make any trades due to minimum tradeable amounts. (see [here for binance minimum trade amounts](https://www.binance.com/en/trade-rule)) -  10 USDT is the minimum for all pairs, so a configuration of 0.002 will result in all trades being rejected.

So when changing the configuration, make sure to change it to something that makes sense when seen together:
You switch from BTC to USDT - you have to also adjust `stake_amount` to something you are able to trade with USDT (which not something < 10 USDT).
Also, you'll need to adjust the pairlist to match the stake-currency.



@hroff-1902  : 

Operating system: Windows 10
Python Version: 
```
(base) C:\Users\john\freqtrade>python -V
Python 3.7.3
```
CCXT version:
```
(base) C:\Users\john\freqtrade>pip freeze
WARNING: Could not generate requirement for distribution -ip 19.2.3 (c:\programdata\anaconda3\lib\site-packages): Parse error at "'-ip==19.'": Expected W:(abcd...)
WARNING: Could not generate requirement for distribution -cxt 1.18.1149 (c:\programdata\anaconda3\lib\site-packages): Parse error at "'-cxt==1.'": Expected W:(abcd...)
aiodns==1.1.1
aiohttp==3.6.2
alabaster==0.7.12
anaconda-client==1.7.2
anaconda-navigator==1.9.7
anaconda-project==0.8.2
arrow==0.15.4
asn1crypto==0.24.0
astroid==2.2.5
astropy==3.1.2
async-timeout==3.0.1
atomicwrites==1.3.0
attrs==19.1.0
Babel==2.6.0
backcall==0.1.0
backports.os==0.1.1
backports.shutil-get-terminal-size==1.0.0
beautifulsoup4==4.7.1
bitarray==0.8.3
bkcharts==0.2
bleach==3.1.0
bokeh==1.0.4
boto==2.49.0
Bottleneck==1.2.1
cachetools==3.1.1
ccxt==1.19.25
certifi==2019.3.9
cffi==1.12.2
chardet==3.0.4
Click==7.0
cloudpickle==0.8.0
clyent==1.2.2
coinmarketcap==5.0.3
colorama==0.4.1
comtypes==1.1.7
conda==4.6.11
conda-build==3.17.7
conda-verify==3.1.1
contextlib2==0.5.5
cryptography==2.6.1
cycler==0.10.0
Cython==0.29.6
cytoolz==0.9.0.1
dask==1.1.4
decorator==4.4.0
defusedxml==0.5.0
distributed==1.26.0
docutils==0.14
entrypoints==0.3
et-xmlfile==1.0.1
fastcache==1.0.2
filelock==3.0.12
Flask==1.1.1
-e git+https://github.com/freqtrade/freqtrade.git@8dd9b5c6fba973b98defc0f9a9e2e3c01af735dd#egg=freqtrade
future==0.17.1
gevent==1.4.0
glob2==0.6
greenlet==0.4.15
h5py==2.9.0
heapdict==1.0.0
html5lib==1.0.1
idna==2.8
imageio==2.5.0
imagesize==1.1.0
importlib-metadata==0.0.0
ipykernel==5.1.0
ipython==7.4.0
ipython-genutils==0.2.0
ipywidgets==7.4.2
isort==4.3.16
itsdangerous==1.1.0
jdcal==1.4
jedi==0.13.3
Jinja2==2.10.1
joblib==0.13.2
jsonschema==3.1.1
jupyter==1.0.0
jupyter-client==5.2.4
jupyter-console==6.0.0
jupyter-core==4.4.0
jupyterlab==0.35.4
jupyterlab-server==0.2.0
keyring==18.0.0
kiwisolver==1.0.1
lazy-object-proxy==1.3.1
libarchive-c==2.8
llvmlite==0.28.0
locket==0.2.0
lxml==4.3.2
MarkupSafe==1.1.1
matplotlib==3.0.3
mccabe==0.6.1
menuinst==1.4.16
mistune==0.8.4
mkl-fft==1.0.10
mkl-random==1.0.2
mock==3.0.5
more-itertools==6.0.0
mpmath==1.1.0
msgpack==0.6.1
multidict==4.5.2
multipledispatch==0.6.0
navigator-updater==0.2.1
nbconvert==5.4.1
nbformat==4.4.0
networkx==2.2
nltk==3.4
nose==1.3.7
notebook==5.7.8
numba==0.43.1
numexpr==2.6.9
numpy==1.17.4
numpydoc==0.8.0
olefile==0.46
openpyxl==2.6.1
packaging==19.0
pandas==0.25.3
pandocfilters==1.4.2
parso==0.3.4
partd==0.3.10
path.py==11.5.0
pathlib2==2.3.3
patsy==0.5.1
pep8==1.7.1
pickleshare==0.7.5
Pillow==5.4.1
pipenv==2018.11.26
pkginfo==1.5.0.1
plotly==4.1.1
pluggy==0.9.0
ply==3.11
prometheus-client==0.6.0
prompt-toolkit==2.0.9
psutil==5.6.1
py==1.8.0
py-find-1st==1.1.4
pycares==3.0.0
pycodestyle==2.5.0
pycosat==0.6.3
pycparser==2.19
pycrypto==2.6.1
pycurl==7.43.0.2
pyflakes==2.1.1
Pygments==2.3.1
pylint==2.3.1
pyodbc==4.0.26
pyOpenSSL==19.0.0
pyparsing==2.3.1
pyreadline==2.1
pyrsistent==0.14.11
PySocks==1.6.8
pytest==4.3.1
pytest-arraydiff==0.3
pytest-astropy==0.5.0
pytest-doctestplus==0.3.0
pytest-openfiles==0.3.2
pytest-remotedata==0.3.1
python-dateutil==2.8.0
python-rapidjson==0.8.0
python-telegram-bot==12.2.0
pytz==2018.9
PyWavelets==1.0.2
pywin32==223
pywinpty==0.5.5
PyYAML==5.1
pyzmq==18.0.0
QtAwesome==0.5.7
qtconsole==4.4.3
QtPy==1.7.0
requests==2.22.0
requests-cache==0.5.0
retrying==1.3.3
rope==0.12.0
ruamel-yaml==0.15.46
scikit-image==0.14.2
scikit-learn==0.21.3
scikit-optimize==0.5.2
scipy==1.3.1
sdnotify==0.3.2
seaborn==0.9.0
Send2Trash==1.5.0
simplegeneric==0.8.1
singledispatch==3.4.0.3
six==1.12.0
snowballstemmer==1.2.1
sortedcollections==1.1.2
sortedcontainers==2.1.0
soupsieve==1.8
Sphinx==1.8.5
sphinxcontrib-websupport==1.1.0
spyder==3.3.3
spyder-kernels==0.4.2
SQLAlchemy==1.3.10
statsmodels==0.9.0
sympy==1.3
TA-Lib==0.4.17
tables==3.5.1
tabulate==0.8.5
tblib==1.3.2
terminado==0.8.1
testpath==0.4.2
toolz==0.9.0
tornado==6.0.2
tqdm==4.31.1
traitlets==4.3.2
unicodecsv==0.14.1
urllib3==1.25.6
virtualenv==16.6.2
virtualenv-clone==0.5.3
wcwidth==0.1.7
webencodings==0.5.1
Werkzeug==0.15.5
widgetsnbextension==3.4.2
win-inet-pton==1.1.0
win-unicode-console==0.5
wincertstore==0.2
wrapt==1.11.2
xlrd==1.2.0
XlsxWriter==1.1.5
xlwings==0.15.4
xlwt==1.3.0
yarl==1.1.0
zict==0.1.4
zipp==0.3.3
```
Branch: Master | Develop 
```
(base) C:\Users\john\freqtrade>freqtrade --version
freqtrade develop-8dd9b5c6f
```
Last Commit ID:  (git log --format="%H" -n 1)
```
(base) C:\Users\john\freqtrade>git log --format="%H" -n 1
8dd9b5c6fba973b98defc0f9a9e2e3c01af735dd
```

Commit message: Validate stake-currency against pairlist - making sure only correct
pairs are in the whitelist

Patch to review:
diff --git a/freqtrade/configuration/config_validation.py b/freqtrade/configuration/config_validation.py
index 4bfd246778c..ca0e01ba00a 100644
--- a/freqtrade/configuration/config_validation.py
+++ b/freqtrade/configuration/config_validation.py
@@ -131,3 +131,10 @@ def _validate_whitelist(conf: Dict[str, Any]) -> None:
         if (pl.get('method') == 'StaticPairList'
                 and not conf.get('exchange', {}).get('pair_whitelist')):
             raise OperationalException("StaticPairList requires pair_whitelist to be set.")
+
+        if pl.get('method') == 'StaticPairList':
+            stake = conf['stake_currency']
+            pairlist = conf['exchange'].get('pair_whitelist')
+            if not all([p.endswith(f'/{stake}') for p in pairlist]):
+                raise OperationalException(
+                    f"Stake-currency {stake} not compatible with pair-whitelist.")
diff --git a/tests/test_configuration.py b/tests/test_configuration.py
index ae85c74937a..7f708934b78 100644
--- a/tests/test_configuration.py
+++ b/tests/test_configuration.py
@@ -798,6 +798,12 @@ def test_validate_whitelist(default_conf):
 
     validate_config_consistency(conf)
 
+    conf = deepcopy(default_conf)
+    conf['stake_currency'] = 'USDT'
+    with pytest.raises(OperationalException,
+                       match="Stake-currency USDT not compatible with pair-whitelist."):
+        validate_config_consistency(conf)
+
 
 def test_load_config_test_comments() -> None:
     """


Code review comments:
diff_hunk: @@ -131,3 +131,10 @@ def _validate_whitelist(conf: Dict[str, Any]) -> None:
         if (pl.get('method') == 'StaticPairList'
                 and not conf.get('exchange', {}).get('pair_whitelist')):
             raise OperationalException("StaticPairList requires pair_whitelist to be set.")
+
+        if pl.get('method') == 'StaticPairList':
+            stake = conf['stake_currency']
+            pairlist = conf['exchange'].get('pair_whitelist')
+            if not all([p.endswith(f'/{stake}') for p in pairlist]):
+                raise OperationalException(
+                    f"Stake-currency {stake} not compatible with pair-whitelist.")
path: freqtrade/configuration/config_validation.py
text: @user1:
It would be better to iterate the pairlist in the for loop here and include into the exception message the particular pair found which is not compatible with the stake_currency (or get a list of all incompatible and show them all).


@author:
kinda like this ... ? 

@user1:
Right, LGTM 👍