From 0d605d2396920d171d477336c0ee111cafa4936e Mon Sep 17 00:00:00 2001 From: Gerald Lonlas Date: Thu, 28 Dec 2017 00:11:52 -0800 Subject: [PATCH] Refactor Optimize tests, and add more unit tests --- freqtrade/optimize/__init__.py | 14 +- freqtrade/tests/optimize/test_backtesting.py | 76 +-------- freqtrade/tests/optimize/test_optimize.py | 166 +++++++++++++++++++ freqtrade/tests/test_main.py | 2 +- 4 files changed, 175 insertions(+), 83 deletions(-) create mode 100644 freqtrade/tests/optimize/test_optimize.py diff --git a/freqtrade/optimize/__init__.py b/freqtrade/optimize/__init__.py index ac077506a..1be7ce536 100644 --- a/freqtrade/optimize/__init__.py +++ b/freqtrade/optimize/__init__.py @@ -87,17 +87,17 @@ def download_backtesting_testdata(pair: str, interval: int = 5) -> bool: )) filepair = pair.replace("-", "_") - filename = os.path.join(path, '{}-{}.json'.format( - filepair, - interval, + filename = os.path.join(path, '{pair}-{interval}.json'.format( + pair=filepair, + interval=interval, )) filename = filename.replace('USDT_BTC', 'BTC_FAKEBULL') if os.path.isfile(filename): with open(filename, "rt") as fp: data = json.load(fp) - logger.debug("Current Start:", data[1]['T']) - logger.debug("Current End: ", data[-1:][0]['T']) + logger.debug("Current Start: {}".format(data[1]['T'])) + logger.debug("Current End: {}".format(data[-1:][0]['T'])) else: data = [] logger.debug("Current Start: None") @@ -107,8 +107,8 @@ def download_backtesting_testdata(pair: str, interval: int = 5) -> bool: for row in new_data: if row not in data: data.append(row) - logger.debug("New Start:", data[1]['T']) - logger.debug("New End: ", data[-1:][0]['T']) + logger.debug("New Start: {}".format(data[1]['T'])) + logger.debug("New End: {}".format(data[-1:][0]['T'])) data = sorted(data, key=lambda data: data['T']) with open(filename, "wt") as fp: diff --git a/freqtrade/tests/optimize/test_backtesting.py b/freqtrade/tests/optimize/test_backtesting.py index 99f95d9bf..e3d423b7d 100644 --- a/freqtrade/tests/optimize/test_backtesting.py +++ b/freqtrade/tests/optimize/test_backtesting.py @@ -1,11 +1,9 @@ # pragma pylint: disable=missing-docstring,W0212 -import os import pandas as pd from freqtrade import exchange, optimize from freqtrade.exchange import Bittrex from freqtrade.optimize.backtesting import backtest, generate_text_table, get_timeframe -from freqtrade.optimize.__init__ import testdata_path, download_pairs, download_backtesting_testdata def test_generate_text_table(): @@ -40,7 +38,7 @@ def test_backtest(default_conf, mocker): assert not results.empty -def test_1min_ticker_interval(default_conf, mocker): +def test_backtest_1min_ticker_interval(default_conf, mocker): mocker.patch.dict('freqtrade.main._CONF', default_conf) exchange._API = Bittrex({'key': '', 'secret': ''}) @@ -48,75 +46,3 @@ def test_1min_ticker_interval(default_conf, mocker): data = optimize.load_data(ticker_interval=1, pairs=['BTC_UNITEST']) results = backtest(default_conf['stake_amount'], optimize.preprocess(data), 1, True) assert not results.empty - - -def test_backtest_with_new_pair(default_conf, ticker_history, mocker): - mocker.patch('freqtrade.optimize.get_ticker_history', return_value=ticker_history) - mocker.patch.dict('freqtrade.main._CONF', default_conf) - - exchange._API = Bittrex({'key': '', 'secret': ''}) - - optimize.load_data(ticker_interval=1, pairs=['BTC_MEME']) - file = 'freqtrade/tests/testdata/BTC_MEME-1.json' - assert os.path.isfile(file) is True - - # delete file freshly downloaded - if os.path.isfile(file): - os.remove(file) - - -def test_testdata_path(): - assert os.path.join('freqtrade', 'tests', 'testdata') in testdata_path() - - -def test_download_pairs(default_conf, ticker_history, mocker): - mocker.patch('freqtrade.optimize.__init__.get_ticker_history', return_value=ticker_history) - mocker.patch.dict('freqtrade.main._CONF', default_conf) - exchange._API = Bittrex({'key': '', 'secret': ''}) - - file1_1 = 'freqtrade/tests/testdata/BTC_MEME-1.json' - file1_5 = 'freqtrade/tests/testdata/BTC_MEME-5.json' - file2_1 = 'freqtrade/tests/testdata/BTC_CFI-1.json' - file2_5 = 'freqtrade/tests/testdata/BTC_CFI-5.json' - - assert download_pairs(pairs=['BTC-MEME', 'BTC-CFI']) is True - - assert os.path.isfile(file1_1) is True - assert os.path.isfile(file1_5) is True - assert os.path.isfile(file2_1) is True - assert os.path.isfile(file2_5) is True - - # delete files freshly downloaded - if os.path.isfile(file1_1): - os.remove(file1_1) - - if os.path.isfile(file1_5): - os.remove(file1_5) - - if os.path.isfile(file2_1): - os.remove(file2_1) - - if os.path.isfile(file2_5): - os.remove(file2_5) - - -def test_download_backtesting_testdata(default_conf, ticker_history, mocker): - mocker.patch('freqtrade.optimize.__init__.get_ticker_history', return_value=ticker_history) - mocker.patch.dict('freqtrade.main._CONF', default_conf) - exchange._API = Bittrex({'key': '', 'secret': ''}) - - # Download a 1 min ticker file - file1 = 'freqtrade/tests/testdata/BTC_XEL-1.json' - download_backtesting_testdata(pair="BTC-XEL", interval=1) - assert os.path.isfile(file1) is True - - if os.path.isfile(file1): - os.remove(file1) - - # Download a 5 min ticker file - file2 = 'freqtrade/tests/testdata/BTC_STORJ-5.json' - download_backtesting_testdata(pair="BTC-STORJ", interval=5) - assert os.path.isfile(file2) is True - - if os.path.isfile(file2): - os.remove(file2) diff --git a/freqtrade/tests/optimize/test_optimize.py b/freqtrade/tests/optimize/test_optimize.py new file mode 100644 index 000000000..aad20567e --- /dev/null +++ b/freqtrade/tests/optimize/test_optimize.py @@ -0,0 +1,166 @@ +# pragma pylint: disable=missing-docstring,W0212 + +import os +import logging +from shutil import copyfile +from freqtrade import exchange, optimize +from freqtrade.exchange import Bittrex +from freqtrade.optimize.__init__ import testdata_path, download_pairs, download_backtesting_testdata + + +def _backup_file(file: str, copy_file: bool = False) -> None: + """ + Backup existing file to avoid deleting the user file + :param file: complete path to the file + :param touch_file: create an empty file in replacement + :return: None + """ + file_swp = file + '.swp' + if os.path.isfile(file): + os.rename(file, file_swp) + + if copy_file: + copyfile(file_swp, file) + + +def _clean_test_file(file: str) -> None: + """ + Backup existing file to avoid deleting the user file + :param file: complete path to the file + :return: None + """ + file_swp = file + '.swp' + # 1. Delete file from the test + if os.path.isfile(file): + os.remove(file) + + # 2. Rollback to the initial file + if os.path.isfile(file_swp): + os.rename(file_swp, file) + + +def test_load_data_5min_ticker(default_conf, ticker_history, mocker, caplog): + mocker.patch('freqtrade.optimize.get_ticker_history', return_value=ticker_history) + mocker.patch.dict('freqtrade.main._CONF', default_conf) + + exchange._API = Bittrex({'key': '', 'secret': ''}) + + file = 'freqtrade/tests/testdata/BTC_ETH-5.json' + _backup_file(file, copy_file=True) + optimize.load_data(pairs=['BTC_ETH']) + assert os.path.isfile(file) is True + assert ('freqtrade.optimize', + logging.INFO, + 'Download the pair: "BTC_ETH", Interval: 5 min' + ) not in caplog.record_tuples + _clean_test_file(file) + + +def test_load_data_1min_ticker(default_conf, ticker_history, mocker, caplog): + mocker.patch('freqtrade.optimize.get_ticker_history', return_value=ticker_history) + mocker.patch.dict('freqtrade.main._CONF', default_conf) + + exchange._API = Bittrex({'key': '', 'secret': ''}) + + file = 'freqtrade/tests/testdata/BTC_ETH-1.json' + _backup_file(file, copy_file=True) + optimize.load_data(ticker_interval=1, pairs=['BTC_ETH']) + assert os.path.isfile(file) is True + assert ('freqtrade.optimize', + logging.INFO, + 'Download the pair: "BTC_ETH", Interval: 1 min' + ) not in caplog.record_tuples + _clean_test_file(file) + + +def test_load_data_with_new_pair_1min(default_conf, ticker_history, mocker, caplog): + mocker.patch('freqtrade.optimize.get_ticker_history', return_value=ticker_history) + mocker.patch.dict('freqtrade.main._CONF', default_conf) + + exchange._API = Bittrex({'key': '', 'secret': ''}) + + file = 'freqtrade/tests/testdata/BTC_MEME-1.json' + _backup_file(file) + optimize.load_data(ticker_interval=1, pairs=['BTC_MEME']) + assert os.path.isfile(file) is True + assert ('freqtrade.optimize', + logging.INFO, + 'Download the pair: "BTC_MEME", Interval: 1 min' + ) in caplog.record_tuples + _clean_test_file(file) + + +def test_testdata_path(): + assert os.path.join('freqtrade', 'tests', 'testdata') in testdata_path() + + +def test_download_pairs(default_conf, ticker_history, mocker): + mocker.patch('freqtrade.optimize.__init__.get_ticker_history', return_value=ticker_history) + mocker.patch.dict('freqtrade.main._CONF', default_conf) + exchange._API = Bittrex({'key': '', 'secret': ''}) + + file1_1 = 'freqtrade/tests/testdata/BTC_MEME-1.json' + file1_5 = 'freqtrade/tests/testdata/BTC_MEME-5.json' + file2_1 = 'freqtrade/tests/testdata/BTC_CFI-1.json' + file2_5 = 'freqtrade/tests/testdata/BTC_CFI-5.json' + + _backup_file(file1_1) + _backup_file(file1_5) + _backup_file(file2_1) + _backup_file(file2_5) + + assert download_pairs(pairs=['BTC-MEME', 'BTC-CFI']) is True + + assert os.path.isfile(file1_1) is True + assert os.path.isfile(file1_5) is True + assert os.path.isfile(file2_1) is True + assert os.path.isfile(file2_5) is True + + # clean files freshly downloaded + _clean_test_file(file1_1) + _clean_test_file(file1_5) + _clean_test_file(file2_1) + _clean_test_file(file2_5) + + +def test_download_pairs_exception(default_conf, ticker_history, mocker, caplog): + mocker.patch('freqtrade.optimize.__init__.get_ticker_history', return_value=ticker_history) + mocker.patch('freqtrade.optimize.__init__.download_backtesting_testdata', + side_effect=BaseException('File Error')) + mocker.patch.dict('freqtrade.main._CONF', default_conf) + exchange._API = Bittrex({'key': '', 'secret': ''}) + + file1_1 = 'freqtrade/tests/testdata/BTC_MEME-1.json' + file1_5 = 'freqtrade/tests/testdata/BTC_MEME-5.json' + _backup_file(file1_1) + _backup_file(file1_5) + + download_pairs(pairs=['BTC-MEME']) + # clean files freshly downloaded + _clean_test_file(file1_1) + _clean_test_file(file1_5) + assert ('freqtrade.optimize.__init__', + logging.INFO, + 'Failed to download the pair: "BTC-MEME", Interval: 1 min' + ) in caplog.record_tuples + + +def test_download_backtesting_testdata(default_conf, ticker_history, mocker): + mocker.patch('freqtrade.optimize.__init__.get_ticker_history', return_value=ticker_history) + mocker.patch.dict('freqtrade.main._CONF', default_conf) + exchange._API = Bittrex({'key': '', 'secret': ''}) + + # Download a 1 min ticker file + file1 = 'freqtrade/tests/testdata/BTC_XEL-1.json' + _backup_file(file1) + download_backtesting_testdata(pair="BTC-XEL", interval=1) + assert os.path.isfile(file1) is True + _clean_test_file(file1) + + # Download a 5 min ticker file + file2 = 'freqtrade/tests/testdata/BTC_STORJ-5.json' + _backup_file(file2) + + download_backtesting_testdata(pair="BTC-STORJ", interval=5) + assert os.path.isfile(file2) is True + _clean_test_file(file2) diff --git a/freqtrade/tests/test_main.py b/freqtrade/tests/test_main.py index 037d6f836..f8bad9fa5 100644 --- a/freqtrade/tests/test_main.py +++ b/freqtrade/tests/test_main.py @@ -217,7 +217,7 @@ def test_handle_trade(default_conf, limit_buy_order, limit_sell_order, mocker): assert trade.close_date is not None -def test_handle_trade_experimental(default_conf, ticker, limit_buy_order, mocker, caplog): +def test_handle_trade_experimental(default_conf, ticker, mocker, caplog): default_conf.update({'experimental': {'use_sell_signal': True}}) mocker.patch.dict('freqtrade.main._CONF', default_conf)