Merge pull request #16 from freqtrade/develop

Update from upstream repo gcarq/freqtrade@develop
This commit is contained in:
Gert Wohlgemuth
2018-06-03 14:40:26 -07:00
committed by GitHub
33 changed files with 349 additions and 165 deletions

View File

@@ -393,6 +393,78 @@ def test_get_ticker_history(default_conf, mocker):
get_ticker_history('EFGH/BTC', default_conf['ticker_interval'])
def test_get_ticker_history_sort(default_conf, mocker):
api_mock = MagicMock()
# GDAX use-case (real data from GDAX)
# This ticker history is ordered DESC (newest first, oldest last)
tick = [
[1527833100000, 0.07666, 0.07671, 0.07666, 0.07668, 16.65244264],
[1527832800000, 0.07662, 0.07666, 0.07662, 0.07666, 1.30051526],
[1527832500000, 0.07656, 0.07661, 0.07656, 0.07661, 12.034778840000001],
[1527832200000, 0.07658, 0.07658, 0.07655, 0.07656, 0.59780186],
[1527831900000, 0.07658, 0.07658, 0.07658, 0.07658, 1.76278136],
[1527831600000, 0.07658, 0.07658, 0.07658, 0.07658, 2.22646521],
[1527831300000, 0.07655, 0.07657, 0.07655, 0.07657, 1.1753],
[1527831000000, 0.07654, 0.07654, 0.07651, 0.07651, 0.8073060299999999],
[1527830700000, 0.07652, 0.07652, 0.07651, 0.07652, 10.04822687],
[1527830400000, 0.07649, 0.07651, 0.07649, 0.07651, 2.5734867]
]
type(api_mock).has = PropertyMock(return_value={'fetchOHLCV': True})
api_mock.fetch_ohlcv = MagicMock(side_effect=make_fetch_ohlcv_mock(tick))
mocker.patch('freqtrade.exchange._API', api_mock)
# Test the ticker history sort
ticks = get_ticker_history('ETH/BTC', default_conf['ticker_interval'])
assert ticks[0][0] == 1527830400000
assert ticks[0][1] == 0.07649
assert ticks[0][2] == 0.07651
assert ticks[0][3] == 0.07649
assert ticks[0][4] == 0.07651
assert ticks[0][5] == 2.5734867
assert ticks[9][0] == 1527833100000
assert ticks[9][1] == 0.07666
assert ticks[9][2] == 0.07671
assert ticks[9][3] == 0.07666
assert ticks[9][4] == 0.07668
assert ticks[9][5] == 16.65244264
# Bittrex use-case (real data from Bittrex)
# This ticker history is ordered ASC (oldest first, newest last)
tick = [
[1527827700000, 0.07659999, 0.0766, 0.07627, 0.07657998, 1.85216924],
[1527828000000, 0.07657995, 0.07657995, 0.0763, 0.0763, 26.04051037],
[1527828300000, 0.0763, 0.07659998, 0.0763, 0.0764, 10.36434124],
[1527828600000, 0.0764, 0.0766, 0.0764, 0.0766, 5.71044773],
[1527828900000, 0.0764, 0.07666998, 0.0764, 0.07666998, 47.48888565],
[1527829200000, 0.0765, 0.07672999, 0.0765, 0.07672999, 3.37640326],
[1527829500000, 0.0766, 0.07675, 0.0765, 0.07675, 8.36203831],
[1527829800000, 0.07675, 0.07677999, 0.07620002, 0.076695, 119.22963884],
[1527830100000, 0.076695, 0.07671, 0.07624171, 0.07671, 1.80689244],
[1527830400000, 0.07671, 0.07674399, 0.07629216, 0.07655213, 2.31452783]
]
type(api_mock).has = PropertyMock(return_value={'fetchOHLCV': True})
api_mock.fetch_ohlcv = MagicMock(side_effect=make_fetch_ohlcv_mock(tick))
mocker.patch('freqtrade.exchange._API', api_mock)
# Test the ticker history sort
ticks = get_ticker_history('ETH/BTC', default_conf['ticker_interval'])
assert ticks[0][0] == 1527827700000
assert ticks[0][1] == 0.07659999
assert ticks[0][2] == 0.0766
assert ticks[0][3] == 0.07627
assert ticks[0][4] == 0.07657998
assert ticks[0][5] == 1.85216924
assert ticks[9][0] == 1527830400000
assert ticks[9][1] == 0.07671
assert ticks[9][2] == 0.07674399
assert ticks[9][3] == 0.07629216
assert ticks[9][4] == 0.07655213
assert ticks[9][5] == 2.31452783
def test_cancel_order_dry_run(default_conf, mocker):
default_conf['dry_run'] = True
mocker.patch.dict('freqtrade.exchange._CONF', default_conf)

View File

@@ -218,7 +218,8 @@ def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> Non
'--realistic-simulation',
'--refresh-pairs-cached',
'--timerange', ':100',
'--export', '/bar/foo'
'--export', '/bar/foo',
'--export-filename', 'foo_bar.json'
]
config = setup_configuration(get_args(args))
@@ -259,6 +260,11 @@ def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> Non
'Parameter --export detected: {} ...'.format(config['export']),
caplog.record_tuples
)
assert 'exportfilename' in config
assert log_has(
'Storing backtest results to {} ...'.format(config['exportfilename']),
caplog.record_tuples
)
def test_start(mocker, fee, default_conf, caplog) -> None:
@@ -286,23 +292,6 @@ def test_start(mocker, fee, default_conf, caplog) -> None:
assert start_mock.call_count == 1
def test_backtesting__init__(mocker, default_conf) -> None:
"""
Test Backtesting.__init__() method
"""
init_mock = MagicMock()
mocker.patch('freqtrade.optimize.backtesting.Backtesting._init', init_mock)
backtesting = Backtesting(default_conf)
assert backtesting.config == default_conf
assert backtesting.analyze is None
assert backtesting.ticker_interval is None
assert backtesting.tickerdata_to_dataframe is None
assert backtesting.populate_buy_trend is None
assert backtesting.populate_sell_trend is None
assert init_mock.call_count == 1
def test_backtesting_init(mocker, default_conf) -> None:
"""
Test Backtesting._init() method
@@ -374,16 +363,15 @@ def test_generate_text_table(default_conf, mocker):
)
result_str = (
'pair buy count avg profit % '
'total profit BTC avg duration profit loss\n'
'------- ----------- -------------- '
'------------------ -------------- -------- ------\n'
'ETH/BTC 2 15.00 '
'0.60000000 20.0 2 0\n'
'TOTAL 2 15.00 '
'0.60000000 20.0 2 0'
'| pair | buy count | avg profit % | '
'total profit BTC | avg duration | profit | loss |\n'
'|:--------|------------:|---------------:|'
'-------------------:|---------------:|---------:|-------:|\n'
'| ETH/BTC | 2 | 15.00 | '
'0.60000000 | 20.0 | 2 | 0 |\n'
'| TOTAL | 2 | 15.00 | '
'0.60000000 | 20.0 | 2 | 0 |'
)
assert backtesting._generate_text_table(data={'ETH/BTC': {}}, results=results) == result_str

View File

@@ -389,10 +389,12 @@ def test_start_uses_mongotrials(mocker, init_hyperopt, default_conf) -> None:
# test buy_strategy_generator def populate_buy_trend
# test optimizer if 'ro_t1' in params
def test_format_results():
def test_format_results(init_hyperopt):
"""
Test Hyperopt.format_results()
"""
# Test with BTC as stake_currency
trades = [
('ETH/BTC', 2, 2, 123),
('LTC/BTC', 1, 1, 123),
@@ -400,8 +402,21 @@ def test_format_results():
]
labels = ['currency', 'profit_percent', 'profit_BTC', 'duration']
df = pd.DataFrame.from_records(trades, columns=labels)
x = Hyperopt.format_results(df)
assert x.find(' 66.67%')
result = _HYPEROPT.format_results(df)
assert result.find(' 66.67%')
assert result.find('Total profit 1.00000000 BTC')
assert result.find('2.0000Σ %')
# Test with EUR as stake_currency
trades = [
('ETH/EUR', 2, 2, 123),
('LTC/EUR', 1, 1, 123),
('XPR/EUR', -1, -2, -246)
]
df = pd.DataFrame.from_records(trades, columns=labels)
result = _HYPEROPT.format_results(df)
assert result.find('Total profit 1.00000000 EUR')
def test_signal_handler(mocker, init_hyperopt):

View File

@@ -105,7 +105,8 @@ def test_load_data_with_new_pair_1min(ticker_history, mocker, caplog) -> None:
refresh_pairs=False,
pairs=['MEME/BTC'])
assert os.path.isfile(file) is False
assert log_has('No data for pair MEME/BTC, use --refresh-pairs-cached to download the data',
assert log_has('No data for pair: "MEME/BTC", Interval: 1m. '
'Use --refresh-pairs-cached to download the data',
caplog.record_tuples)
# download a new pair if refresh_pairs is set

View File

@@ -116,6 +116,12 @@ def test_parse_timerange_incorrect() -> None:
timerange = Arguments.parse_timerange('20100522-20150730')
assert timerange == (('date', 'date'), 1274486400, 1438214400)
# Added test for unix timestamp - BTC genesis date
assert (('date', None), 1231006505, None) == Arguments.parse_timerange('1231006505-')
assert ((None, 'date'), None, 1233360000) == Arguments.parse_timerange('-1233360000')
timerange = Arguments.parse_timerange('1231006505-1233360000')
assert timerange == (('date', 'date'), 1231006505, 1233360000)
with pytest.raises(Exception, match=r'Incorrect syntax.*'):
Arguments.parse_timerange('-')

View File

@@ -6,6 +6,7 @@ Unit test file for configuration.py
import json
from copy import deepcopy
from unittest.mock import MagicMock
from argparse import Namespace
import pytest
from jsonschema import ValidationError
@@ -37,7 +38,7 @@ def test_load_config_invalid_pair(default_conf) -> None:
conf['exchange']['pair_whitelist'].append('ETH-BTC')
with pytest.raises(ValidationError, match=r'.*does not match.*'):
configuration = Configuration([])
configuration = Configuration(Namespace())
configuration._validate_config(conf)
@@ -49,7 +50,7 @@ def test_load_config_missing_attributes(default_conf) -> None:
conf.pop('exchange')
with pytest.raises(ValidationError, match=r'.*\'exchange\' is a required property.*'):
configuration = Configuration([])
configuration = Configuration(Namespace())
configuration._validate_config(conf)
@@ -61,7 +62,7 @@ def test_load_config_file(default_conf, mocker, caplog) -> None:
read_data=json.dumps(default_conf)
))
configuration = Configuration([])
configuration = Configuration(Namespace())
validated_conf = configuration._load_config_file('somefile')
assert file_mock.call_count == 1
assert validated_conf.items() >= default_conf.items()
@@ -79,7 +80,7 @@ def test_load_config_max_open_trades_zero(default_conf, mocker, caplog) -> None:
read_data=json.dumps(conf)
))
Configuration([])._load_config_file('somefile')
Configuration(Namespace())._load_config_file('somefile')
assert file_mock.call_count == 1
assert log_has('Validating configuration ...', caplog.record_tuples)
@@ -92,7 +93,7 @@ def test_load_config_file_exception(mocker, caplog) -> None:
'freqtrade.configuration.open',
MagicMock(side_effect=FileNotFoundError('File not found'))
)
configuration = Configuration([])
configuration = Configuration(Namespace())
with pytest.raises(SystemExit):
configuration._load_config_file('somefile')
@@ -128,13 +129,13 @@ def test_load_config_with_params(default_conf, mocker) -> None:
read_data=json.dumps(default_conf)
))
args = [
arglist = [
'--dynamic-whitelist', '10',
'--strategy', 'TestStrategy',
'--strategy-path', '/some/path',
'--dry-run-db',
]
args = Arguments(args, '').get_parsed_arg()
args = Arguments(arglist, '').get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
@@ -174,12 +175,12 @@ def test_show_info(default_conf, mocker, caplog) -> None:
read_data=json.dumps(default_conf)
))
args = [
arglist = [
'--dynamic-whitelist', '10',
'--strategy', 'TestStrategy',
'--dry-run-db'
]
args = Arguments(args, '').get_parsed_arg()
args = Arguments(arglist, '').get_parsed_arg()
configuration = Configuration(args)
configuration.get_config()
@@ -202,8 +203,8 @@ def test_show_info(default_conf, mocker, caplog) -> None:
)
# Test the Dry run condition
configuration.config.update({'dry_run': False})
configuration._load_common_config(configuration.config)
configuration.config.update({'dry_run': False}) # type: ignore
configuration._load_common_config(configuration.config) # type: ignore
assert log_has(
'Dry run is disabled. (--dry_run_db ignored)',
caplog.record_tuples
@@ -218,13 +219,13 @@ def test_setup_configuration_without_arguments(mocker, default_conf, caplog) ->
read_data=json.dumps(default_conf)
))
args = [
arglist = [
'--config', 'config.json',
'--strategy', 'DefaultStrategy',
'backtesting'
]
args = Arguments(args, '').get_parsed_arg()
args = Arguments(arglist, '').get_parsed_arg()
configuration = Configuration(args)
config = configuration.get_config()
@@ -262,7 +263,7 @@ def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> Non
read_data=json.dumps(default_conf)
))
args = [
arglist = [
'--config', 'config.json',
'--strategy', 'DefaultStrategy',
'--datadir', '/foo/bar',
@@ -275,7 +276,7 @@ def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> Non
'--export', '/bar/foo'
]
args = Arguments(args, '').get_parsed_arg()
args = Arguments(arglist, '').get_parsed_arg()
configuration = Configuration(args)
config = configuration.get_config()
@@ -326,14 +327,14 @@ def test_hyperopt_with_arguments(mocker, default_conf, caplog) -> None:
read_data=json.dumps(default_conf)
))
args = [
arglist = [
'hyperopt',
'--epochs', '10',
'--use-mongodb',
'--spaces', 'all',
]
args = Arguments(args, '').get_parsed_arg()
args = Arguments(arglist, '').get_parsed_arg()
configuration = Configuration(args)
config = configuration.get_config()
@@ -357,7 +358,7 @@ def test_check_exchange(default_conf) -> None:
Test the configuration validator with a missing attribute
"""
conf = deepcopy(default_conf)
configuration = Configuration([])
configuration = Configuration(Namespace())
# Test a valid exchange
conf.get('exchange').update({'name': 'BITTREX'})

View File

@@ -126,6 +126,20 @@ def test_fiat_convert_get_price(mocker):
assert fiat_convert._pairs[0]._expiration is not expiration
def test_fiat_convert_same_currencies(mocker):
patch_coinmarketcap(mocker)
fiat_convert = CryptoToFiatConverter()
assert fiat_convert.get_price(crypto_symbol='USD', fiat_symbol='USD') == 1.0
def test_fiat_convert_two_FIAT(mocker):
patch_coinmarketcap(mocker)
fiat_convert = CryptoToFiatConverter()
assert fiat_convert.get_price(crypto_symbol='USD', fiat_symbol='EUR') == 0.0
def test_loadcryptomap(mocker):
patch_coinmarketcap(mocker)