diff --git a/.coveragerc b/.coveragerc index 95eea4f8f..4bd5b63fa 100644 --- a/.coveragerc +++ b/.coveragerc @@ -2,4 +2,5 @@ omit = scripts/* freqtrade/tests/* - freqtrade/vendor/* \ No newline at end of file + freqtrade/vendor/* + freqtrade/__main__.py diff --git a/docs/backtesting.md b/docs/backtesting.md index 8364d77e4..1efb46b43 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -1,17 +1,19 @@ # Backtesting + This page explains how to validate your strategy performance by using Backtesting. ## Table of Contents + - [Test your strategy with Backtesting](#test-your-strategy-with-backtesting) - [Understand the backtesting result](#understand-the-backtesting-result) ## Test your strategy with Backtesting + Now you have good Buy and Sell strategies, you want to test it against real data. This is what we call [backtesting](https://en.wikipedia.org/wiki/Backtesting). - Backtesting will use the crypto-currencies (pair) from your config file and load static tickers located in [/freqtrade/tests/testdata](https://github.com/freqtrade/freqtrade/tree/develop/freqtrade/tests/testdata). @@ -19,70 +21,80 @@ If the 5 min and 1 min ticker for the crypto-currencies to test is not already in the `testdata` folder, backtesting will download them automatically. Testdata files will not be updated until you specify it. -The result of backtesting will confirm you if your bot as more chance to -make a profit than a loss. - +The result of backtesting will confirm you if your bot has better odds of making a profit than a loss. The backtesting is very easy with freqtrade. ### Run a backtesting against the currencies listed in your config file -**With 5 min tickers (Per default)** +#### With 5 min tickers (Per default) + ```bash python3 ./freqtrade/main.py backtesting --realistic-simulation ``` -**With 1 min tickers** +#### With 1 min tickers + ```bash python3 ./freqtrade/main.py backtesting --realistic-simulation --ticker-interval 1m ``` -**Update cached pairs with the latest data** +#### Update cached pairs with the latest data + ```bash python3 ./freqtrade/main.py backtesting --realistic-simulation --refresh-pairs-cached ``` -**With live data (do not alter your testdata files)** +#### With live data (do not alter your testdata files) + ```bash python3 ./freqtrade/main.py backtesting --realistic-simulation --live ``` -**Using a different on-disk ticker-data source** +#### Using a different on-disk ticker-data source + ```bash python3 ./freqtrade/main.py backtesting --datadir freqtrade/tests/testdata-20180101 ``` -**With a (custom) strategy file** +#### With a (custom) strategy file + ```bash python3 ./freqtrade/main.py -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 -**Exporting trades to file** +#### Exporting trades to file + ```bash python3 ./freqtrade/main.py backtesting --export trades ``` -**Exporting trades to file specifying a custom filename** +#### Exporting trades to file specifying a custom filename + ```bash python3 ./freqtrade/main.py backtesting --export trades --export-filename=backtest_teststrategy.json ``` +#### Running backtest with smaller testset -**Running backtest with smaller testset** Use the `--timerange` argument to change how much of the testset you want to use. The last N ticks/timeframes will be used. Example: + ```bash python3 ./freqtrade/main.py backtesting --timerange=-200 ``` -***Advanced use of timerange*** +#### Advanced use of timerange + 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. The full timerange specification: + - Use last 123 tickframes of data: `--timerange=-123` - Use first 123 tickframes of data: `--timerange=123-` - Use tickframes from line 123 through 456: `--timerange=123-456` @@ -92,11 +104,12 @@ The full timerange specification: - Use tickframes between POSIX timestamps 1527595200 1527618600: `--timerange=1527595200-1527618600` +#### Downloading new set of ticker data -**Downloading new set of ticker data** To download new set of backtesting ticker data, you can use a download script. If you are using Binance for example: + - create a folder `user_data/data/binance` and copy `pairs.json` in that folder. - update the `pairs.json` to contain the currency pairs you are interested in. @@ -119,33 +132,55 @@ This will download ticker data for all the currency pairs you defined in `pairs. - To download ticker data for only 10 days, use `--days 10`. - Use `--timeframes` to specify which tickers to download. Default is `--timeframes 1m 5m` which will download 1-minute and 5-minute tickers. - -For help about backtesting usage, please refer to -[Backtesting commands](#backtesting-commands). +For help about backtesting usage, please refer to [Backtesting commands](#backtesting-commands). ## Understand the backtesting result + The most important in the backtesting is to understand the result. A backtesting result will look like that: + ``` -====================== BACKTESTING REPORT ================================ -pair buy count avg profit % total profit BTC avg duration --------- ----------- -------------- ------------------ -------------- -ETH/BTC 56 -0.67 -0.00075455 62.3 -LTC/BTC 38 -0.48 -0.00036315 57.9 -ETC/BTC 42 -1.15 -0.00096469 67.0 -DASH/BTC 72 -0.62 -0.00089368 39.9 -ZEC/BTC 45 -0.46 -0.00041387 63.2 -XLM/BTC 24 -0.88 -0.00041846 47.7 -NXT/BTC 24 0.68 0.00031833 40.2 -POWR/BTC 35 0.98 0.00064887 45.3 -ADA/BTC 43 -0.39 -0.00032292 55.0 -XMR/BTC 40 -0.40 -0.00032181 47.4 -TOTAL 419 -0.41 -0.00348593 52.9 +======================================== BACKTESTING REPORT ========================================= +| pair | buy count | avg profit % | total profit BTC | avg duration | profit | loss | +|:---------|------------:|---------------:|-------------------:|---------------:|---------:|-------:| +| ETH/BTC | 44 | 0.18 | 0.00159118 | 50.9 | 44 | 0 | +| LTC/BTC | 27 | 0.10 | 0.00051931 | 103.1 | 26 | 1 | +| ETC/BTC | 24 | 0.05 | 0.00022434 | 166.0 | 22 | 2 | +| DASH/BTC | 29 | 0.18 | 0.00103223 | 192.2 | 29 | 0 | +| ZEC/BTC | 65 | -0.02 | -0.00020621 | 202.7 | 62 | 3 | +| XLM/BTC | 35 | 0.02 | 0.00012877 | 242.4 | 32 | 3 | +| BCH/BTC | 12 | 0.62 | 0.00149284 | 50.0 | 12 | 0 | +| POWR/BTC | 21 | 0.26 | 0.00108215 | 134.8 | 21 | 0 | +| ADA/BTC | 54 | -0.19 | -0.00205202 | 191.3 | 47 | 7 | +| XMR/BTC | 24 | -0.43 | -0.00206013 | 120.6 | 20 | 4 | +| TOTAL | 335 | 0.03 | 0.00175246 | 157.9 | 315 | 20 | +2018-06-13 06:57:27,347 - freqtrade.optimize.backtesting - INFO - +====================================== LEFT OPEN TRADES REPORT ====================================== +| pair | buy count | avg profit % | total profit BTC | avg duration | profit | loss | +|:---------|------------:|---------------:|-------------------:|---------------:|---------:|-------:| +| ETH/BTC | 3 | 0.16 | 0.00009619 | 25.0 | 3 | 0 | +| LTC/BTC | 1 | -1.00 | -0.00020118 | 1085.0 | 0 | 1 | +| ETC/BTC | 2 | -1.80 | -0.00071933 | 1092.5 | 0 | 2 | +| DASH/BTC | 0 | nan | 0.00000000 | nan | 0 | 0 | +| ZEC/BTC | 3 | -4.27 | -0.00256826 | 1301.7 | 0 | 3 | +| XLM/BTC | 3 | -1.11 | -0.00066744 | 965.0 | 0 | 3 | +| BCH/BTC | 0 | nan | 0.00000000 | nan | 0 | 0 | +| POWR/BTC | 0 | nan | 0.00000000 | nan | 0 | 0 | +| ADA/BTC | 7 | -3.58 | -0.00503604 | 850.0 | 0 | 7 | +| XMR/BTC | 4 | -3.79 | -0.00303456 | 291.2 | 0 | 4 | +| TOTAL | 23 | -2.63 | -0.01213062 | 750.4 | 3 | 20 | + ``` +The 1st table will contain all trades the bot made. + +The 2nd table will contain all trades the bot had to `forcesell` at the end of the backtest period to prsent a full picture. +These trades are also included in the first table, but are extracted separately for clarity. + The last line will give you the overall performance of your strategy, here: + ``` TOTAL 419 -0.41 -0.00348593 52.9 ``` @@ -161,6 +196,7 @@ strategy, your sell strategy, and also by the `minimal_roi` and As for an example if your minimal_roi is only `"0": 0.01`. You cannot expect the bot to make more profit than 1% (because it will sell every time a trade will reach 1%). + ```json "minimal_roi": { "0": 0.01 @@ -173,6 +209,7 @@ profit. Hence, keep in mind that your performance is a mix of your strategies, your configuration, and the crypto-currency you have set up. ## Next step + Great, your strategy is profitable. What if the bot can give your the optimal parameters to use for your strategy? Your next step is to learn [how to find optimal parameters with Hyperopt](https://github.com/freqtrade/freqtrade/blob/develop/docs/hyperopt.md) diff --git a/docs/bot-usage.md b/docs/bot-usage.md index 8079d9816..25fc78f0a 100644 --- a/docs/bot-usage.md +++ b/docs/bot-usage.md @@ -160,13 +160,12 @@ the parameter `-l` or `--live`. ## Hyperopt commands -It is possible to use hyperopt for trading strategy optimization. -Hyperopt uses an internal json config return by `hyperopt_optimize_conf()` -located in `freqtrade/optimize/hyperopt_conf.py`. +To optimize your strategy, you can use hyperopt parameter hyperoptimization +to find optimal parameter values for your stategy. ``` usage: main.py hyperopt [-h] [-i TICKER_INTERVAL] [--realistic-simulation] - [--timerange TIMERANGE] [-e INT] [--use-mongodb] + [--timerange TIMERANGE] [-e INT] [-s {all,buy,roi,stoploss} [{all,buy,roi,stoploss} ...]] optional arguments: @@ -176,11 +175,8 @@ optional arguments: --realistic-simulation uses max_open_trades from config to simulate real world limitations - --timerange TIMERANGE - specify what timerange of data to use. + --timerange TIMERANGE specify what timerange of data to use. -e INT, --epochs INT specify number of epochs (default: 100) - --use-mongodb parallelize evaluations with mongodb (requires mongod - in PATH) -s {all,buy,roi,stoploss} [{all,buy,roi,stoploss} ...], --spaces {all,buy,roi,stoploss} [{all,buy,roi,stoploss} ...] Specify which parameters to hyperopt. Space separate list. Default: all diff --git a/docs/hyperopt.md b/docs/hyperopt.md index a079e34df..2ad94896a 100644 --- a/docs/hyperopt.md +++ b/docs/hyperopt.md @@ -9,7 +9,6 @@ parameters with Hyperopt. - [Advanced Hyperopt notions](#advanced-notions) - [Understand the Guards and Triggers](#understand-the-guards-and-triggers) - [Execute Hyperopt](#execute-hyperopt) - - [Hyperopt with MongoDB](#hyperopt-with-mongoDB) - [Understand the hyperopts result](#understand-the-backtesting-result) ## Prepare Hyperopt @@ -194,41 +193,6 @@ Legal values are: - `stoploss`: search for the best stoploss value - space-separated list of any of the above values for example `--spaces roi stoploss` -### Hyperopt with MongoDB -Hyperopt with MongoDB, is like Hyperopt under steroids. As you saw by -executing the previous command is the execution takes a long time. -To accelerate it you can use hyperopt with MongoDB. - -To run hyperopt with MongoDb you will need 3 terminals. - -**Terminal 1: Start MongoDB** -```bash -cd -source .env/bin/activate -python3 scripts/start-mongodb.py -``` - -**Terminal 2: Start Hyperopt worker** -```bash -cd -source .env/bin/activate -python3 scripts/start-hyperopt-worker.py -``` - -**Terminal 3: Start Hyperopt with MongoDB** -```bash -cd -source .env/bin/activate -python3 ./freqtrade/main.py -c config.json hyperopt --use-mongodb -``` - -**Re-run an Hyperopt** -To re-run Hyperopt you have to delete the existing MongoDB table. -```bash -cd -rm -rf .hyperopt/mongodb/ -``` - ## Understand the hyperopts result Once Hyperopt is completed you can use the result to adding new buy signal. Given following result from hyperopt: diff --git a/docs/installation.md b/docs/installation.md index 9818529f6..87d3dc5cf 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -184,6 +184,26 @@ docker start freqtrade You do not need to rebuild the image for configuration changes, it will suffice to edit `config.json` and restart the container. +### 7. Backtest with docker + +The following assumes that the above steps (1-4) have been completed successfully. +Also, backtest-data should be available at `~/.freqtrade/user_data/`. + + +``` bash +docker run -d \ + --name freqtrade \ + -v /etc/localtime:/etc/localtime:ro \ + -v ~/.freqtrade/config.json:/freqtrade/config.json \ + -v ~/.freqtrade/tradesv3.sqlite:/freqtrade/tradesv3.sqlite \ + -v ~/.freqtrade/user_data/:/freqtrade/user_data/ \ + freqtrade --strategy AwsomelyProfitableStrategy backtesting +``` + +Head over to the [Backtesting Documentation](https://github.com/freqtrade/freqtrade/blob/develop/docs/backtesting.md) for more details. + +*Note*: Additional parameters can be appended after the image name (`freqtrade` in the above example). + ------ ## Custom Installation @@ -225,17 +245,7 @@ cd .. rm -rf ./ta-lib* ``` -#### 3. [Optional] Install MongoDB - -Install MongoDB if you plan to optimize your strategy with Hyperopt. - -```bash -sudo apt-get install mongodb-org -``` - -> Complete tutorial from Digital Ocean: [How to Install MongoDB on Ubuntu 16.04](https://www.digitalocean.com/community/tutorials/how-to-install-mongodb-on-ubuntu-16-04). - -#### 4. Install FreqTrade +#### 3. Install FreqTrade Clone the git repository: @@ -243,7 +253,7 @@ Clone the git repository: git clone https://github.com/freqtrade/freqtrade.git ``` -#### 5. Configure `freqtrade` as a `systemd` service +#### 4. Configure `freqtrade` as a `systemd` service From the freqtrade repo... copy `freqtrade.service` to your systemd user directory (usually `~/.config/systemd/user`) and update `WorkingDirectory` and `ExecStart` to match your setup. @@ -267,19 +277,7 @@ sudo loginctl enable-linger "$USER" brew install python3 git wget ta-lib ``` -#### 2. [Optional] Install MongoDB - -Install MongoDB if you plan to optimize your strategy with Hyperopt. - -```bash -curl -O https://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-3.4.10.tgz -tar -zxvf mongodb-osx-ssl-x86_64-3.4.10.tgz -mkdir -p /env/mongodb -cp -R -n mongodb-osx-x86_64-3.4.10/ /env/mongodb -export PATH=/env/mongodb/bin:$PATH -``` - -#### 3. Install FreqTrade +#### 2. Install FreqTrade Clone the git repository: diff --git a/freqtrade/arguments.py b/freqtrade/arguments.py index 9c342141f..cc4e27845 100644 --- a/freqtrade/arguments.py +++ b/freqtrade/arguments.py @@ -203,12 +203,6 @@ class Arguments(object): type=int, metavar='INT', ) - parser.add_argument( - '--use-mongodb', - help='parallelize evaluations with mongodb (requires mongod in PATH)', - dest='mongodb', - action='store_true', - ) parser.add_argument( '-s', '--spaces', help='Specify which parameters to hyperopt. Space separate list. \ diff --git a/freqtrade/configuration.py b/freqtrade/configuration.py index 1f14df560..7c3a5eb4b 100644 --- a/freqtrade/configuration.py +++ b/freqtrade/configuration.py @@ -188,11 +188,6 @@ class Configuration(object): logger.info('Parameter --epochs detected ...') logger.info('Will run Hyperopt with for %s epochs ...', config.get('epochs')) - # If --mongodb is used we add it to the configuration - if 'mongodb' in self.args and self.args.mongodb: - config.update({'mongodb': self.args.mongodb}) - logger.info('Parameter --use-mongodb detected ...') - # If --spaces is used we add it to the configuration if 'spaces' in self.args and self.args.spaces: config.update({'spaces': self.args.spaces}) diff --git a/freqtrade/optimize/__init__.py b/freqtrade/optimize/__init__.py index fc5d53114..867e8c7dc 100644 --- a/freqtrade/optimize/__init__.py +++ b/freqtrade/optimize/__init__.py @@ -11,8 +11,6 @@ from freqtrade import misc, constants from freqtrade.exchange import get_ticker_history from freqtrade.arguments import TimeRange -from user_data.hyperopt_conf import hyperopt_optimize_conf - logger = logging.getLogger(__name__) @@ -83,7 +81,7 @@ def load_tickerdata_file( def load_data(datadir: str, ticker_interval: str, - pairs: Optional[List[str]] = None, + pairs: List[str], refresh_pairs: Optional[bool] = False, timerange: TimeRange = TimeRange(None, None, 0, 0)) -> Dict[str, List]: """ @@ -92,14 +90,12 @@ def load_data(datadir: str, """ result = {} - _pairs = pairs or hyperopt_optimize_conf()['exchange']['pair_whitelist'] - # If the user force the refresh of pairs if refresh_pairs: logger.info('Download data for all pairs and store them in %s', datadir) - download_pairs(datadir, _pairs, ticker_interval, timerange=timerange) + download_pairs(datadir, pairs, ticker_interval, timerange=timerange) - for pair in _pairs: + for pair in pairs: pairdata = load_tickerdata_file(datadir, pair, ticker_interval, timerange=timerange) if pairdata: result[pair] = pairdata diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index d12f478ee..7438c04c8 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -6,7 +6,8 @@ This module contains the backtesting logic import logging import operator from argparse import Namespace -from typing import Dict, Tuple, Any, List, Optional +from datetime import datetime +from typing import Dict, Tuple, Any, List, Optional, NamedTuple import arrow from pandas import DataFrame @@ -23,6 +24,21 @@ from freqtrade.persistence import Trade logger = logging.getLogger(__name__) +class BacktestResult(NamedTuple): + """ + NamedTuple Defining BacktestResults inputs. + """ + pair: str + profit_percent: float + profit_abs: float + open_time: datetime + close_time: datetime + open_index: int + close_index: int + trade_duration: float + open_at_end: bool + + class Backtesting(object): """ Backtesting class, this class contains all the logic to run a backtest @@ -78,17 +94,16 @@ class Backtesting(object): headers = ['pair', 'buy count', 'avg profit %', 'cum profit %', 'total profit ' + stake_currency, 'avg duration', 'profit', 'loss'] for pair in data: - result = results[results.currency == pair] - + result = results[results.pair == pair] tabular_data.append([ pair, len(result.index), result.profit_percent.mean() * 100.0, result.profit_percent.sum() * 100.0, - result.profit_BTC.sum(), - result.duration.mean(), - len(result[result.profit_BTC > 0]), - len(result[result.profit_BTC < 0]) + result.profit_abs.sum(), + result.trade_duration.mean(), + len(result[result.profit_abs > 0]), + len(result[result.profit_abs < 0]) ]) # Append Total tabular_data.append([ @@ -96,16 +111,28 @@ class Backtesting(object): len(results.index), results.profit_percent.mean() * 100.0, results.profit_percent.sum() * 100.0, - results.profit_BTC.sum(), - results.duration.mean(), - len(results[results.profit_BTC > 0]), - len(results[results.profit_BTC < 0]) + results.profit_abs.sum(), + results.trade_duration.mean(), + len(results[results.profit_abs > 0]), + len(results[results.profit_abs < 0]) ]) return floatfmt, headers, tabular_data + def _store_backtest_result(self, recordfilename: Optional[str], results: DataFrame) -> None: + + records = [(trade_entry.pair, trade_entry.profit_percent, + trade_entry.open_time.timestamp(), + trade_entry.close_time.timestamp(), + trade_entry.open_index - 1, trade_entry.trade_duration) + for index, trade_entry in results.iterrows()] + + if records: + logger.info('Dumping backtest results to %s', recordfilename) + file_dump_json(recordfilename, records) + def _get_sell_trade_entry( self, pair: str, buy_row: DataFrame, - partial_ticker: List, trade_count_lock: Dict, args: Dict) -> Optional[Tuple]: + partial_ticker: List, trade_count_lock: Dict, args: Dict) -> Optional[BacktestResult]: stake_amount = args['stake_amount'] max_open_trades = args.get('max_open_trades', 0) @@ -128,17 +155,32 @@ class Backtesting(object): buy_signal = sell_row.buy if self.analyze.should_sell(trade, sell_row.close, sell_row.date, buy_signal, sell_row.sell): - return \ - sell_row, \ - ( - pair, - trade.calc_profit_percent(rate=sell_row.close), - trade.calc_profit(rate=sell_row.close), - (sell_row.date - buy_row.date).seconds // 60, - buy_row.date, - sell_row.date - ), \ - sell_row.date + return BacktestResult(pair=pair, + profit_percent=trade.calc_profit_percent(rate=sell_row.close), + profit_abs=trade.calc_profit(rate=sell_row.close), + open_time=buy_row.date, + close_time=sell_row.date, + trade_duration=(sell_row.date - buy_row.date).seconds // 60, + open_index=buy_row.Index, + close_index=sell_row.Index, + open_at_end=False + ) + if partial_ticker: + # no sell condition found - trade stil open at end of backtest period + sell_row = partial_ticker[-1] + btr = BacktestResult(pair=pair, + profit_percent=trade.calc_profit_percent(rate=sell_row.close), + profit_abs=trade.calc_profit(rate=sell_row.close), + open_time=buy_row.date, + close_time=sell_row.date, + trade_duration=(sell_row.date - buy_row.date).seconds // 60, + open_index=buy_row.Index, + close_index=sell_row.Index, + open_at_end=True + ) + logger.debug('Force_selling still open trade %s with %s perc - %s', btr.pair, + btr.profit_percent, btr.profit_abs) + return btr return None def backtest(self, args: Dict) -> DataFrame: @@ -154,17 +196,12 @@ class Backtesting(object): processed: a processed dictionary with format {pair, data} max_open_trades: maximum number of concurrent trades (default: 0, disabled) realistic: do we try to simulate realistic trades? (default: True) - sell_profit_only: sell if profit only - use_sell_signal: act on sell-signal :return: DataFrame """ headers = ['date', 'buy', 'open', 'close', 'sell'] processed = args['processed'] max_open_trades = args.get('max_open_trades', 0) realistic = args.get('realistic', False) - record = args.get('record', None) - recordfilename = args.get('recordfn', 'backtest-result.json') - records = [] trades = [] trade_count_lock: Dict = {} for pair, pair_data in processed.items(): @@ -179,6 +216,8 @@ class Backtesting(object): ticker_data.drop(ticker_data.head(1).index, inplace=True) + # Convert from Pandas to list for performance reasons + # (Looping Pandas is slow.) ticker = [x for x in ticker_data.itertuples()] lock_pair_until = None @@ -196,30 +235,18 @@ class Backtesting(object): trade_count_lock[row.date] = trade_count_lock.get(row.date, 0) + 1 - ret = self._get_sell_trade_entry(pair, row, ticker[index + 1:], - trade_count_lock, args) - - if ret: - row2, trade_entry, next_date = ret - lock_pair_until = next_date + trade_entry = self._get_sell_trade_entry(pair, row, ticker[index + 1:], + trade_count_lock, args) + if trade_entry: + lock_pair_until = trade_entry.close_time trades.append(trade_entry) - if record: - # Note, need to be json.dump friendly - # record a tuple of pair, current_profit_percent, - # entry-date, duration - records.append((pair, trade_entry[1], - row.date.strftime('%s'), - row2.date.strftime('%s'), - index, trade_entry[3])) - # For now export inside backtest(), maybe change so that backtest() - # returns a tuple like: (dataframe, records, logs, etc) - if record and record.find('trades') >= 0: - logger.info('Dumping backtest results to %s', recordfilename) - file_dump_json(recordfilename, records) - labels = ['currency', 'profit_percent', 'profit_BTC', 'duration', 'entry', 'exit'] + else: + # Set lock_pair_until to end of testing period if trade could not be closed + # This happens only if the buy-signal was with the last candle + lock_pair_until = ticker_data.iloc[-1].date - return DataFrame.from_records(trades, columns=labels) + return DataFrame.from_records(trades, columns=BacktestResult._fields) def start(self): """ @@ -270,24 +297,22 @@ class Backtesting(object): ) # Execute backtest and print results - sell_profit_only = self.config.get('experimental', {}).get('sell_profit_only', False) - use_sell_signal = self.config.get('experimental', {}).get('use_sell_signal', False) results = self.backtest( { 'stake_amount': self.config.get('stake_amount'), 'processed': preprocessed, 'max_open_trades': max_open_trades, 'realistic': self.config.get('realistic_simulation', False), - 'sell_profit_only': sell_profit_only, - 'use_sell_signal': use_sell_signal, - 'record': self.config.get('export'), - 'recordfn': self.config.get('exportfilename'), } ) + + if self.config.get('export', False): + self._store_backtest_result(self.config.get('exportfilename'), results) + logger.info( - '\n==================================== ' + '\n======================================== ' 'BACKTESTING REPORT' - ' ====================================\n' + ' =========================================\n' '%s', self._generate_text_table( data, @@ -295,7 +320,17 @@ class Backtesting(object): ) ) - # return date for data storage + logger.info( + '\n====================================== ' + 'LEFT OPEN TRADES REPORT' + ' ======================================\n' + '%s', + self._generate_text_table( + data, + results.loc[results.open_at_end] + ) + ) + table = self.aggregate(data, results) return results, table diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index c98911991..39df74799 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -19,7 +19,6 @@ from typing import Dict, Any, Callable, Optional import numpy import talib.abstract as ta from hyperopt import STATUS_FAIL, STATUS_OK, Trials, fmin, hp, space_eval, tpe -from hyperopt.mongoexp import MongoTrials from pandas import DataFrame import freqtrade.vendor.qtpylib.indicators as qtpylib @@ -27,7 +26,6 @@ from freqtrade.arguments import Arguments from freqtrade.configuration import Configuration from freqtrade.optimize import load_data from freqtrade.optimize.backtesting import Backtesting -from user_data.hyperopt_conf import hyperopt_optimize_conf logger = logging.getLogger(__name__) @@ -449,7 +447,7 @@ class Hyperopt(Backtesting): total_profit = results.profit_percent.sum() trade_count = len(results.index) - trade_duration = results.duration.mean() + trade_duration = results.trade_duration.mean() if trade_count == 0 or trade_duration > self.max_accepted_trade_duration: print('.', end='') @@ -486,10 +484,10 @@ class Hyperopt(Backtesting): 'Total profit {: 11.8f} {} ({:.4f}Σ%). Avg duration {:5.1f} mins.').format( len(results.index), results.profit_percent.mean() * 100.0, - results.profit_BTC.sum(), + results.profit_abs.sum(), self.config['stake_currency'], results.profit_percent.sum(), - results.duration.mean(), + results.trade_duration.mean(), ) def start(self) -> None: @@ -506,32 +504,20 @@ class Hyperopt(Backtesting): self.analyze.populate_indicators = Hyperopt.populate_indicators # type: ignore self.processed = self.tickerdata_to_dataframe(data) - if self.config.get('mongodb'): - logger.info('Using mongodb ...') + logger.info('Preparing Trials..') + signal.signal(signal.SIGINT, self.signal_handler) + # read trials file if we have one + if os.path.exists(self.trials_file) and os.path.getsize(self.trials_file) > 0: + self.trials = self.read_trials() + + self.current_tries = len(self.trials.results) + self.total_tries += self.current_tries logger.info( - 'Start scripts/start-mongodb.sh and start-hyperopt-worker.sh manually!' + 'Continuing with trials. Current: %d, Total: %d', + self.current_tries, + self.total_tries ) - db_name = 'freqtrade_hyperopt' - self.trials = MongoTrials( - arg='mongo://127.0.0.1:1234/{}/jobs'.format(db_name), - exp_key='exp1' - ) - else: - logger.info('Preparing Trials..') - signal.signal(signal.SIGINT, self.signal_handler) - # read trials file if we have one - if os.path.exists(self.trials_file) and os.path.getsize(self.trials_file) > 0: - self.trials = self.read_trials() - - self.current_tries = len(self.trials.results) - self.total_tries += self.current_tries - logger.info( - 'Continuing with trials. Current: %d, Total: %d', - self.current_tries, - self.total_tries - ) - try: best_parameters = fmin( fn=self.generate_optimizer, @@ -587,18 +573,14 @@ def start(args: Namespace) -> None: """ # Remove noisy log messages - logging.getLogger('hyperopt.mongoexp').setLevel(logging.WARNING) logging.getLogger('hyperopt.tpe').setLevel(logging.WARNING) # Initialize configuration # Monkey patch the configuration with hyperopt_conf.py configuration = Configuration(args) logger.info('Starting freqtrade in Hyperopt mode') + config = configuration.load_config() - optimize_config = hyperopt_optimize_conf() - config = configuration._load_common_config(optimize_config) - config = configuration._load_backtesting_config(config) - config = configuration._load_hyperopt_config(config) config['exchange']['key'] = '' config['exchange']['secret'] = '' diff --git a/freqtrade/tests/optimize/test_backtesting.py b/freqtrade/tests/optimize/test_backtesting.py index 7729fdd26..4ee623e1f 100644 --- a/freqtrade/tests/optimize/test_backtesting.py +++ b/freqtrade/tests/optimize/test_backtesting.py @@ -356,21 +356,31 @@ def test_generate_text_table(default_conf, mocker): results = pd.DataFrame( { - 'currency': ['ETH/BTC', 'ETH/BTC'], + 'pair': ['ETH/BTC', 'ETH/BTC'], 'profit_percent': [0.1, 0.2], - 'profit_BTC': [0.2, 0.4], - 'duration': [10, 30], + 'profit_abs': [0.2, 0.4], + 'cum profit %': [30, 30], + 'total profit BTC': [0.6, 0.6], + 'trade_duration': [10, 30], 'profit': [2, 0], 'loss': [0, 0] } ) result_str = ( -"""| pair | buy count | avg profit % | cum profit % | total profit BTC | avg duration | profit | loss | + """| pair | buy count | avg profit % | cum profit % | total profit BTC | avg duration | profit | loss | |:--------|------------:|---------------:|---------------:|-------------------:|---------------:|---------:|-------:| | ETH/BTC | 2 | 15.00 | 30.00 | 0.60000000 | 20.0 | 2 | 0 | | TOTAL | 2 | 15.00 | 30.00 | 0.60000000 | 20.0 | 2 | 0 |""" ) + # + # print() + # print(backtesting._generate_text_table(data={'ETH/BTC': {}}, results=results)) + # + # print() + # print() + # print(result_str) + assert backtesting._generate_text_table(data={'ETH/BTC': {}}, results=results) == result_str @@ -469,6 +479,7 @@ def test_backtest(default_conf, fee, mocker) -> None: } ) assert not results.empty + assert len(results) == 2 def test_backtest_1min_ticker_interval(default_conf, fee, mocker) -> None: @@ -491,6 +502,7 @@ def test_backtest_1min_ticker_interval(default_conf, fee, mocker) -> None: } ) assert not results.empty + assert len(results) == 1 def test_processed(default_conf, mocker) -> None: @@ -512,7 +524,7 @@ def test_processed(default_conf, mocker) -> None: def test_backtest_pricecontours(default_conf, fee, mocker) -> None: mocker.patch('freqtrade.optimize.backtesting.exchange.get_fee', fee) - tests = [['raise', 17], ['lower', 0], ['sine', 16]] + tests = [['raise', 18], ['lower', 0], ['sine', 16]] for [contour, numres] in tests: simple_backtest(default_conf, contour, numres, mocker) @@ -572,7 +584,10 @@ def test_backtest_alternate_buy_sell(default_conf, fee, mocker): backtesting.populate_buy_trend = _trend_alternate # Override backtesting.populate_sell_trend = _trend_alternate # Override results = backtesting.backtest(backtest_conf) - assert len(results) == 3 + backtesting._store_backtest_result("test_.json", results) + assert len(results) == 4 + # One trade was force-closed at the end + assert len(results.loc[results.open_at_end]) == 1 def test_backtest_record(default_conf, fee, mocker): @@ -584,22 +599,30 @@ def test_backtest_record(default_conf, fee, mocker): 'freqtrade.optimize.backtesting.file_dump_json', new=lambda n, r: (names.append(n), records.append(r)) ) - backtest_conf = _make_backtest_conf( - mocker, - conf=default_conf, - pair='UNITTEST/BTC', - record="trades" - ) + backtesting = Backtesting(default_conf) - backtesting.populate_buy_trend = _trend_alternate # Override - backtesting.populate_sell_trend = _trend_alternate # Override - results = backtesting.backtest(backtest_conf) - assert len(results) == 3 + results = pd.DataFrame({"pair": ["UNITTEST/BTC", "UNITTEST/BTC", + "UNITTEST/BTC", "UNITTEST/BTC"], + "profit_percent": [0.003312, 0.010801, 0.013803, 0.002780], + "profit_abs": [0.000003, 0.000011, 0.000014, 0.000003], + "open_time": [Arrow(2017, 11, 14, 19, 32, 00).datetime, + Arrow(2017, 11, 14, 21, 36, 00).datetime, + Arrow(2017, 11, 14, 22, 12, 00).datetime, + Arrow(2017, 11, 14, 22, 44, 00).datetime], + "close_time": [Arrow(2017, 11, 14, 21, 35, 00).datetime, + Arrow(2017, 11, 14, 22, 10, 00).datetime, + Arrow(2017, 11, 14, 22, 43, 00).datetime, + Arrow(2017, 11, 14, 22, 58, 00).datetime], + "open_index": [1, 119, 153, 185], + "close_index": [118, 151, 184, 199], + "trade_duration": [123, 34, 31, 14]}) + backtesting._store_backtest_result("backtest-result.json", results) + assert len(results) == 4 # Assert file_dump_json was only called once assert names == ['backtest-result.json'] records = records[0] # Ensure records are of correct type - assert len(records) == 3 + assert len(records) == 4 # ('UNITTEST/BTC', 0.00331158, '1510684320', '1510691700', 0, 117) # Below follows just a typecheck of the schema/type of trade-records oix = None diff --git a/freqtrade/tests/optimize/test_hyperopt.py b/freqtrade/tests/optimize/test_hyperopt.py index 3edfe4393..950861573 100644 --- a/freqtrade/tests/optimize/test_hyperopt.py +++ b/freqtrade/tests/optimize/test_hyperopt.py @@ -23,8 +23,6 @@ def init_hyperopt(default_conf, mocker): global _HYPEROPT_INITIALIZED, _HYPEROPT if not _HYPEROPT_INITIALIZED: mocker.patch('freqtrade.exchange.validate_pairs', MagicMock(return_value=True)) - mocker.patch('freqtrade.optimize.hyperopt.hyperopt_optimize_conf', - MagicMock(return_value=default_conf)) mocker.patch('freqtrade.exchange.validate_pairs', MagicMock()) _HYPEROPT = Hyperopt(default_conf) _HYPEROPT_INITIALIZED = True @@ -63,9 +61,11 @@ def test_start(mocker, default_conf, caplog) -> None: Test start() function """ start_mock = MagicMock() + mocker.patch( + 'freqtrade.configuration.Configuration._load_config_file', + lambda *args, **kwargs: default_conf + ) mocker.patch('freqtrade.optimize.hyperopt.Hyperopt.start', start_mock) - mocker.patch('freqtrade.optimize.hyperopt.hyperopt_optimize_conf', - MagicMock(return_value=default_conf)) mocker.patch('freqtrade.freqtradebot.exchange.validate_pairs', MagicMock()) args = [ @@ -123,6 +123,7 @@ def test_loss_calculation_has_limited_profit(init_hyperopt) -> None: assert under > correct +@pytest.mark.skip(reason="no way of currently testing this") def test_log_results_if_loss_improves(init_hyperopt, capsys) -> None: hyperopt = _HYPEROPT hyperopt.current_best_loss = 2 @@ -135,7 +136,9 @@ def test_log_results_if_loss_improves(init_hyperopt, capsys) -> None: } ) out, err = capsys.readouterr() - assert ' 1/2: foo. Loss 1.00000'in out + with capsys.disabled(): + print("out is: {}".format(out)) + assert ' 1/2: foo. Loss 1.00000'in out def test_no_log_if_loss_does_not_improve(init_hyperopt, caplog) -> None: @@ -182,7 +185,6 @@ def test_fmin_best_results(mocker, init_hyperopt, default_conf, caplog) -> None: mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock()) mocker.patch('freqtrade.optimize.hyperopt.fmin', return_value=fmin_result) - mocker.patch('freqtrade.optimize.hyperopt.hyperopt_optimize_conf', return_value=conf) mocker.patch('freqtrade.freqtradebot.exchange.validate_pairs', MagicMock()) StrategyResolver({'strategy': 'DefaultStrategy'}) @@ -227,7 +229,6 @@ def test_fmin_throw_value_error(mocker, init_hyperopt, default_conf, caplog) -> conf.update({'epochs': 1}) conf.update({'timerange': None}) conf.update({'spaces': 'all'}) - mocker.patch('freqtrade.optimize.hyperopt.hyperopt_optimize_conf', return_value=conf) mocker.patch('freqtrade.freqtradebot.exchange.validate_pairs', MagicMock()) StrategyResolver({'strategy': 'DefaultStrategy'}) @@ -253,7 +254,6 @@ def test_resuming_previous_hyperopt_results_succeeds(mocker, init_hyperopt, defa conf = deepcopy(default_conf) conf.update({'config': 'config.json.example'}) conf.update({'epochs': 1}) - conf.update({'mongodb': False}) conf.update({'timerange': None}) conf.update({'spaces': 'all'}) @@ -270,7 +270,6 @@ def test_resuming_previous_hyperopt_results_succeeds(mocker, init_hyperopt, defa mocker.patch('freqtrade.optimize.hyperopt.sorted', return_value=trials.results) mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock()) mocker.patch('freqtrade.optimize.hyperopt.fmin', return_value={}) - mocker.patch('freqtrade.optimize.hyperopt.hyperopt_optimize_conf', return_value=conf) mocker.patch('freqtrade.exchange.validate_pairs', MagicMock()) StrategyResolver({'strategy': 'DefaultStrategy'}) @@ -348,7 +347,6 @@ def test_start_calls_fmin(mocker, init_hyperopt, default_conf) -> None: conf = deepcopy(default_conf) conf.update({'config': 'config.json.example'}) conf.update({'epochs': 1}) - conf.update({'mongodb': False}) conf.update({'timerange': None}) conf.update({'spaces': 'all'}) @@ -360,35 +358,6 @@ def test_start_calls_fmin(mocker, init_hyperopt, default_conf) -> None: mock_fmin.assert_called_once() -def test_start_uses_mongotrials(mocker, init_hyperopt, default_conf) -> None: - mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock()) - mock_fmin = mocker.patch('freqtrade.optimize.hyperopt.fmin', return_value={}) - mock_mongotrials = mocker.patch( - 'freqtrade.optimize.hyperopt.MongoTrials', - return_value=create_trials(mocker) - ) - - conf = deepcopy(default_conf) - conf.update({'config': 'config.json.example'}) - conf.update({'epochs': 1}) - conf.update({'mongodb': True}) - conf.update({'timerange': None}) - conf.update({'spaces': 'all'}) - mocker.patch('freqtrade.optimize.hyperopt.hyperopt_optimize_conf', return_value=conf) - mocker.patch('freqtrade.freqtradebot.exchange.validate_pairs', MagicMock()) - - hyperopt = Hyperopt(conf) - hyperopt.tickerdata_to_dataframe = MagicMock() - - hyperopt.start() - mock_mongotrials.assert_called_once() - mock_fmin.assert_called_once() - - -# test log_trials_result -# test buy_strategy_generator def populate_buy_trend -# test optimizer if 'ro_t1' in params - def test_format_results(init_hyperopt): """ Test Hyperopt.format_results() @@ -400,7 +369,7 @@ def test_format_results(init_hyperopt): ('LTC/BTC', 1, 1, 123), ('XPR/BTC', -1, -2, -246) ] - labels = ['currency', 'profit_percent', 'profit_BTC', 'duration'] + labels = ['currency', 'profit_percent', 'profit_abs', 'trade_duration'] df = pd.DataFrame.from_records(trades, columns=labels) result = _HYPEROPT.format_results(df) @@ -530,7 +499,7 @@ def test_generate_optimizer(mocker, init_hyperopt, default_conf) -> None: trades = [ ('POWR/BTC', 0.023117, 0.000233, 100) ] - labels = ['currency', 'profit_percent', 'profit_BTC', 'duration'] + labels = ['currency', 'profit_percent', 'profit_abs', 'trade_duration'] backtest_result = pd.DataFrame.from_records(trades, columns=labels) mocker.patch( diff --git a/freqtrade/tests/optimize/test_hyperopt_config.py b/freqtrade/tests/optimize/test_hyperopt_config.py deleted file mode 100644 index aa9424826..000000000 --- a/freqtrade/tests/optimize/test_hyperopt_config.py +++ /dev/null @@ -1,16 +0,0 @@ -# pragma pylint: disable=missing-docstring,W0212 - -from user_data.hyperopt_conf import hyperopt_optimize_conf - - -def test_hyperopt_optimize_conf(): - hyperopt_conf = hyperopt_optimize_conf() - - assert "max_open_trades" in hyperopt_conf - assert "stake_currency" in hyperopt_conf - assert "stake_amount" in hyperopt_conf - assert "minimal_roi" in hyperopt_conf - assert "stoploss" in hyperopt_conf - assert "bid_strategy" in hyperopt_conf - assert "exchange" in hyperopt_conf - assert "pair_whitelist" in hyperopt_conf['exchange'] diff --git a/freqtrade/tests/optimize/test_optimize.py b/freqtrade/tests/optimize/test_optimize.py index 3f358cfb8..bac8a6b36 100644 --- a/freqtrade/tests/optimize/test_optimize.py +++ b/freqtrade/tests/optimize/test_optimize.py @@ -326,8 +326,6 @@ def test_load_tickerdata_file() -> None: def test_init(default_conf, mocker) -> None: - conf = {'exchange': {'pair_whitelist': []}} - mocker.patch('freqtrade.optimize.hyperopt_optimize_conf', return_value=conf) assert {} == optimize.load_data( '', pairs=[], diff --git a/freqtrade/tests/test_configuration.py b/freqtrade/tests/test_configuration.py index caaddbf25..019c0c09d 100644 --- a/freqtrade/tests/test_configuration.py +++ b/freqtrade/tests/test_configuration.py @@ -13,6 +13,7 @@ from jsonschema import ValidationError from freqtrade.arguments import Arguments from freqtrade.configuration import Configuration +from freqtrade.constants import DEFAULT_DB_PROD_URL, DEFAULT_DB_DRYRUN_URL from freqtrade.tests.conftest import log_has from freqtrade import OperationalException @@ -140,6 +141,43 @@ def test_load_config_with_params(default_conf, mocker) -> None: assert validated_conf.get('strategy_path') == '/some/path' assert validated_conf.get('db_url') == 'sqlite:///someurl' + conf = default_conf.copy() + conf["dry_run"] = False + del conf["db_url"] + mocker.patch('freqtrade.configuration.open', mocker.mock_open( + read_data=json.dumps(conf) + )) + + arglist = [ + '--dynamic-whitelist', '10', + '--strategy', 'TestStrategy', + '--strategy-path', '/some/path' + ] + args = Arguments(arglist, '').get_parsed_arg() + + configuration = Configuration(args) + validated_conf = configuration.load_config() + assert validated_conf.get('db_url') == DEFAULT_DB_PROD_URL + + # Test dry=run with ProdURL + conf = default_conf.copy() + conf["dry_run"] = True + conf["db_url"] = DEFAULT_DB_PROD_URL + mocker.patch('freqtrade.configuration.open', mocker.mock_open( + read_data=json.dumps(conf) + )) + + arglist = [ + '--dynamic-whitelist', '10', + '--strategy', 'TestStrategy', + '--strategy-path', '/some/path' + ] + args = Arguments(arglist, '').get_parsed_arg() + + configuration = Configuration(args) + validated_conf = configuration.load_config() + assert validated_conf.get('db_url') == DEFAULT_DB_DRYRUN_URL + def test_load_custom_strategy(default_conf, mocker) -> None: """ @@ -310,7 +348,6 @@ def test_hyperopt_with_arguments(mocker, default_conf, caplog) -> None: arglist = [ 'hyperopt', '--epochs', '10', - '--use-mongodb', '--spaces', 'all', ] @@ -324,10 +361,6 @@ def test_hyperopt_with_arguments(mocker, default_conf, caplog) -> None: assert log_has('Parameter --epochs detected ...', caplog.record_tuples) assert log_has('Will run Hyperopt with for 10 epochs ...', caplog.record_tuples) - assert 'mongodb' in config - assert config['mongodb'] is True - assert log_has('Parameter --use-mongodb detected ...', caplog.record_tuples) - assert 'spaces' in config assert config['spaces'] == ['all'] assert log_has('Parameter -s/--spaces detected: [\'all\']', caplog.record_tuples) diff --git a/freqtrade/tests/test_fiat_convert.py b/freqtrade/tests/test_fiat_convert.py index 24f0f776b..2fb9219ca 100644 --- a/freqtrade/tests/test_fiat_convert.py +++ b/freqtrade/tests/test_fiat_convert.py @@ -40,7 +40,8 @@ def test_pair_convertion_object(): assert pair_convertion.price == 30000.123 -def test_fiat_convert_is_supported(): +def test_fiat_convert_is_supported(mocker): + patch_coinmarketcap(mocker) fiat_convert = CryptoToFiatConverter() assert fiat_convert._is_supported_fiat(fiat='USD') is True assert fiat_convert._is_supported_fiat(fiat='usd') is True @@ -48,7 +49,9 @@ def test_fiat_convert_is_supported(): assert fiat_convert._is_supported_fiat(fiat='ABC') is False -def test_fiat_convert_add_pair(): +def test_fiat_convert_add_pair(mocker): + patch_coinmarketcap(mocker) + fiat_convert = CryptoToFiatConverter() pair_len = len(fiat_convert._pairs) @@ -70,11 +73,8 @@ def test_fiat_convert_add_pair(): def test_fiat_convert_find_price(mocker): - api_mock = MagicMock(return_value={ - 'price_usd': 12345.0, - 'price_eur': 13000.2 - }) - mocker.patch('freqtrade.fiat_convert.Market.ticker', api_mock) + patch_coinmarketcap(mocker) + fiat_convert = CryptoToFiatConverter() with pytest.raises(ValueError, match=r'The fiat ABC is not supported.'): @@ -92,17 +92,15 @@ def test_fiat_convert_find_price(mocker): def test_fiat_convert_unsupported_crypto(mocker, caplog): mocker.patch('freqtrade.fiat_convert.CryptoToFiatConverter._cryptomap', return_value=[]) + patch_coinmarketcap(mocker) fiat_convert = CryptoToFiatConverter() assert fiat_convert._find_price(crypto_symbol='CRYPTO_123', fiat_symbol='EUR') == 0.0 assert log_has('unsupported crypto-symbol CRYPTO_123 - returning 0.0', caplog.record_tuples) def test_fiat_convert_get_price(mocker): - api_mock = MagicMock(return_value={ - 'price_usd': 28000.0, - 'price_eur': 15000.0 - }) - mocker.patch('freqtrade.fiat_convert.Market.ticker', api_mock) + patch_coinmarketcap(mocker) + mocker.patch('freqtrade.fiat_convert.CryptoToFiatConverter._find_price', return_value=28000.0) fiat_convert = CryptoToFiatConverter() @@ -172,8 +170,9 @@ def test_fiat_init_network_exception(mocker): assert length_cryptomap == 0 -def test_fiat_convert_without_network(): +def test_fiat_convert_without_network(mocker): # Because CryptoToFiatConverter is a Singleton we reset the value of _coinmarketcap + patch_coinmarketcap(mocker) fiat_convert = CryptoToFiatConverter() @@ -186,6 +185,7 @@ def test_fiat_convert_without_network(): def test_convert_amount(mocker): + patch_coinmarketcap(mocker) mocker.patch('freqtrade.fiat_convert.CryptoToFiatConverter.get_price', return_value=12345.0) fiat_convert = CryptoToFiatConverter() diff --git a/requirements.txt b/requirements.txt index b0d42699b..af9be6e67 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,9 @@ -ccxt==1.14.186 +ccxt==1.14.224 SQLAlchemy==1.2.8 python-telegram-bot==10.1.0 arrow==0.12.1 cachetools==2.1.0 -requests==2.19.0 +requests==2.19.1 urllib3==1.22 wrapt==1.10.11 pandas==0.23.1 diff --git a/scripts/start-hyperopt-worker.py b/scripts/start-hyperopt-worker.py deleted file mode 100755 index 8b0ae6326..000000000 --- a/scripts/start-hyperopt-worker.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python3 -import multiprocessing -import os -import subprocess - -PROC_COUNT = multiprocessing.cpu_count() - 1 -DB_NAME = 'freqtrade_hyperopt' -WORK_DIR = os.path.join( - os.path.sep, - os.path.abspath(os.path.dirname(__file__)), - '..', '.hyperopt', 'worker' -) -if not os.path.exists(WORK_DIR): - os.makedirs(WORK_DIR) - -# Spawn workers -command = [ - 'hyperopt-mongo-worker', - '--mongo=127.0.0.1:1234/{}'.format(DB_NAME), - '--poll-interval=0.1', - '--workdir={}'.format(WORK_DIR), -] -processes = [subprocess.Popen(command) for i in range(PROC_COUNT)] - -# Join all workers -for proc in processes: - proc.wait() diff --git a/scripts/start-mongodb.py b/scripts/start-mongodb.py deleted file mode 100755 index 910ee9233..000000000 --- a/scripts/start-mongodb.py +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env python3 - -import os -import subprocess - - -DB_PATH = os.path.join( - os.path.sep, - os.path.abspath(os.path.dirname(__file__)), - '..', '.hyperopt', 'mongodb' -) -if not os.path.exists(DB_PATH): - os.makedirs(DB_PATH) - -subprocess.Popen([ - 'mongod', - '--bind_ip=127.0.0.1', - '--port=1234', - '--nohttpinterface', - '--dbpath={}'.format(DB_PATH), -]).wait() diff --git a/user_data/hyperopt_conf.py b/user_data/hyperopt_conf.py deleted file mode 100644 index c3a6e2a29..000000000 --- a/user_data/hyperopt_conf.py +++ /dev/null @@ -1,42 +0,0 @@ -""" -File that contains the configuration for Hyperopt -""" - - -def hyperopt_optimize_conf() -> dict: - """ - This function is used to define which parameters Hyperopt must used. - The "pair_whitelist" is only used is your are using Hyperopt with MongoDB, - without MongoDB, Hyperopt will use the pair your have set in your config file. - :return: - """ - return { - 'max_open_trades': 3, - 'stake_currency': 'BTC', - 'stake_amount': 0.01, - "minimal_roi": { - '40': 0.0, - '30': 0.01, - '20': 0.02, - '0': 0.04, - }, - 'stoploss': -0.10, - "bid_strategy": { - "ask_last_balance": 0.0 - }, - "exchange": { - "name": "bittrex", - "pair_whitelist": [ - "ETH/BTC", - "LTC/BTC", - "ETC/BTC", - "DASH/BTC", - "ZEC/BTC", - "XLM/BTC", - "NXT/BTC", - "POWR/BTC", - "ADA/BTC", - "XMR/BTC" - ] - } - }