From 89145a7711da5914c473146e4c5023e509261802 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Fri, 22 Mar 2019 13:35:06 +0100 Subject: [PATCH 01/51] Update ccxt from 1.18.385 to 1.18.386 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 3a25bb8bc..53e81aad3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.18.385 +ccxt==1.18.386 SQLAlchemy==1.3.1 python-telegram-bot==11.1.0 arrow==0.13.1 From 34ff946f4dc3042056a3dfa03a648b42d8e932d0 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sat, 23 Mar 2019 13:35:03 +0100 Subject: [PATCH 02/51] Update ccxt from 1.18.386 to 1.18.387 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 53e81aad3..9c083a675 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.18.386 +ccxt==1.18.387 SQLAlchemy==1.3.1 python-telegram-bot==11.1.0 arrow==0.13.1 From 184b13f2fba7a690919d85ca815fdfb4d48e1ee8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 23 Mar 2019 19:18:10 +0100 Subject: [PATCH 03/51] Flake8 for scripts --- .travis.yml | 4 ++-- scripts/get_market_pairs.py | 2 -- scripts/plot_dataframe.py | 6 ++---- scripts/plot_profit.py | 10 ++++------ 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index d24ffcf1b..014eb00ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,7 +29,7 @@ jobs: script: - pytest --cov=freqtrade --cov-config=.coveragerc freqtrade/tests/ # Allow failure for coveralls - - coveralls || true + - coveralls || true name: pytest - script: - cp config.json.example config.json @@ -39,7 +39,7 @@ jobs: - cp config.json.example config.json - python freqtrade/main.py --datadir freqtrade/tests/testdata hyperopt -e 5 name: hyperopt - - script: flake8 freqtrade + - script: flake8 freqtrade scripts name: flake8 - script: mypy freqtrade name: mypy diff --git a/scripts/get_market_pairs.py b/scripts/get_market_pairs.py index 6ee6464d3..1a4c593f9 100644 --- a/scripts/get_market_pairs.py +++ b/scripts/get_market_pairs.py @@ -51,7 +51,6 @@ try: id = sys.argv[1] # get exchange id from command line arguments - # check if the exchange is supported by ccxt exchange_found = id in ccxt.exchanges @@ -90,4 +89,3 @@ except Exception as e: dump('[' + type(e).__name__ + ']', str(e)) dump("Usage: python " + sys.argv[0], green('id')) print_supported_exchanges() - diff --git a/scripts/plot_dataframe.py b/scripts/plot_dataframe.py index 581518b12..2eccaca18 100755 --- a/scripts/plot_dataframe.py +++ b/scripts/plot_dataframe.py @@ -24,24 +24,22 @@ Example of usage: > python3 scripts/plot_dataframe.py --pairs BTC/EUR,XRP/BTC -d user_data/data/ --indicators1 sma,ema3 --indicators2 fastk,fastd """ -import json import logging import sys from argparse import Namespace from pathlib import Path -from typing import Dict, List, Any +from typing import Any, Dict, List import pandas as pd import plotly.graph_objs as go import pytz - from plotly import tools from plotly.offline import plot from freqtrade import persistence from freqtrade.arguments import Arguments, TimeRange from freqtrade.data import history -from freqtrade.data.btanalysis import load_backtest_data, BT_DATA_COLUMNS +from freqtrade.data.btanalysis import BT_DATA_COLUMNS, load_backtest_data from freqtrade.exchange import Exchange from freqtrade.optimize.backtesting import setup_configuration from freqtrade.persistence import Trade diff --git a/scripts/plot_profit.py b/scripts/plot_profit.py index e2f85932f..8361e8bf6 100755 --- a/scripts/plot_profit.py +++ b/scripts/plot_profit.py @@ -12,26 +12,24 @@ Optional Cli parameters --timerange: specify what timerange of data to use --export-filename: Specify where the backtest export is located. """ +import json import logging import sys -import json from argparse import Namespace from pathlib import Path from typing import List, Optional -import numpy as np +import numpy as np +import plotly.graph_objs as go from plotly import tools from plotly.offline import plot -import plotly.graph_objs as go +from freqtrade import constants, misc from freqtrade.arguments import Arguments from freqtrade.configuration import Configuration -from freqtrade import constants from freqtrade.data import history from freqtrade.resolvers import StrategyResolver from freqtrade.state import RunMode -import freqtrade.misc as misc - logger = logging.getLogger(__name__) From 83a2427a61b7025d58e74c49100dc3b65d4c1088 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 23 Mar 2019 19:28:06 +0100 Subject: [PATCH 04/51] Fix mypy in scripts --- .travis.yml | 2 +- docs/plotting.md | 2 +- scripts/plot_dataframe.py | 2 +- scripts/plot_profit.py | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 014eb00ad..71432ea0a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ jobs: name: hyperopt - script: flake8 freqtrade scripts name: flake8 - - script: mypy freqtrade + - script: mypy freqtrade scripts name: mypy - stage: docker diff --git a/docs/plotting.md b/docs/plotting.md index a9b191e75..60c642ab3 100644 --- a/docs/plotting.md +++ b/docs/plotting.md @@ -84,5 +84,5 @@ The `-p` pair argument, can be used to plot a single pair Example ``` -python3 scripts/plot_profit.py --datadir ../freqtrade/freqtrade/tests/testdata-20171221/ -p BTC_LTC +python3 scripts/plot_profit.py --datadir ../freqtrade/freqtrade/tests/testdata-20171221/ -p LTC/BTC ``` diff --git a/scripts/plot_dataframe.py b/scripts/plot_dataframe.py index 2eccaca18..14d57265e 100755 --- a/scripts/plot_dataframe.py +++ b/scripts/plot_dataframe.py @@ -146,7 +146,7 @@ def get_tickers_data(strategy, exchange, pairs: List[str], args): tickers[pair] = exchange.klines((pair, tick_interval)) else: tickers = history.load_data( - datadir=Path(_CONF.get("datadir")), + datadir=Path(str(_CONF.get("datadir"))), pairs=pairs, ticker_interval=tick_interval, refresh_pairs=_CONF.get('refresh_pairs', False), diff --git a/scripts/plot_profit.py b/scripts/plot_profit.py index 8361e8bf6..394f02116 100755 --- a/scripts/plot_profit.py +++ b/scripts/plot_profit.py @@ -37,7 +37,7 @@ logger = logging.getLogger(__name__) # data:: [ pair, profit-%, enter, exit, time, duration] # data:: ["ETH/BTC", 0.0023975, "1515598200", "1515602100", "2018-01-10 07:30:00+00:00", 65] def make_profit_array(data: List, px: int, min_date: int, - interval: int, + interval: str, filter_pairs: Optional[List] = None) -> np.ndarray: pg = np.zeros(px) filter_pairs = filter_pairs or [] @@ -120,7 +120,7 @@ def plot_profit(args: Namespace) -> None: logger.info('Filter, keep pairs %s' % pairs) tickers = history.load_data( - datadir=Path(config.get('datadir')), + datadir=Path(str(config.get('datadir'))), pairs=pairs, ticker_interval=tick_interval, refresh_pairs=False, @@ -178,7 +178,7 @@ def plot_profit(args: Namespace) -> None: fig.append_trace(profit, 2, 1) for pair in pairs: - pg = make_profit_array(data, num_iterations, min_date, tick_interval, pair) + pg = make_profit_array(data, num_iterations, min_date, tick_interval, [pair]) pair_profit = go.Scattergl( x=dates, y=pg, From a95f30ce452b06d16a854ccf04e182d1f350c2b4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 23 Mar 2019 19:40:52 +0100 Subject: [PATCH 05/51] Fix custom boxes on documentation --- docs/bot-optimization.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/bot-optimization.md b/docs/bot-optimization.md index 8592f6cca..00ed470f5 100644 --- a/docs/bot-optimization.md +++ b/docs/bot-optimization.md @@ -250,17 +250,17 @@ class Awesomestrategy(IStrategy): self.cust_info[metadata["pair"]["crosstime"] = 1 ``` -!!! Warning: +!!! Warning The data is not persisted after a bot-restart (or config-reload). Also, the amount of data should be kept smallish (no DataFrames and such), otherwise the bot will start to consume a lot of memory and eventually run out of memory and crash. -!!! Note: +!!! Note If the data is pair-specific, make sure to use pair as one of the keys in the dictionary. ### Additional data (DataProvider) The strategy provides access to the `DataProvider`. This allows you to get additional data to use in your strategy. -!!!Note: +!!! Note The DataProvier is currently not available during backtesting / hyperopt, but this is planned for the future. All methods return `None` in case of failure (do not raise an exception). @@ -288,7 +288,7 @@ if self.dp: ticker_interval='1h') ``` -!!! Warning: Warning about backtesting +!!! Warning Warning about backtesting Be carefull when using dataprovider in backtesting. `historic_ohlcv()` provides the full time-range in one go, so please be aware of it and make sure to not "look into the future" to avoid surprises when running in dry/live mode). @@ -317,7 +317,7 @@ def informative_pairs(self): ] ``` -!!! Warning: +!!! Warning As these pairs will be refreshed as part of the regular whitelist refresh, it's best to keep this list short. All intervals and all pairs can be specified as long as they are available (and active) on the used exchange. It is however better to use resampling to longer time-intervals when possible @@ -327,7 +327,7 @@ def informative_pairs(self): The strategy provides access to the `Wallets` object. This contains the current balances on the exchange. -!!!NOTE: +!!! Note Wallets is not available during backtesting / hyperopt. Please always check if `Wallets` is available to avoid failures during backtesting. From 0dc96210b629af0157136f2e31d1763c45cfde61 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 23 Mar 2019 19:43:23 +0100 Subject: [PATCH 06/51] Fix formatting of boxes 2 --- docs/bot-optimization.md | 2 +- docs/hyperopt.md | 4 ++-- docs/installation.md | 6 +++--- docs/sql_cheatsheet.md | 4 ++-- docs/telegram-usage.md | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/bot-optimization.md b/docs/bot-optimization.md index 00ed470f5..d1ab08635 100644 --- a/docs/bot-optimization.md +++ b/docs/bot-optimization.md @@ -47,7 +47,7 @@ python3 ./freqtrade/main.py --strategy AwesomeStrategy **For the following section we will use the [user_data/strategies/test_strategy.py](https://github.com/freqtrade/freqtrade/blob/develop/user_data/strategies/test_strategy.py) file as reference.** -!!! Note: Strategies and Backtesting +!!! Note Strategies and Backtesting To avoid problems and unexpected differences between Backtesting and dry/live modes, please be aware that during backtesting the full time-interval is passed to the `populate_*()` methods at once. It is therefore best to use vectorized operations (across the whole dataframe, not loops) and diff --git a/docs/hyperopt.md b/docs/hyperopt.md index 6e52be47f..14021a341 100644 --- a/docs/hyperopt.md +++ b/docs/hyperopt.md @@ -293,8 +293,8 @@ You can overwrite position stacking in the configuration by explicitly setting ` Enabling the market-position for hyperopt is currently not possible. -!!! Note: -Dry/live runs will **NOT** use position stacking - therefore it does make sense to also validate the strategy without this as it's closer to reality. +!!! Note + Dry/live runs will **NOT** use position stacking - therefore it does make sense to also validate the strategy without this as it's closer to reality. ## Next Step diff --git a/docs/installation.md b/docs/installation.md index bd6c50c5a..02fdf5b8f 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -437,9 +437,9 @@ when it changes. The `freqtrade.service.watchdog` file contains an example of the service unit configuration file which uses systemd as the watchdog. -!!! Note: -The sd_notify communication between the bot and the systemd service manager will not work if the bot runs in a -Docker container. +!!! Note + The sd_notify communication between the bot and the systemd service manager will not work if the bot runs in a + Docker container. ------ diff --git a/docs/sql_cheatsheet.md b/docs/sql_cheatsheet.md index e85aceec8..54f9b8213 100644 --- a/docs/sql_cheatsheet.md +++ b/docs/sql_cheatsheet.md @@ -65,11 +65,11 @@ SELECT * FROM trades; ## Fix trade still open after a manual sell on the exchange -!!! Warning: +!!! Warning Manually selling on the exchange should not be done by default, since the bot does not detect this and will try to sell anyway. /foresell should accomplish the same thing. -!!! Note: +!!! Note This should not be necessary after /forcesell, as forcesell orders are closed automatically by the bot on the next iteration. ```sql diff --git a/docs/telegram-usage.md b/docs/telegram-usage.md index face22404..92d60c7ed 100644 --- a/docs/telegram-usage.md +++ b/docs/telegram-usage.md @@ -55,8 +55,8 @@ Once all positions are sold, run `/stop` to completely stop the bot. `/reload_conf` resets "max_open_trades" to the value set in the configuration and resets this command. -!!! warning: -The stop-buy signal is ONLY active while the bot is running, and is not persisted anyway, so restarting the bot will cause this to reset. +!!! warning + The stop-buy signal is ONLY active while the bot is running, and is not persisted anyway, so restarting the bot will cause this to reset. ### /status From 06f4e627fcf8ba33ed58dd4ed390b98a3c5428a7 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 23 Mar 2019 20:40:07 +0100 Subject: [PATCH 07/51] Add stake_currency to strategy, fix documentation typo --- docs/bot-optimization.md | 10 +++++----- freqtrade/resolvers/strategy_resolver.py | 2 ++ freqtrade/tests/strategy/test_strategy.py | 4 +++- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/bot-optimization.md b/docs/bot-optimization.md index 8592f6cca..89d35848e 100644 --- a/docs/bot-optimization.md +++ b/docs/bot-optimization.md @@ -278,13 +278,13 @@ Please always check if the `DataProvider` is available to avoid failures during ``` python if self.dp: - if dp.runmode == 'live': - if ('ETH/BTC', ticker_interval) in self.dp.available_pairs: - data_eth = self.dp.ohlcv(pair='ETH/BTC', - ticker_interval=ticker_interval) + if self.dp.runmode == 'live': + if (f'{self.stake_currency}/BTC', self.ticker_interval) in self.dp.available_pairs: + data_eth = self.dp.ohlcv(pair='{self.stake_currency}/BTC', + ticker_interval=self.ticker_interval) else: # Get historic ohlcv data (cached on disk). - history_eth = self.dp.historic_ohlcv(pair='ETH/BTC', + history_eth = self.dp.historic_ohlcv(pair='{self.stake_currency}/BTC', ticker_interval='1h') ``` diff --git a/freqtrade/resolvers/strategy_resolver.py b/freqtrade/resolvers/strategy_resolver.py index cece5a5d1..44cc3fe76 100644 --- a/freqtrade/resolvers/strategy_resolver.py +++ b/freqtrade/resolvers/strategy_resolver.py @@ -56,6 +56,8 @@ class StrategyResolver(IResolver): ("process_only_new_candles", None, False), ("order_types", None, False), ("order_time_in_force", None, False), + ("stake_currency", None, False), + ("stake_amount", None, False), ("use_sell_signal", False, True), ("sell_profit_only", False, True), ("ignore_roi_if_buy_signal", False, True), diff --git a/freqtrade/tests/strategy/test_strategy.py b/freqtrade/tests/strategy/test_strategy.py index 602ea5dbe..b63180d1e 100644 --- a/freqtrade/tests/strategy/test_strategy.py +++ b/freqtrade/tests/strategy/test_strategy.py @@ -194,11 +194,13 @@ def test_strategy_override_ticker_interval(caplog): config = { 'strategy': 'DefaultStrategy', - 'ticker_interval': 60 + 'ticker_interval': 60, + 'stake_currency': 'ETH' } resolver = StrategyResolver(config) assert resolver.strategy.ticker_interval == 60 + assert resolver.strategy.stake_currency == 'ETH' assert ('freqtrade.resolvers.strategy_resolver', logging.INFO, "Override strategy 'ticker_interval' with value in config file: 60." From e644493e02b4877e160eb95a638dfc9c58a82715 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sun, 24 Mar 2019 13:35:03 +0100 Subject: [PATCH 08/51] Update ccxt from 1.18.387 to 1.18.395 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 9c083a675..73c65aff6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.18.387 +ccxt==1.18.395 SQLAlchemy==1.3.1 python-telegram-bot==11.1.0 arrow==0.13.1 From e60d1788b28a92f75959a4d096cceb58440d3e57 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Mar 2019 15:06:17 +0100 Subject: [PATCH 09/51] Add new options to docu --- docs/configuration.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 4b8d990fe..11b941220 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -14,8 +14,8 @@ Mandatory Parameters are marked as **Required**. | Command | Default | Description | |----------|---------|-------------| | `max_open_trades` | 3 | **Required.** Number of trades open your bot will have. If -1 then it is ignored (i.e. potentially unlimited open trades) -| `stake_currency` | BTC | **Required.** Crypto-currency used for trading. -| `stake_amount` | 0.05 | **Required.** Amount of crypto-currency your bot will use for each trade. Per default, the bot will use (0.05 BTC x 3) = 0.15 BTC in total will be always engaged. Set it to `"unlimited"` to allow the bot to use all available balance. +| `stake_currency` | BTC | **Required.** Crypto-currency used for trading. [Strategy Override](#parameters-in-the-strategy). +| `stake_amount` | 0.05 | **Required.** Amount of crypto-currency your bot will use for each trade. Per default, the bot will use (0.05 BTC x 3) = 0.15 BTC in total will be always engaged. Set it to `"unlimited"` to allow the bot to use all available balance. [Strategy Override](#parameters-in-the-strategy). | `amount_reserve_percent` | 0.05 | Reserve some amount in min pair stake amount. Default is 5%. The bot will reserve `amount_reserve_percent` + stop-loss value when calculating min pair stake amount in order to avoid possible trade refusals. | `ticker_interval` | [1m, 5m, 15m, 30m, 1h, 1d, ...] | The ticker interval to use (1min, 5 min, 15 min, 30 min, 1 hour or 1 day). Default is 5 minutes. [Strategy Override](#parameters-in-the-strategy). | `fiat_display_currency` | USD | **Required.** Fiat currency used to show your profits. More information below. @@ -77,8 +77,10 @@ Mandatory Parameters are marked as **Required**. The following parameters can be set in either configuration file or strategy. Values set in the configuration file always overwrite values set in the strategy. -* `minimal_roi` +* `stake_currency` +* `stake_amount` * `ticker_interval` +* `minimal_roi` * `stoploss` * `trailing_stop` * `trailing_stop_positive` From f7fc9adc638367cde602e3d2222530dd46030101 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Mar 2019 15:13:03 +0100 Subject: [PATCH 10/51] Run travis with freqtrade, not main.py --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index d24ffcf1b..a711290ea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,15 +29,15 @@ jobs: script: - pytest --cov=freqtrade --cov-config=.coveragerc freqtrade/tests/ # Allow failure for coveralls - - coveralls || true + - coveralls || true name: pytest - script: - cp config.json.example config.json - - python freqtrade/main.py --datadir freqtrade/tests/testdata backtesting + - python freqtrade --datadir freqtrade/tests/testdata backtesting name: backtest - script: - cp config.json.example config.json - - python freqtrade/main.py --datadir freqtrade/tests/testdata hyperopt -e 5 + - python freqtrade --datadir freqtrade/tests/testdata hyperopt -e 5 name: hyperopt - script: flake8 freqtrade name: flake8 From 1bba9fcc53bed652cca3e55d6596f51b5a0791f2 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Mar 2019 15:13:17 +0100 Subject: [PATCH 11/51] Update documentation to use freqtrade, not freqtrade/main.py fixes #1521 --- docs/backtesting.md | 18 +++++++++--------- docs/bot-optimization.md | 6 +++--- docs/bot-usage.md | 12 ++++++------ docs/deprecated.md | 4 ++-- docs/edge.md | 22 +++++++++++++++++----- docs/faq.md | 10 ++++++---- docs/hyperopt.md | 4 ++-- docs/installation.md | 2 +- setup.sh | 2 +- 9 files changed, 47 insertions(+), 33 deletions(-) diff --git a/docs/backtesting.md b/docs/backtesting.md index 932783160..a25d3c1d5 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -24,37 +24,37 @@ The backtesting is very easy with freqtrade. #### With 5 min tickers (Per default) ```bash -python3 ./freqtrade/main.py backtesting +python3 freqtrade backtesting ``` #### With 1 min tickers ```bash -python3 ./freqtrade/main.py backtesting --ticker-interval 1m +python3 freqtrade backtesting --ticker-interval 1m ``` #### Update cached pairs with the latest data ```bash -python3 ./freqtrade/main.py backtesting --refresh-pairs-cached +python3 freqtrade backtesting --refresh-pairs-cached ``` #### With live data (do not alter your testdata files) ```bash -python3 ./freqtrade/main.py backtesting --live +python3 freqtrade backtesting --live ``` #### Using a different on-disk ticker-data source ```bash -python3 ./freqtrade/main.py backtesting --datadir freqtrade/tests/testdata-20180101 +python3 freqtrade backtesting --datadir freqtrade/tests/testdata-20180101 ``` #### With a (custom) strategy file ```bash -python3 ./freqtrade/main.py -s TestStrategy backtesting +python3 freqtrade -s TestStrategy backtesting ``` Where `-s TestStrategy` refers to the class name within the strategy file `test_strategy.py` found in the `freqtrade/user_data/strategies` directory @@ -62,7 +62,7 @@ Where `-s TestStrategy` refers to the class name within the strategy file `test_ #### Exporting trades to file ```bash -python3 ./freqtrade/main.py backtesting --export trades +python3 freqtrade backtesting --export trades ``` The exported trades can be used for [further analysis](#further-backtest-result-analysis), or can be used by the plotting script `plot_dataframe.py` in the scripts folder. @@ -70,7 +70,7 @@ The exported trades can be used for [further analysis](#further-backtest-result- #### Exporting trades to file specifying a custom filename ```bash -python3 ./freqtrade/main.py backtesting --export trades --export-filename=backtest_teststrategy.json +python3 freqtrade backtesting --export trades --export-filename=backtest_teststrategy.json ``` #### Running backtest with smaller testset @@ -81,7 +81,7 @@ you want to use. The last N ticks/timeframes will be used. Example: ```bash -python3 ./freqtrade/main.py backtesting --timerange=-200 +python3 freqtrade backtesting --timerange=-200 ``` #### Advanced use of timerange diff --git a/docs/bot-optimization.md b/docs/bot-optimization.md index d1ab08635..511be18fa 100644 --- a/docs/bot-optimization.md +++ b/docs/bot-optimization.md @@ -14,7 +14,7 @@ Let assume you have a class called `AwesomeStrategy` in the file `awesome-strate 2. Start the bot with the param `--strategy AwesomeStrategy` (the parameter is the class name) ```bash -python3 ./freqtrade/main.py --strategy AwesomeStrategy +python3 freqtrade --strategy AwesomeStrategy ``` ## Change your strategy @@ -41,7 +41,7 @@ The bot also include a sample strategy called `TestStrategy` you can update: `us You can test it with the parameter: `--strategy TestStrategy` ```bash -python3 ./freqtrade/main.py --strategy AwesomeStrategy +python3 freqtrade --strategy AwesomeStrategy ``` **For the following section we will use the [user_data/strategies/test_strategy.py](https://github.com/freqtrade/freqtrade/blob/develop/user_data/strategies/test_strategy.py) @@ -355,7 +355,7 @@ The default buy strategy is located in the file If you want to use a strategy from a different folder you can pass `--strategy-path` ```bash -python3 ./freqtrade/main.py --strategy AwesomeStrategy --strategy-path /some/folder +python3 freqtrade --strategy AwesomeStrategy --strategy-path /some/folder ``` ### Further strategy ideas diff --git a/docs/bot-usage.md b/docs/bot-usage.md index 739a89c07..35e4a776d 100644 --- a/docs/bot-usage.md +++ b/docs/bot-usage.md @@ -47,7 +47,7 @@ The bot allows you to select which configuration file you want to use. Per default, the bot will load the file `./config.json` ```bash -python3 ./freqtrade/main.py -c path/far/far/away/config.json +python3 freqtrade -c path/far/far/away/config.json ``` ### How to use multiple configuration files? @@ -63,13 +63,13 @@ empty key and secrete values while running in the Dry Mode (which does not actua require them): ```bash -python3 ./freqtrade/main.py -c ./config.json +python3 freqtrade -c ./config.json ``` and specify both configuration files when running in the normal Live Trade Mode: ```bash -python3 ./freqtrade/main.py -c ./config.json -c path/to/secrets/keys.config.json +python3 freqtrade -c ./config.json -c path/to/secrets/keys.config.json ``` This could help you hide your private Exchange key and Exchange secrete on you local machine @@ -95,7 +95,7 @@ In `user_data/strategies` you have a file `my_awesome_strategy.py` which has a strategy class called `AwesomeStrategy` to load it: ```bash -python3 ./freqtrade/main.py --strategy AwesomeStrategy +python3 freqtrade --strategy AwesomeStrategy ``` If the bot does not find your strategy file, it will display in an error @@ -109,7 +109,7 @@ Learn more about strategy file in This parameter allows you to add an additional strategy lookup path, which gets checked before the default locations (The passed path must be a folder!): ```bash -python3 ./freqtrade/main.py --strategy AwesomeStrategy --strategy-path /some/folder +python3 freqtrade --strategy AwesomeStrategy --strategy-path /some/folder ``` #### How to install a strategy? @@ -136,7 +136,7 @@ using `--db-url`. This can also be used to specify a custom database in production mode. Example command: ```bash -python3 ./freqtrade/main.py -c config.json --db-url sqlite:///tradesv3.dry_run.sqlite +python3 freqtrade -c config.json --db-url sqlite:///tradesv3.dry_run.sqlite ``` ## Backtesting commands diff --git a/docs/deprecated.md b/docs/deprecated.md index 25043d981..c218bd360 100644 --- a/docs/deprecated.md +++ b/docs/deprecated.md @@ -13,14 +13,14 @@ on BaseVolume. This value can be changed when you run the script. Get the 20 currencies based on BaseVolume. ```bash -python3 ./freqtrade/main.py --dynamic-whitelist +python3 freqtrade --dynamic-whitelist ``` **Customize the number of currencies to retrieve** Get the 30 currencies based on BaseVolume. ```bash -python3 ./freqtrade/main.py --dynamic-whitelist 30 +python3 freqtrade --dynamic-whitelist 30 ``` **Exception** diff --git a/docs/edge.md b/docs/edge.md index 7372e3373..b0e0b2d42 100644 --- a/docs/edge.md +++ b/docs/edge.md @@ -146,16 +146,19 @@ Percentage of allowed risk per trade. (defaults to 0.01 so 1%) #### stoploss_range_min + Minimum stoploss. (defaults to -0.01) #### stoploss_range_max + Maximum stoploss. (defaults to -0.10) #### stoploss_range_step + As an example if this is set to -0.01 then Edge will test the strategy for \[-0.01, -0,02, -0,03 ..., -0.09, -0.10\] ranges. Note than having a smaller step means having a bigger range which could lead to slow calculation. @@ -164,6 +167,7 @@ If you set this parameter to -0.001, you then slow down the Edge calculation by (defaults to -0.01) #### minimum_winrate + It filters out pairs which don't have at least minimum_winrate. This comes handy if you want to be conservative and don't comprise win rate in favour of risk reward ratio. @@ -171,6 +175,7 @@ This comes handy if you want to be conservative and don't comprise win rate in f (defaults to 0.60) #### minimum_expectancy + It filters out pairs which have the expectancy lower than this number. Having an expectancy of 0.20 means if you put 10$ on a trade you expect a 12$ return. @@ -178,6 +183,7 @@ Having an expectancy of 0.20 means if you put 10$ on a trade you expect a 12$ re (defaults to 0.20) #### min_trade_number + When calculating *W*, *R* and *E* (expectancy) against historical data, you always want to have a minimum number of trades. The more this number is the more Edge is reliable. Having a win rate of 100% on a single trade doesn't mean anything at all. But having a win rate of 70% over past 100 trades means clearly something. @@ -185,6 +191,7 @@ Having a win rate of 100% on a single trade doesn't mean anything at all. But ha (defaults to 10, it is highly recommended not to decrease this number) #### max_trade_duration_minute + Edge will filter out trades with long duration. If a trade is profitable after 1 month, it is hard to evaluate the strategy based on it. But if most of trades are profitable and they have maximum duration of 30 minutes, then it is clearly a good sign. **NOTICE:** While configuring this value, you should take into consideration your ticker interval. As an example filtering out trades having duration less than one day for a strategy which has 4h interval does not make sense. Default value is set assuming your strategy interval is relatively small (1m or 5m, etc.). @@ -192,15 +199,17 @@ Edge will filter out trades with long duration. If a trade is profitable after 1 (defaults to 1 day, i.e. to 60 * 24 = 1440 minutes) #### remove_pumps + Edge will remove sudden pumps in a given market while going through historical data. However, given that pumps happen very often in crypto markets, we recommend you keep this off. (defaults to false) - ## Running Edge independently + You can run Edge independently in order to see in details the result. Here is an example: + ```bash -python3 ./freqtrade/main.py edge +python3 freqtrade edge ``` An example of its output: @@ -224,18 +233,21 @@ An example of its output: | NEBL/BTC | -0.03 | 0.63 | 1.29 | 0.58 | 0.44 | 19 | 59 | ### Update cached pairs with the latest data + ```bash -python3 ./freqtrade/main.py edge --refresh-pairs-cached +python3 freqtrade edge --refresh-pairs-cached ``` ### Precising stoploss range + ```bash -python3 ./freqtrade/main.py edge --stoplosses=-0.01,-0.1,-0.001 #min,max,step +python3 freqtrade edge --stoplosses=-0.01,-0.1,-0.001 #min,max,step ``` ### Advanced use of timerange + ```bash -python3 ./freqtrade/main.py edge --timerange=20181110-20181113 +python3 freqtrade edge --timerange=20181110-20181113 ``` Doing `--timerange=-200` will get the last 200 timeframes from your inputdata. You can also specify specific dates, or a range span indexed by start and stop. diff --git a/docs/faq.md b/docs/faq.md index 127f69e9f..60c1509e0 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -46,22 +46,24 @@ have to run it for 10.000 or more. But it will take an eternity to compute. We recommend you to run it at least 10.000 epochs: + ```bash -python3 ./freqtrade/main.py hyperopt -e 10000 +python3 freqtrade hyperopt -e 10000 ``` or if you want intermediate result to see + ```bash -for i in {1..100}; do python3 ./freqtrade/main.py hyperopt -e 100; done +for i in {1..100}; do python3 freqtrade hyperopt -e 100; done ``` #### Why it is so long to run hyperopt? + Finding a great Hyperopt results takes time. If you wonder why it takes a while to find great hyperopt results -This answer was written during the under the release 0.15.1, when we had -: +This answer was written during the under the release 0.15.1, when we had: - 8 triggers - 9 guards: let's say we evaluate even 10 values from each - 1 stoploss calculation: let's say we want 10 values from that too to diff --git a/docs/hyperopt.md b/docs/hyperopt.md index 14021a341..e25f35c35 100644 --- a/docs/hyperopt.md +++ b/docs/hyperopt.md @@ -152,7 +152,7 @@ Because hyperopt tries a lot of combinations to find the best parameters it will We strongly recommend to use `screen` or `tmux` to prevent any connection loss. ```bash -python3 ./freqtrade/main.py -c config.json hyperopt --customhyperopt -e 5000 --spaces all +python3 freqtrade -c config.json hyperopt --customhyperopt -e 5000 --spaces all ``` Use `` as the name of the custom hyperopt used. @@ -178,7 +178,7 @@ you want to use. The last N ticks/timeframes will be used. Example: ```bash -python3 ./freqtrade/main.py hyperopt --timerange -200 +python3 freqtrade hyperopt --timerange -200 ``` ### Running Hyperopt with Smaller Search Space diff --git a/docs/installation.md b/docs/installation.md index 02fdf5b8f..995bc561b 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -407,7 +407,7 @@ pip3 install -e . If this is the first time you run the bot, ensure you are running it in Dry-run `"dry_run": true,` otherwise it will start to buy and sell coins. ```bash -python3.6 ./freqtrade/main.py -c config.json +python3.6 freqtrade -c config.json ``` *Note*: If you run the bot on a server, you should consider using [Docker](#automatic-installation---docker) a terminal multiplexer like `screen` or [`tmux`](https://en.wikipedia.org/wiki/Tmux) to avoid that the bot is stopped on logout. diff --git a/setup.sh b/setup.sh index 66d449037..11df6820e 100755 --- a/setup.sh +++ b/setup.sh @@ -235,7 +235,7 @@ function install() { echo "-------------------------" echo "Run the bot !" echo "-------------------------" - echo "You can now use the bot by executing 'source .env/bin/activate; python freqtrade/main.py'." + echo "You can now use the bot by executing 'source .env/bin/activate; python freqtrade'." } function plot() { From 3a8b69d69becf6aa7711a29d1dc7ce6c2c3791b7 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Mar 2019 15:37:58 +0100 Subject: [PATCH 12/51] also support dry_run --- docs/bot-optimization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/bot-optimization.md b/docs/bot-optimization.md index 89d35848e..276c992f1 100644 --- a/docs/bot-optimization.md +++ b/docs/bot-optimization.md @@ -278,7 +278,7 @@ Please always check if the `DataProvider` is available to avoid failures during ``` python if self.dp: - if self.dp.runmode == 'live': + if self.dp.runmode in ('live', 'dry_run'): if (f'{self.stake_currency}/BTC', self.ticker_interval) in self.dp.available_pairs: data_eth = self.dp.ohlcv(pair='{self.stake_currency}/BTC', ticker_interval=self.ticker_interval) From 684727b32ea11c8f1b4a4e8a120db215bb32fa7e Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Mar 2019 16:08:48 +0100 Subject: [PATCH 13/51] Add black blacklist handler (ro) --- freqtrade/rpc/rpc.py | 10 +++++++++- freqtrade/rpc/telegram.py | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index a0ffff107..687ee9375 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -456,7 +456,15 @@ class RPC(object): def _rpc_whitelist(self) -> Dict: """ Returns the currently active whitelist""" res = {'method': self._freqtrade.pairlists.name, - 'length': len(self._freqtrade.pairlists.whitelist), + 'length': len(self._freqtrade.active_pair_whitelist), 'whitelist': self._freqtrade.active_pair_whitelist } return res + + def _rpc_blacklist(self) -> Dict: + """ Returns the currently active blacklist""" + res = {'method': self._freqtrade.pairlists.name, + 'length': len(self._freqtrade.pairlists.blacklist), + 'blacklist': self._freqtrade.pairlists.blacklist + } + return res diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 6771ec803..903efe7d1 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -93,6 +93,7 @@ class Telegram(RPC): CommandHandler('reload_conf', self._reload_conf), CommandHandler('stopbuy', self._stopbuy), CommandHandler('whitelist', self._whitelist), + CommandHandler('blacklist', self._blacklist), CommandHandler('help', self._help), CommandHandler('version', self._version), ] @@ -470,6 +471,23 @@ class Telegram(RPC): except RPCException as e: self._send_msg(str(e), bot=bot) + @authorized_only + def _blacklist(self, bot: Bot, update: Update) -> None: + """ + Handler for /blacklist + Shows the currently active blacklist + """ + try: + blacklist = self._rpc_blacklist() + + message = f"Using blacklist `{blacklist['method']}` with {blacklist['length']} pairs\n" + message += f"`{', '.join(blacklist['blacklist'])}`" + + logger.debug(message) + self._send_msg(message) + except RPCException as e: + self._send_msg(str(e), bot=bot) + @authorized_only def _help(self, bot: Bot, update: Update) -> None: """ @@ -497,6 +515,7 @@ class Telegram(RPC): "*/stopbuy:* `Stops buying, but handles open trades gracefully` \n" \ "*/reload_conf:* `Reload configuration file` \n" \ "*/whitelist:* `Show current whitelist` \n" \ + "*/blacklist:* `Show current blacklist` \n" \ "*/help:* `This help message`\n" \ "*/version:* `Show version`" From ffdca7eea7d62969e9c580fe9a4599453241e541 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Mar 2019 16:09:04 +0100 Subject: [PATCH 14/51] Add blacklist to default_config --- freqtrade/tests/conftest.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/freqtrade/tests/conftest.py b/freqtrade/tests/conftest.py index 26262cb4b..c0f8e49b7 100644 --- a/freqtrade/tests/conftest.py +++ b/freqtrade/tests/conftest.py @@ -171,6 +171,10 @@ def default_conf(): "LTC/BTC", "XRP/BTC", "NEO/BTC" + ], + "pair_blacklist": [ + "DOGE/BTC", + "HOT/BTC", ] }, "telegram": { From 8b2174d249135b285932892cbd417af5c470747a Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Mar 2019 16:09:20 +0100 Subject: [PATCH 15/51] Add tests for /blacklist handler --- freqtrade/tests/rpc/test_rpc.py | 12 ++++++++++++ freqtrade/tests/rpc/test_rpc_telegram.py | 20 +++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/freqtrade/tests/rpc/test_rpc.py b/freqtrade/tests/rpc/test_rpc.py index baddc0685..b1fbd27ff 100644 --- a/freqtrade/tests/rpc/test_rpc.py +++ b/freqtrade/tests/rpc/test_rpc.py @@ -693,3 +693,15 @@ def test_rpc_whitelist_dynamic(mocker, default_conf) -> None: assert ret['method'] == 'VolumePairList' assert ret['length'] == 4 assert ret['whitelist'] == default_conf['exchange']['pair_whitelist'] + + +def test_rpc_blacklist(mocker, default_conf) -> None: + patch_coinmarketcap(mocker) + patch_exchange(mocker) + mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) + + freqtradebot = FreqtradeBot(default_conf) + rpc = RPC(freqtradebot) + ret = rpc._rpc_blacklist() + assert ret['method'] == 'StaticPairList' + assert ret['blacklist'] == default_conf['exchange']['pair_blacklist'] diff --git a/freqtrade/tests/rpc/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py index 8e8d1f1bb..fec2e508c 100644 --- a/freqtrade/tests/rpc/test_rpc_telegram.py +++ b/freqtrade/tests/rpc/test_rpc_telegram.py @@ -74,7 +74,7 @@ def test_init(default_conf, mocker, caplog) -> None: message_str = "rpc.telegram is listening for following commands: [['status'], ['profit'], " \ "['balance'], ['start'], ['stop'], ['forcesell'], ['forcebuy'], " \ "['performance'], ['daily'], ['count'], ['reload_conf'], " \ - "['stopbuy'], ['whitelist'], ['help'], ['version']]" + "['stopbuy'], ['whitelist'], ['blacklist'], ['help'], ['version']]" assert log_has(message_str, caplog.record_tuples) @@ -1074,6 +1074,24 @@ def test_whitelist_dynamic(default_conf, update, mocker) -> None: in msg_mock.call_args_list[0][0][0]) +def test_blacklist_static(default_conf, update, mocker) -> None: + patch_coinmarketcap(mocker) + msg_mock = MagicMock() + mocker.patch.multiple( + 'freqtrade.rpc.telegram.Telegram', + _init=MagicMock(), + _send_msg=msg_mock + ) + freqtradebot = get_patched_freqtradebot(mocker, default_conf) + + telegram = Telegram(freqtradebot) + + telegram._blacklist(bot=MagicMock(), update=update) + assert msg_mock.call_count == 1 + assert ('Using blacklist `StaticPairList` with 2 pairs\n`DOGE/BTC, HOT/BTC`' + in msg_mock.call_args_list[0][0][0]) + + def test_help_handle(default_conf, update, mocker) -> None: patch_coinmarketcap(mocker) msg_mock = MagicMock() From 7b99d5ebcbb742d724232c606ca5a87691e9bcdb Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Mar 2019 16:16:39 +0100 Subject: [PATCH 16/51] Add blacklist and whitelist commands to telegram docs --- docs/telegram-usage.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/telegram-usage.md b/docs/telegram-usage.md index 92d60c7ed..671229242 100644 --- a/docs/telegram-usage.md +++ b/docs/telegram-usage.md @@ -28,6 +28,8 @@ official commands. You can ask at any moment for help with `/help`. | `/performance` | | Show performance of each finished trade grouped by pair | `/balance` | | Show account balance per currency | `/daily ` | 7 | Shows profit or loss per day, over the last n days +| `/whitelist` | | Show the current whitelist +| `/blacklist` | | Show the current blacklist | `/help` | | Show help message | `/version` | | Show version @@ -160,6 +162,21 @@ Day Profit BTC Profit USD 2018-01-01 0.00269130 BTC 34.986 USD ``` +### /whitelist + +Shows the current whitelist + +> Using whitelist `StaticPairList` with 22 pairs +> `IOTA/BTC, NEO/BTC, TRX/BTC, VET/BTC, ADA/BTC, ETC/BTC, NCASH/BTC, DASH/BTC, XRP/BTC, XVG/BTC, EOS/BTC, LTC/BTC, OMG/BTC, BTG/BTC, LSK/BTC, ZEC/BTC, HOT/BTC, IOTX/BTC, XMR/BTC, AST/BTC, XLM/BTC, NANO/BTC` + + +### /blacklist + +Shows the current blacklist + +> Using blacklist `StaticPairList` with 2 pairs +>`DODGE/BTC`, `HOT/BTC`. + ### /version > **Version:** `0.14.3` From 9d6f629f6a50f29d8f497b2baaf8623995f87dcd Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Mar 2019 16:28:14 +0100 Subject: [PATCH 17/51] Support adding pairs to blacklist --- freqtrade/rpc/rpc.py | 5 ++++- freqtrade/rpc/telegram.py | 11 ++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 687ee9375..cacca4e3c 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -461,8 +461,11 @@ class RPC(object): } return res - def _rpc_blacklist(self) -> Dict: + def _rpc_blacklist(self, add: List[str]) -> Dict: """ Returns the currently active blacklist""" + if add: + self._freqtrade.pairlists.blacklist.extend(add) + res = {'method': self._freqtrade.pairlists.name, 'length': len(self._freqtrade.pairlists.blacklist), 'blacklist': self._freqtrade.pairlists.blacklist diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 903efe7d1..92108ded9 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -4,7 +4,7 @@ This module manage Telegram communication """ import logging -from typing import Any, Callable, Dict +from typing import Any, Callable, Dict, List from tabulate import tabulate from telegram import Bot, ParseMode, ReplyKeyboardMarkup, Update @@ -93,7 +93,7 @@ class Telegram(RPC): CommandHandler('reload_conf', self._reload_conf), CommandHandler('stopbuy', self._stopbuy), CommandHandler('whitelist', self._whitelist), - CommandHandler('blacklist', self._blacklist), + CommandHandler('blacklist', self._blacklist, pass_args=True), CommandHandler('help', self._help), CommandHandler('version', self._version), ] @@ -472,15 +472,16 @@ class Telegram(RPC): self._send_msg(str(e), bot=bot) @authorized_only - def _blacklist(self, bot: Bot, update: Update) -> None: + def _blacklist(self, bot: Bot, update: Update, args: List[str]) -> None: """ Handler for /blacklist Shows the currently active blacklist """ try: - blacklist = self._rpc_blacklist() - message = f"Using blacklist `{blacklist['method']}` with {blacklist['length']} pairs\n" + blacklist = self._rpc_blacklist(args) + + message = f"Blacklist contains {blacklist['length']} pairs\n" message += f"`{', '.join(blacklist['blacklist'])}`" logger.debug(message) From f0d3901b6b77976836a0fb300b7980b7f3b9fdfc Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Mar 2019 16:29:58 +0100 Subject: [PATCH 18/51] Add blacklist-pair to documentation --- docs/telegram-usage.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/telegram-usage.md b/docs/telegram-usage.md index 671229242..d0ee2849d 100644 --- a/docs/telegram-usage.md +++ b/docs/telegram-usage.md @@ -29,7 +29,7 @@ official commands. You can ask at any moment for help with `/help`. | `/balance` | | Show account balance per currency | `/daily ` | 7 | Shows profit or loss per day, over the last n days | `/whitelist` | | Show the current whitelist -| `/blacklist` | | Show the current blacklist +| `/blacklist [pair]` | | Show the current blacklist, or adds a pair to the blacklist. | `/help` | | Show help message | `/version` | | Show version @@ -169,10 +169,11 @@ Shows the current whitelist > Using whitelist `StaticPairList` with 22 pairs > `IOTA/BTC, NEO/BTC, TRX/BTC, VET/BTC, ADA/BTC, ETC/BTC, NCASH/BTC, DASH/BTC, XRP/BTC, XVG/BTC, EOS/BTC, LTC/BTC, OMG/BTC, BTG/BTC, LSK/BTC, ZEC/BTC, HOT/BTC, IOTX/BTC, XMR/BTC, AST/BTC, XLM/BTC, NANO/BTC` +### /blacklist [pair] -### /blacklist - -Shows the current blacklist +Shows the current blacklist. +If Pair is set, then this pair will be added to the pairlist. +Use `/reload_conf` to reset the blacklist. > Using blacklist `StaticPairList` with 2 pairs >`DODGE/BTC`, `HOT/BTC`. From 042354d00f2ede1a9052ceb935f6c3edf2dffb73 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Mar 2019 16:30:11 +0100 Subject: [PATCH 19/51] Test blacklist-adding --- freqtrade/tests/rpc/test_rpc_telegram.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/freqtrade/tests/rpc/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py index fec2e508c..6adcda77b 100644 --- a/freqtrade/tests/rpc/test_rpc_telegram.py +++ b/freqtrade/tests/rpc/test_rpc_telegram.py @@ -1086,11 +1086,19 @@ def test_blacklist_static(default_conf, update, mocker) -> None: telegram = Telegram(freqtradebot) - telegram._blacklist(bot=MagicMock(), update=update) + telegram._blacklist(bot=MagicMock(), update=update, args=[]) assert msg_mock.call_count == 1 - assert ('Using blacklist `StaticPairList` with 2 pairs\n`DOGE/BTC, HOT/BTC`' + assert ("Blacklist contains 2 pairs\n`DOGE/BTC, HOT/BTC`" in msg_mock.call_args_list[0][0][0]) + msg_mock.reset_mock() + telegram._blacklist(bot=MagicMock(), update=update, args=["ETH/BTC"]) + assert msg_mock.call_count == 1 + assert ("Blacklist contains 3 pairs\n`DOGE/BTC, HOT/BTC, ETH/BTC`" + in msg_mock.call_args_list[0][0][0]) + assert freqtradebot.pairlists.blacklist == ["DOGE/BTC", "HOT/BTC", "ETH/BTC"] + + def test_help_handle(default_conf, update, mocker) -> None: patch_coinmarketcap(mocker) From 49559f1a1a4b553476ae986bc6bd677dc7f49890 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Mar 2019 16:32:56 +0100 Subject: [PATCH 20/51] Improve documentation and help message --- docs/telegram-usage.md | 1 + freqtrade/rpc/telegram.py | 3 ++- freqtrade/tests/rpc/test_rpc_telegram.py | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/telegram-usage.md b/docs/telegram-usage.md index d0ee2849d..2f7e9ada8 100644 --- a/docs/telegram-usage.md +++ b/docs/telegram-usage.md @@ -173,6 +173,7 @@ Shows the current whitelist Shows the current blacklist. If Pair is set, then this pair will be added to the pairlist. +Also supports multiple pairs, seperated by a space. Use `/reload_conf` to reset the blacklist. > Using blacklist `StaticPairList` with 2 pairs diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 92108ded9..553ac4ed9 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -516,7 +516,8 @@ class Telegram(RPC): "*/stopbuy:* `Stops buying, but handles open trades gracefully` \n" \ "*/reload_conf:* `Reload configuration file` \n" \ "*/whitelist:* `Show current whitelist` \n" \ - "*/blacklist:* `Show current blacklist` \n" \ + "*/blacklist [pair]:* `Show current blacklist, or adds one or more pairs " \ + "to the blacklist.` \n" \ "*/help:* `This help message`\n" \ "*/version:* `Show version`" diff --git a/freqtrade/tests/rpc/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py index 6adcda77b..dd49b0000 100644 --- a/freqtrade/tests/rpc/test_rpc_telegram.py +++ b/freqtrade/tests/rpc/test_rpc_telegram.py @@ -1099,7 +1099,6 @@ def test_blacklist_static(default_conf, update, mocker) -> None: assert freqtradebot.pairlists.blacklist == ["DOGE/BTC", "HOT/BTC", "ETH/BTC"] - def test_help_handle(default_conf, update, mocker) -> None: patch_coinmarketcap(mocker) msg_mock = MagicMock() From 14167f826ba8924c629438461294ab2fb4179690 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Mar 2019 19:44:52 +0100 Subject: [PATCH 21/51] Fix typehints --- freqtrade/rpc/telegram.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 553ac4ed9..2c419e417 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -20,7 +20,7 @@ logger = logging.getLogger(__name__) logger.debug('Included module rpc.telegram ...') -def authorized_only(command_handler: Callable[[Any, Bot, Update], None]) -> Callable[..., Any]: +def authorized_only(command_handler: Callable[..., None]) -> Callable[..., Any]: """ Decorator to check if the message comes from the correct chat_id :param command_handler: Telegram CommandHandler From 29b9bb96f3bc745a0ee88b83b39db7584e732175 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Mar 2019 19:49:49 +0100 Subject: [PATCH 22/51] Fix test to support adding things to pairlist --- freqtrade/tests/rpc/test_rpc.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/freqtrade/tests/rpc/test_rpc.py b/freqtrade/tests/rpc/test_rpc.py index b1fbd27ff..e6f7ea41e 100644 --- a/freqtrade/tests/rpc/test_rpc.py +++ b/freqtrade/tests/rpc/test_rpc.py @@ -702,6 +702,14 @@ def test_rpc_blacklist(mocker, default_conf) -> None: freqtradebot = FreqtradeBot(default_conf) rpc = RPC(freqtradebot) - ret = rpc._rpc_blacklist() + ret = rpc._rpc_blacklist(None) assert ret['method'] == 'StaticPairList' + assert len(ret['blacklist']) == 2 assert ret['blacklist'] == default_conf['exchange']['pair_blacklist'] + assert ret['blacklist'] == ['DOGE/BTC', 'HOT/BTC'] + + ret = rpc._rpc_blacklist(["ETH/BTC"]) + assert ret['method'] == 'StaticPairList' + assert len(ret['blacklist']) == 3 + assert ret['blacklist'] == default_conf['exchange']['pair_blacklist'] + assert ret['blacklist'] == ['DOGE/BTC', 'HOT/BTC', 'ETH/BTC'] From 1dfbf6eed646b6fe3575d8703f0f101053f3aad9 Mon Sep 17 00:00:00 2001 From: Misagh Date: Sun, 24 Mar 2019 22:36:33 +0100 Subject: [PATCH 23/51] darfting edge rpc messages --- freqtrade/rpc/rpc.py | 15 +++++++++++++++ freqtrade/rpc/telegram.py | 23 +++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index a0ffff107..3c0fbeba9 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -460,3 +460,18 @@ class RPC(object): 'whitelist': self._freqtrade.active_pair_whitelist } return res + + def _rpc_edge(self) -> Dict: + """ Returns information related to Edge """ + if not self._freqtrade.edge: + raise RPCException(f'Edge is not enabled.') + + for pair in self._freqtrade.edge._cached_pairs: + res = { + 'pair': pair, + 'winrate': self._freqtrade.edge._cached_pairs[pair].winrate, + 'expectancy': self._freqtrade.edge._cached_pairs[pair].expectancy, + 'stoploss': self._freqtrade.edge._cached_pairs[pair].stoploss, + } + + return res diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 6771ec803..edc380f92 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -470,6 +470,29 @@ class Telegram(RPC): except RPCException as e: self._send_msg(str(e), bot=bot) + @authorized_only + def _edge(self, bot: Bot, update: Update) -> None: + """ + Handler for /edge + Shows informaton related to Edge + """ + try: + edge_pairs = self._rpc_edge() + edge_pairs_tab = tabulate(edge_pairs, + headers=[ + 'Pair', + f'Winrate', + f'Expectancy', + f'Stoploss' + ], + tablefmt='simple') + + message = f'Edge only validated following pairs:\n
{edge_pairs_tab}
' + self._send_msg(message, bot=bot, parse_mode=ParseMode.HTML) + except RPCException as e: + self._send_msg(str(e), bot=bot) + + @authorized_only def _help(self, bot: Bot, update: Update) -> None: """ From a8be277ca022ddf9f41e32a904e3490101e9b6c2 Mon Sep 17 00:00:00 2001 From: Misagh Date: Sun, 24 Mar 2019 22:56:42 +0100 Subject: [PATCH 24/51] cached pairs iteration fixed + help added --- freqtrade/rpc/rpc.py | 16 ++++++++-------- freqtrade/rpc/telegram.py | 13 ++++--------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 3c0fbeba9..fb06c7d86 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -466,12 +466,12 @@ class RPC(object): if not self._freqtrade.edge: raise RPCException(f'Edge is not enabled.') - for pair in self._freqtrade.edge._cached_pairs: - res = { - 'pair': pair, - 'winrate': self._freqtrade.edge._cached_pairs[pair].winrate, - 'expectancy': self._freqtrade.edge._cached_pairs[pair].expectancy, - 'stoploss': self._freqtrade.edge._cached_pairs[pair].stoploss, + return [ + { + 'Pair': pair, + 'Winrate': self._freqtrade.edge._cached_pairs[pair].winrate, + 'Expectancy': self._freqtrade.edge._cached_pairs[pair].expectancy, + 'Stoploss': self._freqtrade.edge._cached_pairs[pair].stoploss, } - - return res + for pair in self._freqtrade.edge._cached_pairs + ] diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index edc380f92..64c35078d 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -93,6 +93,7 @@ class Telegram(RPC): CommandHandler('reload_conf', self._reload_conf), CommandHandler('stopbuy', self._stopbuy), CommandHandler('whitelist', self._whitelist), + CommandHandler('edge', self._edge), CommandHandler('help', self._help), CommandHandler('version', self._version), ] @@ -478,15 +479,8 @@ class Telegram(RPC): """ try: edge_pairs = self._rpc_edge() - edge_pairs_tab = tabulate(edge_pairs, - headers=[ - 'Pair', - f'Winrate', - f'Expectancy', - f'Stoploss' - ], - tablefmt='simple') - + print(edge_pairs) + edge_pairs_tab = tabulate(edge_pairs, headers='keys', tablefmt='simple') message = f'Edge only validated following pairs:\n
{edge_pairs_tab}
' self._send_msg(message, bot=bot, parse_mode=ParseMode.HTML) except RPCException as e: @@ -520,6 +514,7 @@ class Telegram(RPC): "*/stopbuy:* `Stops buying, but handles open trades gracefully` \n" \ "*/reload_conf:* `Reload configuration file` \n" \ "*/whitelist:* `Show current whitelist` \n" \ + "*/edge:* `Shows validated pairs by Edge if it is enabeld` \n" \ "*/help:* `This help message`\n" \ "*/version:* `Show version`" From fd7278517dd7613c9ce7f0f4ba72b24ad4ed21c9 Mon Sep 17 00:00:00 2001 From: Misagh Date: Mon, 25 Mar 2019 09:48:41 +0100 Subject: [PATCH 25/51] using items() --- freqtrade/rpc/rpc.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index fb06c7d86..6416a97eb 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -468,10 +468,10 @@ class RPC(object): return [ { - 'Pair': pair, - 'Winrate': self._freqtrade.edge._cached_pairs[pair].winrate, - 'Expectancy': self._freqtrade.edge._cached_pairs[pair].expectancy, - 'Stoploss': self._freqtrade.edge._cached_pairs[pair].stoploss, + 'Pair': k, + 'Winrate': v.winrate, + 'Expectancy': v.expectancy, + 'Stoploss': v.stoploss, } - for pair in self._freqtrade.edge._cached_pairs + for k, v in self._freqtrade.edge._cached_pairs.items() ] From 66f1e0f4cd82597305bfa5ff74d8224973fd1338 Mon Sep 17 00:00:00 2001 From: Misagh Date: Mon, 25 Mar 2019 10:25:07 +0100 Subject: [PATCH 26/51] help added --- docs/telegram-usage.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/telegram-usage.md b/docs/telegram-usage.md index 2f7e9ada8..6788bec90 100644 --- a/docs/telegram-usage.md +++ b/docs/telegram-usage.md @@ -30,6 +30,7 @@ official commands. You can ask at any moment for help with `/help`. | `/daily ` | 7 | Shows profit or loss per day, over the last n days | `/whitelist` | | Show the current whitelist | `/blacklist [pair]` | | Show the current blacklist, or adds a pair to the blacklist. +| `/edge` | | Show validated pairs by Edge if it is enabled. | `/help` | | Show help message | `/version` | | Show version @@ -55,7 +56,7 @@ Prevents the bot from opening new trades by temporarily setting "max_open_trades After this, give the bot time to close off open trades (can be checked via `/status table`). Once all positions are sold, run `/stop` to completely stop the bot. -`/reload_conf` resets "max_open_trades" to the value set in the configuration and resets this command. +`/reload_conf` resets "max_open_trades" to the value set in the configuration and resets this command. !!! warning The stop-buy signal is ONLY active while the bot is running, and is not persisted anyway, so restarting the bot will cause this to reset. @@ -166,7 +167,7 @@ Day Profit BTC Profit USD Shows the current whitelist -> Using whitelist `StaticPairList` with 22 pairs +> Using whitelist `StaticPairList` with 22 pairs > `IOTA/BTC, NEO/BTC, TRX/BTC, VET/BTC, ADA/BTC, ETC/BTC, NCASH/BTC, DASH/BTC, XRP/BTC, XVG/BTC, EOS/BTC, LTC/BTC, OMG/BTC, BTG/BTC, LSK/BTC, ZEC/BTC, HOT/BTC, IOTX/BTC, XMR/BTC, AST/BTC, XLM/BTC, NANO/BTC` ### /blacklist [pair] @@ -176,7 +177,7 @@ If Pair is set, then this pair will be added to the pairlist. Also supports multiple pairs, seperated by a space. Use `/reload_conf` to reset the blacklist. -> Using blacklist `StaticPairList` with 2 pairs +> Using blacklist `StaticPairList` with 2 pairs >`DODGE/BTC`, `HOT/BTC`. ### /version From 904b3008a97eda34648809ef1906eca7d7887adf Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Mon, 25 Mar 2019 13:36:04 +0100 Subject: [PATCH 27/51] Update ccxt from 1.18.395 to 1.18.398 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 73c65aff6..feed42b52 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.18.395 +ccxt==1.18.398 SQLAlchemy==1.3.1 python-telegram-bot==11.1.0 arrow==0.13.1 From fe9322ecd53eea54ec7a97fbe31f82df4fc96a14 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Mon, 25 Mar 2019 13:36:06 +0100 Subject: [PATCH 28/51] Update pytest-mock from 1.10.1 to 1.10.2 --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index e0aaf9461..56d7964c3 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -5,7 +5,7 @@ flake8==3.7.7 flake8-type-annotations==0.1.0 flake8-tidy-imports==2.0.0 pytest==4.3.1 -pytest-mock==1.10.1 +pytest-mock==1.10.2 pytest-asyncio==0.10.0 pytest-cov==2.6.1 coveralls==1.7.0 From bd29b7d03136b3905152b079f872d030284e7a3c Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Mar 2019 15:21:05 +0100 Subject: [PATCH 29/51] Test that dataprovider is loaded to strategy --- freqtrade/tests/test_freqtradebot.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py index e4f0415f7..fa50b36e6 100644 --- a/freqtrade/tests/test_freqtradebot.py +++ b/freqtrade/tests/test_freqtradebot.py @@ -13,12 +13,14 @@ import requests from freqtrade import (DependencyException, OperationalException, TemporaryError, constants) +from freqtrade.data.dataprovider import DataProvider from freqtrade.freqtradebot import FreqtradeBot from freqtrade.persistence import Trade from freqtrade.rpc import RPCMessageType from freqtrade.state import State -from freqtrade.strategy.interface import SellType, SellCheckTuple -from freqtrade.tests.conftest import log_has, log_has_re, patch_exchange, patch_edge, patch_wallet +from freqtrade.strategy.interface import SellCheckTuple, SellType +from freqtrade.tests.conftest import (log_has, log_has_re, patch_edge, + patch_exchange, patch_wallet) # Functions for recurrent object patching @@ -88,6 +90,10 @@ def test_worker_running(mocker, default_conf, caplog) -> None: assert state is State.RUNNING assert log_has('Changing state to: RUNNING', caplog.record_tuples) assert mock_throttle.call_count == 1 + # Check strategy is loaded, and received a dataprovider object + assert freqtrade.strategy + assert freqtrade.strategy.dp + assert isinstance(freqtrade.strategy.dp, DataProvider) def test_worker_stopped(mocker, default_conf, caplog) -> None: From 226fc3d99b97b9a62a2c2a8246c60d8753c367e6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Mar 2019 15:23:14 +0100 Subject: [PATCH 30/51] Check that dataprovider is part of strategy --- freqtrade/tests/optimize/test_backtesting.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/freqtrade/tests/optimize/test_backtesting.py b/freqtrade/tests/optimize/test_backtesting.py index 40754cfbc..d0b21b8f4 100644 --- a/freqtrade/tests/optimize/test_backtesting.py +++ b/freqtrade/tests/optimize/test_backtesting.py @@ -16,6 +16,7 @@ from freqtrade.arguments import Arguments, TimeRange from freqtrade.data import history from freqtrade.data.btanalysis import evaluate_result_multi from freqtrade.data.converter import parse_ticker_dataframe +from freqtrade.data.dataprovider import DataProvider from freqtrade.optimize import get_timeframe from freqtrade.optimize.backtesting import (Backtesting, setup_configuration, start) @@ -346,6 +347,7 @@ def test_backtesting_init(mocker, default_conf, order_types) -> None: assert callable(backtesting.strategy.tickerdata_to_dataframe) assert callable(backtesting.advise_buy) assert callable(backtesting.advise_sell) + assert isinstance(backtesting.strategy.dp, DataProvider) get_fee.assert_called() assert backtesting.fee == 0.5 assert not backtesting.strategy.order_types["stoploss_on_exchange"] From 0ae81d41156f84828d9bab0ec22f0686fb4d75a2 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Mar 2019 15:24:47 +0100 Subject: [PATCH 31/51] Provide dataprovider access during backtesting --- freqtrade/optimize/backtesting.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 031b490c8..7c98bd3a7 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -18,6 +18,7 @@ from freqtrade import DependencyException, constants from freqtrade.arguments import Arguments from freqtrade.configuration import Configuration from freqtrade.data import history +from freqtrade.data.dataprovider import DataProvider from freqtrade.misc import file_dump_json from freqtrade.persistence import Trade from freqtrade.resolvers import ExchangeResolver, StrategyResolver @@ -64,6 +65,13 @@ class Backtesting(object): self.config['exchange']['uid'] = '' self.config['dry_run'] = True self.strategylist: List[IStrategy] = [] + + exchange_name = self.config.get('exchange', {}).get('name', 'bittrex').title() + self.exchange = ExchangeResolver(exchange_name, self.config).exchange + self.fee = self.exchange.get_fee() + self.dataprovider = DataProvider(self.config, self.exchange) + IStrategy.dp = self.dataprovider + if self.config.get('strategy_list', None): # Force one interval self.ticker_interval = str(self.config.get('ticker_interval')) @@ -78,15 +86,13 @@ class Backtesting(object): self.strategylist.append(StrategyResolver(self.config).strategy) # Load one strategy self._set_strategy(self.strategylist[0]) - exchange_name = self.config.get('exchange', {}).get('name', 'bittrex').title() - self.exchange = ExchangeResolver(exchange_name, self.config).exchange - self.fee = self.exchange.get_fee() def _set_strategy(self, strategy): """ Load strategy into backtesting """ self.strategy = strategy + self.ticker_interval = self.config.get('ticker_interval') self.ticker_interval_mins = constants.TICKER_INTERVAL_MINUTES[self.ticker_interval] self.tickerdata_to_dataframe = strategy.tickerdata_to_dataframe From 4cf7282027e56277f79a317a8d8a7aa3092f17be Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 25 Mar 2019 19:31:10 +0100 Subject: [PATCH 32/51] Update dataprovider docs --- docs/bot-optimization.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/bot-optimization.md b/docs/bot-optimization.md index c01a0a03d..ae6377bf5 100644 --- a/docs/bot-optimization.md +++ b/docs/bot-optimization.md @@ -260,12 +260,9 @@ class Awesomestrategy(IStrategy): The strategy provides access to the `DataProvider`. This allows you to get additional data to use in your strategy. -!!! Note - The DataProvier is currently not available during backtesting / hyperopt, but this is planned for the future. - All methods return `None` in case of failure (do not raise an exception). -Please always check if the `DataProvider` is available to avoid failures during backtesting. +Please always the mode of operation to select the correct method to get data (samples see below). #### Possible options for DataProvider @@ -292,6 +289,9 @@ if self.dp: Be carefull when using dataprovider in backtesting. `historic_ohlcv()` provides the full time-range in one go, so please be aware of it and make sure to not "look into the future" to avoid surprises when running in dry/live mode). +!!! Warning Warning in hyperopt + This option should only be used in `populate_indicators()` - since it pulls the historic data from disk each time, which would be a huge performance penalty during hyperopt. + #### Available Pairs ``` python From f26ed1c8c1503457293dbdae6f0fb53c8251a317 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 25 Mar 2019 19:40:21 +0100 Subject: [PATCH 33/51] Check if added pair has correct stake-currency --- freqtrade/rpc/rpc.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index cacca4e3c..a5601a502 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -464,10 +464,14 @@ class RPC(object): def _rpc_blacklist(self, add: List[str]) -> Dict: """ Returns the currently active blacklist""" if add: - self._freqtrade.pairlists.blacklist.extend(add) + stake_currency = self._freqtrade.config.get('stake_currency') + for pair in add: + if (pair.endswith(stake_currency) + and pair not in self._freqtrade.pairlists.blacklist): + self._freqtrade.pairlists.blacklist.append(pair) res = {'method': self._freqtrade.pairlists.name, 'length': len(self._freqtrade.pairlists.blacklist), - 'blacklist': self._freqtrade.pairlists.blacklist + 'blacklist': self._freqtrade.pairlists.blacklist, } return res From e085fd9e9538c18a6e4e6ea51c0dd151eb31c15e Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 25 Mar 2019 19:49:58 +0100 Subject: [PATCH 34/51] Disable dataprovider from hyperopt. Dataprovider uses weak links to initialize, which cannot be pickled, and therefore cannot be used during hyperopt. --- docs/bot-optimization.md | 2 +- freqtrade/optimize/backtesting.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/bot-optimization.md b/docs/bot-optimization.md index ae6377bf5..f018d92a7 100644 --- a/docs/bot-optimization.md +++ b/docs/bot-optimization.md @@ -290,7 +290,7 @@ if self.dp: so please be aware of it and make sure to not "look into the future" to avoid surprises when running in dry/live mode). !!! Warning Warning in hyperopt - This option should only be used in `populate_indicators()` - since it pulls the historic data from disk each time, which would be a huge performance penalty during hyperopt. + This option cannot currently be used during hyperopt. #### Available Pairs diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 7c98bd3a7..293511fc0 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -69,8 +69,10 @@ class Backtesting(object): exchange_name = self.config.get('exchange', {}).get('name', 'bittrex').title() self.exchange = ExchangeResolver(exchange_name, self.config).exchange self.fee = self.exchange.get_fee() - self.dataprovider = DataProvider(self.config, self.exchange) - IStrategy.dp = self.dataprovider + + if self.config.get('runmode') != RunMode.HYPEROPT: + self.dataprovider = DataProvider(self.config, self.exchange) + IStrategy.dp = self.dataprovider if self.config.get('strategy_list', None): # Force one interval From 85ac99aee021522e60f2b1823b2c6a2998d2a144 Mon Sep 17 00:00:00 2001 From: iuvbio Date: Thu, 21 Mar 2019 19:11:47 +0100 Subject: [PATCH 35/51] move exchange urls to constants --- freqtrade/constants.py | 6 ++++++ freqtrade/exchange/exchange.py | 7 ------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 02062acc4..bd021c327 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -22,6 +22,12 @@ ORDERTIF_POSSIBILITIES = ['gtc', 'fok', 'ioc'] AVAILABLE_PAIRLISTS = ['StaticPairList', 'VolumePairList'] DRY_RUN_WALLET = 999.9 +# Urls to exchange markets, insert quote and base with .format() +_EXCHANGE_URLS = { + "Bittrex": '/Market/Index?MarketName={quote}-{base}', + "Binance": '/tradeDetail.html?symbol={base}_{quote}', +} + TICKER_INTERVAL_MINUTES = { '1m': 1, '3m': 3, diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index ea8bcfac1..7781c85e4 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -21,13 +21,6 @@ logger = logging.getLogger(__name__) API_RETRY_COUNT = 4 -# Urls to exchange markets, insert quote and base with .format() -_EXCHANGE_URLS = { - ccxt.bittrex.__name__: '/Market/Index?MarketName={quote}-{base}', - ccxt.binance.__name__: '/tradeDetail.html?symbol={base}_{quote}', -} - - def retrier_async(f): async def wrapper(*args, **kwargs): count = kwargs.pop('count', API_RETRY_COUNT) From 4005b8d1d254f94840cc00034521e2c7421c17a5 Mon Sep 17 00:00:00 2001 From: iuvbio Date: Thu, 21 Mar 2019 19:12:15 +0100 Subject: [PATCH 36/51] remove the if condition for binance --- freqtrade/exchange/binance.py | 6 ++++++ freqtrade/exchange/exchange.py | 7 +++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/freqtrade/exchange/binance.py b/freqtrade/exchange/binance.py index 127f4e916..1d633be2b 100644 --- a/freqtrade/exchange/binance.py +++ b/freqtrade/exchange/binance.py @@ -24,3 +24,9 @@ class Binance(Exchange): limit = min(list(filter(lambda x: limit <= x, limit_range))) return super().get_order_book(pair, limit) + + def validate_order_time_in_force(self, order_time_in_force: Dict) -> None: + """ + Checks if order time in force configured in strategy/config are supported + """ + pass diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 7781c85e4..d422e2bbf 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -13,7 +13,7 @@ import ccxt import ccxt.async_support as ccxt_async from pandas import DataFrame -from freqtrade import constants, OperationalException, DependencyException, TemporaryError +from freqtrade import constants, DependencyException, OperationalException, TemporaryError from freqtrade.data.converter import parse_ticker_dataframe logger = logging.getLogger(__name__) @@ -269,9 +269,8 @@ class Exchange(object): Checks if order time in force configured in strategy/config are supported """ if any(v != 'gtc' for k, v in order_time_in_force.items()): - if self.name != 'Binance': - raise OperationalException( - f'Time in force policies are not supporetd for {self.name} yet.') + raise OperationalException( + f'Time in force policies are not supporetd for {self.name} yet.') def exchange_has(self, endpoint: str) -> bool: """ From 8dea640e9a671b315675f27557361e46e5eee084 Mon Sep 17 00:00:00 2001 From: iuvbio Date: Mon, 25 Mar 2019 23:58:02 +0100 Subject: [PATCH 37/51] remove exchange urls --- freqtrade/constants.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index bd021c327..02062acc4 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -22,12 +22,6 @@ ORDERTIF_POSSIBILITIES = ['gtc', 'fok', 'ioc'] AVAILABLE_PAIRLISTS = ['StaticPairList', 'VolumePairList'] DRY_RUN_WALLET = 999.9 -# Urls to exchange markets, insert quote and base with .format() -_EXCHANGE_URLS = { - "Bittrex": '/Market/Index?MarketName={quote}-{base}', - "Binance": '/tradeDetail.html?symbol={base}_{quote}', -} - TICKER_INTERVAL_MINUTES = { '1m': 1, '3m': 3, From e15f2ef11ad07c4f71e5086d0edaad1c22c80e11 Mon Sep 17 00:00:00 2001 From: iuvbio Date: Tue, 26 Mar 2019 00:49:39 +0100 Subject: [PATCH 38/51] add order_time_in_force in _ft_has and revert binance --- freqtrade/exchange/binance.py | 7 +------ freqtrade/exchange/exchange.py | 6 ++++-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/freqtrade/exchange/binance.py b/freqtrade/exchange/binance.py index 1d633be2b..18e754e3f 100644 --- a/freqtrade/exchange/binance.py +++ b/freqtrade/exchange/binance.py @@ -11,6 +11,7 @@ class Binance(Exchange): _ft_has: Dict = { "stoploss_on_exchange": True, + "order_time_in_force": ['gtc', 'fok', 'ioc'], } def get_order_book(self, pair: str, limit: int = 100) -> dict: @@ -24,9 +25,3 @@ class Binance(Exchange): limit = min(list(filter(lambda x: limit <= x, limit_range))) return super().get_order_book(pair, limit) - - def validate_order_time_in_force(self, order_time_in_force: Dict) -> None: - """ - Checks if order time in force configured in strategy/config are supported - """ - pass diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index d422e2bbf..2ec5c0e25 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -65,8 +65,9 @@ class Exchange(object): # Dict to specify which options each exchange implements # TODO: this should be merged with attributes from subclasses # To avoid having to copy/paste this to all subclasses. - _ft_has = { + _ft_has: Dict = { "stoploss_on_exchange": False, + "order_time_in_force": ["gtc"], } def __init__(self, config: dict) -> None: @@ -268,7 +269,8 @@ class Exchange(object): """ Checks if order time in force configured in strategy/config are supported """ - if any(v != 'gtc' for k, v in order_time_in_force.items()): + if any(v not in self._ft_has["order_time_in_force"] + for k, v in order_time_in_force.items()): raise OperationalException( f'Time in force policies are not supporetd for {self.name} yet.') From 1f50bc79bc0ee098f6974ab40c7bfd530ceca914 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Tue, 26 Mar 2019 13:37:03 +0100 Subject: [PATCH 39/51] Update ccxt from 1.18.398 to 1.18.400 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index feed42b52..345d32c0d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.18.398 +ccxt==1.18.400 SQLAlchemy==1.3.1 python-telegram-bot==11.1.0 arrow==0.13.1 From 3bdc7b9a8880a23cf9ae0925a0194f373e027c27 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 27 Mar 2019 10:51:13 +0100 Subject: [PATCH 40/51] add missed "check" in docs --- docs/bot-optimization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/bot-optimization.md b/docs/bot-optimization.md index f018d92a7..9e754c213 100644 --- a/docs/bot-optimization.md +++ b/docs/bot-optimization.md @@ -262,7 +262,7 @@ The strategy provides access to the `DataProvider`. This allows you to get addit All methods return `None` in case of failure (do not raise an exception). -Please always the mode of operation to select the correct method to get data (samples see below). +Please always check the mode of operation to select the correct method to get data (samples see below). #### Possible options for DataProvider From 4e57969e4e2d3e1d49967f46844e744f2f6e2b8d Mon Sep 17 00:00:00 2001 From: Misagh Date: Wed, 27 Mar 2019 12:54:00 +0100 Subject: [PATCH 41/51] documentation added --- docs/telegram-usage.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/telegram-usage.md b/docs/telegram-usage.md index 6788bec90..fa10969db 100644 --- a/docs/telegram-usage.md +++ b/docs/telegram-usage.md @@ -180,6 +180,21 @@ Use `/reload_conf` to reset the blacklist. > Using blacklist `StaticPairList` with 2 pairs >`DODGE/BTC`, `HOT/BTC`. +### /edge + +Shows pairs accepted by pais along with their corresponding winrate, expectancy and stoploss values. + +> **Edge only validated following pairs:** +``` +Pair Winrate Expectancy Stoploss +-------- --------- ------------ ---------- +DOCK/ETH 0.522727 0.881821 -0.03 +PHX/ETH 0.677419 0.560488 -0.03 +HOT/ETH 0.733333 0.490492 -0.03 +HC/ETH 0.588235 0.280988 -0.02 +ARDR/ETH 0.366667 0.143059 -0.01 +``` + ### /version > **Version:** `0.14.3` From 955e2d28262fd8572cd8983196a0a0bcbdd099f6 Mon Sep 17 00:00:00 2001 From: Misagh Date: Wed, 27 Mar 2019 12:59:59 +0100 Subject: [PATCH 42/51] Update test_rpc_telegram.py telegram test_init fixed --- freqtrade/tests/rpc/test_rpc_telegram.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/tests/rpc/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py index dd49b0000..24e99b1c5 100644 --- a/freqtrade/tests/rpc/test_rpc_telegram.py +++ b/freqtrade/tests/rpc/test_rpc_telegram.py @@ -74,7 +74,7 @@ def test_init(default_conf, mocker, caplog) -> None: message_str = "rpc.telegram is listening for following commands: [['status'], ['profit'], " \ "['balance'], ['start'], ['stop'], ['forcesell'], ['forcebuy'], " \ "['performance'], ['daily'], ['count'], ['reload_conf'], " \ - "['stopbuy'], ['whitelist'], ['blacklist'], ['help'], ['version']]" + "['stopbuy'], ['whitelist'], ['blacklist'], ['edge'], ['help'], ['version']]" assert log_has(message_str, caplog.record_tuples) From cc32566c92f046dfe943e80dcd36fdcdcffa2e6d Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Wed, 27 Mar 2019 12:38:05 +0000 Subject: [PATCH 43/51] Update ccxt from 1.18.400 to 1.18.406 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 345d32c0d..2bf329bd8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.18.400 +ccxt==1.18.406 SQLAlchemy==1.3.1 python-telegram-bot==11.1.0 arrow==0.13.1 From 8641da13b908747d49b0b5f39610e8cd104ecdfd Mon Sep 17 00:00:00 2001 From: Misagh Date: Wed, 27 Mar 2019 14:02:37 +0100 Subject: [PATCH 44/51] added RPC tests in case of edge enabled/disabled --- freqtrade/tests/rpc/test_rpc.py | 36 ++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/freqtrade/tests/rpc/test_rpc.py b/freqtrade/tests/rpc/test_rpc.py index e6f7ea41e..a5ee4a26c 100644 --- a/freqtrade/tests/rpc/test_rpc.py +++ b/freqtrade/tests/rpc/test_rpc.py @@ -2,19 +2,20 @@ # pragma pylint: disable=invalid-sequence-index, invalid-name, too-many-arguments from datetime import datetime -from unittest.mock import MagicMock, ANY, PropertyMock +from unittest.mock import ANY, MagicMock, PropertyMock import pytest from numpy import isnan -from freqtrade import TemporaryError, DependencyException +from freqtrade import DependencyException, TemporaryError +from freqtrade.edge import PairInfo from freqtrade.freqtradebot import FreqtradeBot from freqtrade.persistence import Trade from freqtrade.rpc import RPC, RPCException from freqtrade.rpc.fiat_convert import CryptoToFiatConverter from freqtrade.state import State -from freqtrade.tests.test_freqtradebot import patch_get_signal from freqtrade.tests.conftest import patch_coinmarketcap, patch_exchange +from freqtrade.tests.test_freqtradebot import patch_get_signal # Functions for recurrent object patching @@ -713,3 +714,32 @@ def test_rpc_blacklist(mocker, default_conf) -> None: assert len(ret['blacklist']) == 3 assert ret['blacklist'] == default_conf['exchange']['pair_blacklist'] assert ret['blacklist'] == ['DOGE/BTC', 'HOT/BTC', 'ETH/BTC'] + +def test_rpc_edge_disabled(mocker, default_conf) -> None: + patch_coinmarketcap(mocker) + patch_exchange(mocker) + mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) + freqtradebot = FreqtradeBot(default_conf) + rpc = RPC(freqtradebot) + with pytest.raises(RPCException, match=r'Edge is not enabled.'): + ret = rpc._rpc_edge() + +def test_rpc_edge_enabled(mocker, edge_conf) -> None: + patch_coinmarketcap(mocker) + patch_exchange(mocker) + mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) + mocker.patch('freqtrade.edge.Edge._cached_pairs', mocker.PropertyMock( + return_value={ + 'E/F': PairInfo(-0.02, 0.66, 3.71, 0.50, 1.71, 10, 60), + } + )) + freqtradebot = FreqtradeBot(edge_conf) + + rpc = RPC(freqtradebot) + ret = rpc._rpc_edge() + + assert len(ret) == 1 + assert ret[0]['Pair'] == 'E/F' + assert ret[0]['Winrate'] == 0.66 + assert ret[0]['Expectancy'] == 1.71 + assert ret[0]['Stoploss'] == -0.02 \ No newline at end of file From 0687051ffbd86b821cfdccb228680f6d51df1bd7 Mon Sep 17 00:00:00 2001 From: Misagh Date: Wed, 27 Mar 2019 14:04:33 +0100 Subject: [PATCH 45/51] Update test_rpc.py flake8 --- freqtrade/tests/rpc/test_rpc.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/freqtrade/tests/rpc/test_rpc.py b/freqtrade/tests/rpc/test_rpc.py index a5ee4a26c..8e8e7fc50 100644 --- a/freqtrade/tests/rpc/test_rpc.py +++ b/freqtrade/tests/rpc/test_rpc.py @@ -715,6 +715,7 @@ def test_rpc_blacklist(mocker, default_conf) -> None: assert ret['blacklist'] == default_conf['exchange']['pair_blacklist'] assert ret['blacklist'] == ['DOGE/BTC', 'HOT/BTC', 'ETH/BTC'] + def test_rpc_edge_disabled(mocker, default_conf) -> None: patch_coinmarketcap(mocker) patch_exchange(mocker) @@ -722,7 +723,8 @@ def test_rpc_edge_disabled(mocker, default_conf) -> None: freqtradebot = FreqtradeBot(default_conf) rpc = RPC(freqtradebot) with pytest.raises(RPCException, match=r'Edge is not enabled.'): - ret = rpc._rpc_edge() + rpc._rpc_edge() + def test_rpc_edge_enabled(mocker, edge_conf) -> None: patch_coinmarketcap(mocker) @@ -742,4 +744,4 @@ def test_rpc_edge_enabled(mocker, edge_conf) -> None: assert ret[0]['Pair'] == 'E/F' assert ret[0]['Winrate'] == 0.66 assert ret[0]['Expectancy'] == 1.71 - assert ret[0]['Stoploss'] == -0.02 \ No newline at end of file + assert ret[0]['Stoploss'] == -0.02 From 4038cdf70a25deae3ab1f50399dbd7cbd94d34ce Mon Sep 17 00:00:00 2001 From: Misagh Date: Wed, 27 Mar 2019 16:04:05 +0100 Subject: [PATCH 46/51] "Edge" test for rpc telegram --- freqtrade/tests/rpc/test_rpc_telegram.py | 47 ++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/freqtrade/tests/rpc/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py index 24e99b1c5..8118266cc 100644 --- a/freqtrade/tests/rpc/test_rpc_telegram.py +++ b/freqtrade/tests/rpc/test_rpc_telegram.py @@ -13,16 +13,16 @@ from telegram import Chat, Message, Update from telegram.error import NetworkError from freqtrade import __version__ +from freqtrade.edge import PairInfo from freqtrade.freqtradebot import FreqtradeBot from freqtrade.persistence import Trade from freqtrade.rpc import RPCMessageType from freqtrade.rpc.telegram import Telegram, authorized_only -from freqtrade.strategy.interface import SellType from freqtrade.state import State +from freqtrade.strategy.interface import SellType from freqtrade.tests.conftest import (get_patched_freqtradebot, log_has, - patch_exchange) + patch_coinmarketcap, patch_exchange) from freqtrade.tests.test_freqtradebot import patch_get_signal -from freqtrade.tests.conftest import patch_coinmarketcap class DummyCls(Telegram): @@ -1099,6 +1099,47 @@ def test_blacklist_static(default_conf, update, mocker) -> None: assert freqtradebot.pairlists.blacklist == ["DOGE/BTC", "HOT/BTC", "ETH/BTC"] +def test_edge_disabled(default_conf, update, mocker) -> None: + patch_coinmarketcap(mocker) + msg_mock = MagicMock() + mocker.patch.multiple( + 'freqtrade.rpc.telegram.Telegram', + _init=MagicMock(), + _send_msg=msg_mock + ) + + freqtradebot = get_patched_freqtradebot(mocker, default_conf) + + telegram = Telegram(freqtradebot) + + telegram._edge(bot=MagicMock(), update=update) + assert msg_mock.call_count == 1 + assert "Edge is not enabled." in msg_mock.call_args_list[0][0][0] + + +def test_edge_enabled(edge_conf, update, mocker) -> None: + patch_coinmarketcap(mocker) + msg_mock = MagicMock() + mocker.patch('freqtrade.edge.Edge._cached_pairs', mocker.PropertyMock( + return_value={ + 'E/F': PairInfo(-0.01, 0.66, 3.71, 0.50, 1.71, 10, 60), + } + )) + mocker.patch.multiple( + 'freqtrade.rpc.telegram.Telegram', + _init=MagicMock(), + _send_msg=msg_mock + ) + + freqtradebot = get_patched_freqtradebot(mocker, edge_conf) + + telegram = Telegram(freqtradebot) + + telegram._edge(bot=MagicMock(), update=update) + assert msg_mock.call_count == 1 + assert 'Edge only validated following pairs:\n
' in msg_mock.call_args_list[0][0][0]
+    assert 'Pair      Winrate    Expectancy    Stoploss' in msg_mock.call_args_list[0][0][0]
+
 def test_help_handle(default_conf, update, mocker) -> None:
     patch_coinmarketcap(mocker)
     msg_mock = MagicMock()

From 1e37d8ccb3266be217847865e4fa9154d3d83583 Mon Sep 17 00:00:00 2001
From: Misagh 
Date: Wed, 27 Mar 2019 16:58:53 +0100
Subject: [PATCH 47/51] flake8

---
 freqtrade/tests/rpc/test_rpc_telegram.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/freqtrade/tests/rpc/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py
index 8118266cc..c6a5fff54 100644
--- a/freqtrade/tests/rpc/test_rpc_telegram.py
+++ b/freqtrade/tests/rpc/test_rpc_telegram.py
@@ -1140,6 +1140,7 @@ def test_edge_enabled(edge_conf, update, mocker) -> None:
     assert 'Edge only validated following pairs:\n
' in msg_mock.call_args_list[0][0][0]
     assert 'Pair      Winrate    Expectancy    Stoploss' in msg_mock.call_args_list[0][0][0]
 
+
 def test_help_handle(default_conf, update, mocker) -> None:
     patch_coinmarketcap(mocker)
     msg_mock = MagicMock()

From 753b03d581d2f435f70c44ca96fcbcd4589a45a7 Mon Sep 17 00:00:00 2001
From: Misagh 
Date: Wed, 27 Mar 2019 18:19:42 +0100
Subject: [PATCH 48/51] rolback on removing MD whitespaces

---
 docs/telegram-usage.md | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/docs/telegram-usage.md b/docs/telegram-usage.md
index fa10969db..d68183537 100644
--- a/docs/telegram-usage.md
+++ b/docs/telegram-usage.md
@@ -56,7 +56,7 @@ Prevents the bot from opening new trades by temporarily setting "max_open_trades
 After this, give the bot time to close off open trades (can be checked via `/status table`).
 Once all positions are sold, run `/stop` to completely stop the bot.
 
-`/reload_conf` resets "max_open_trades" to the value set in the configuration and resets this command.
+`/reload_conf` resets "max_open_trades" to the value set in the configuration and resets this command. 
 
 !!! warning
    The stop-buy signal is ONLY active while the bot is running, and is not persisted anyway, so restarting the bot will cause this to reset.
@@ -167,7 +167,7 @@ Day         Profit BTC      Profit USD
 
 Shows the current whitelist
 
-> Using whitelist `StaticPairList` with 22 pairs
+> Using whitelist `StaticPairList` with 22 pairs  
 > `IOTA/BTC, NEO/BTC, TRX/BTC, VET/BTC, ADA/BTC, ETC/BTC, NCASH/BTC, DASH/BTC, XRP/BTC, XVG/BTC, EOS/BTC, LTC/BTC, OMG/BTC, BTG/BTC, LSK/BTC, ZEC/BTC, HOT/BTC, IOTX/BTC, XMR/BTC, AST/BTC, XLM/BTC, NANO/BTC`
 
 ### /blacklist [pair]
@@ -177,7 +177,7 @@ If Pair is set, then this pair will be added to the pairlist.
 Also supports multiple pairs, seperated by a space.
 Use `/reload_conf` to reset the blacklist.
 
-> Using blacklist `StaticPairList` with 2 pairs
+> Using blacklist `StaticPairList` with 2 pairs  
 >`DODGE/BTC`, `HOT/BTC`.
 
 ### /edge

From 9b22d5cab135d743d7c5b3841427a24636de11ee Mon Sep 17 00:00:00 2001
From: Matthias 
Date: Wed, 27 Mar 2019 20:51:55 +0100
Subject: [PATCH 49/51] Fix typo, add test for validate_order_tif

---
 freqtrade/exchange/exchange.py            |  2 +-
 freqtrade/tests/exchange/test_exchange.py | 22 ++++++++++++++++++++++
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py
index 2ec5c0e25..011be58e5 100644
--- a/freqtrade/exchange/exchange.py
+++ b/freqtrade/exchange/exchange.py
@@ -272,7 +272,7 @@ class Exchange(object):
         if any(v not in self._ft_has["order_time_in_force"]
                for k, v in order_time_in_force.items()):
             raise OperationalException(
-                f'Time in force policies are not supporetd for  {self.name} yet.')
+                f'Time in force policies are not supported for {self.name} yet.')
 
     def exchange_has(self, endpoint: str) -> bool:
         """
diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py
index 736f2298a..eed16d39b 100644
--- a/freqtrade/tests/exchange/test_exchange.py
+++ b/freqtrade/tests/exchange/test_exchange.py
@@ -139,6 +139,28 @@ def test_exchange_resolver(default_conf, mocker, caplog):
                           caplog.record_tuples)
 
 
+def test_validate_order_time_in_force(default_conf, mocker, caplog):
+    caplog.set_level(logging.INFO)
+    # explicitly test bittrex, exchanges implementing other policies need seperate tests
+    ex = get_patched_exchange(mocker, default_conf, id="bittrex")
+    tif = {
+        "buy": "gtc",
+        "sell": "gtc",
+    }
+
+    ex.validate_order_time_in_force(tif)
+    tif2 = {
+        "buy": "fok",
+        "sell": "ioc",
+    }
+    with pytest.raises(OperationalException, match=r"Time in force.*not supported for .*"):
+        ex.validate_order_time_in_force(tif2)
+
+    # Patch to see if this will pass if the values are in the ft dict
+    ex._ft_has.update({"order_time_in_force": ["gtc", "fok", "ioc"]})
+    ex.validate_order_time_in_force(tif2)
+
+
 def test_symbol_amount_prec(default_conf, mocker):
     '''
     Test rounds down to 4 Decimal places

From 4d9ca71c82c08270d8fcb8c102c1c52670c60f9e Mon Sep 17 00:00:00 2001
From: Misagh 
Date: Wed, 27 Mar 2019 21:20:09 +0100
Subject: [PATCH 50/51] shifting edge help message a line lower

---
 freqtrade/rpc/telegram.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py
index 553f1a1fb..919c45757 100644
--- a/freqtrade/rpc/telegram.py
+++ b/freqtrade/rpc/telegram.py
@@ -533,8 +533,8 @@ class Telegram(RPC):
                   "*/reload_conf:* `Reload configuration file` \n" \
                   "*/whitelist:* `Show current whitelist` \n" \
                   "*/blacklist [pair]:* `Show current blacklist, or adds one or more pairs " \
-                  "*/edge:* `Shows validated pairs by Edge if it is enabeld` \n" \
                   "to the blacklist.` \n" \
+                  "*/edge:* `Shows validated pairs by Edge if it is enabeld` \n" \
                   "*/help:* `This help message`\n" \
                   "*/version:* `Show version`"
 

From e5406ed3cfe41d75a8381ab5112c80451023bf03 Mon Sep 17 00:00:00 2001
From: Misagh 
Date: Wed, 27 Mar 2019 21:22:25 +0100
Subject: [PATCH 51/51] typo in docs and comments

---
 docs/telegram-usage.md    | 2 +-
 freqtrade/rpc/telegram.py | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/docs/telegram-usage.md b/docs/telegram-usage.md
index d68183537..1ca61e54a 100644
--- a/docs/telegram-usage.md
+++ b/docs/telegram-usage.md
@@ -182,7 +182,7 @@ Use `/reload_conf` to reset the blacklist.
 
 ### /edge
 
-Shows pairs accepted by pais along with their corresponding winrate, expectancy and stoploss values.
+Shows pairs validated by Edge along with their corresponding winrate, expectancy and stoploss values.
 
 > **Edge only validated following pairs:**
 ```
diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py
index 919c45757..06bf5efe9 100644
--- a/freqtrade/rpc/telegram.py
+++ b/freqtrade/rpc/telegram.py
@@ -494,7 +494,7 @@ class Telegram(RPC):
     def _edge(self, bot: Bot, update: Update) -> None:
         """
         Handler for /edge
-        Shows informaton related to Edge
+        Shows information related to Edge
         """
         try:
             edge_pairs = self._rpc_edge()