Merge branch 'develop' into python-version

This commit is contained in:
hroff-1902
2019-05-29 20:07:46 +03:00
committed by GitHub
54 changed files with 1199 additions and 835 deletions

View File

@@ -2,8 +2,7 @@
import logging
from freqtrade.data.converter import parse_ticker_dataframe, ohlcv_fill_up_missing_data
from freqtrade.data.history import load_pair_history
from freqtrade.optimize import validate_backtest_data, get_timeframe
from freqtrade.data.history import load_pair_history, validate_backtest_data, get_timeframe
from freqtrade.tests.conftest import log_has

View File

@@ -2,24 +2,25 @@
import json
import os
from pathlib import Path
import uuid
from pathlib import Path
from shutil import copyfile
import arrow
from pandas import DataFrame
import pytest
from pandas import DataFrame
from freqtrade import OperationalException
from freqtrade.arguments import TimeRange
from freqtrade.data import history
from freqtrade.data.history import (download_pair_history,
load_cached_data_for_updating,
load_tickerdata_file,
make_testdata_path,
load_tickerdata_file, make_testdata_path,
trim_tickerlist)
from freqtrade.exchange import timeframe_to_minutes
from freqtrade.misc import file_dump_json
from freqtrade.tests.conftest import get_patched_exchange, log_has
from freqtrade.strategy.default_strategy import DefaultStrategy
from freqtrade.tests.conftest import get_patched_exchange, log_has, patch_exchange
# Change this if modifying UNITTEST/BTC testdatafile
_BTC_UNITTEST_LENGTH = 13681
@@ -59,7 +60,11 @@ def _clean_test_file(file: str) -> None:
def test_load_data_30min_ticker(mocker, caplog, default_conf) -> None:
ld = history.load_pair_history(pair='UNITTEST/BTC', ticker_interval='30m', datadir=None)
assert isinstance(ld, DataFrame)
assert not log_has('Download the pair: "UNITTEST/BTC", Interval: 30m', caplog.record_tuples)
assert not log_has(
'Download history data for pair: "UNITTEST/BTC", interval: 30m '
'and store in None.',
caplog.record_tuples
)
def test_load_data_7min_ticker(mocker, caplog, default_conf) -> None:
@@ -67,7 +72,7 @@ def test_load_data_7min_ticker(mocker, caplog, default_conf) -> None:
assert not isinstance(ld, DataFrame)
assert ld is None
assert log_has(
'No data for pair: "UNITTEST/BTC", Interval: 7m. '
'No history data for pair: "UNITTEST/BTC", interval: 7m. '
'Use --refresh-pairs-cached option or download_backtest_data.py '
'script to download the data',
caplog.record_tuples
@@ -80,7 +85,11 @@ def test_load_data_1min_ticker(ticker_history, mocker, caplog) -> None:
_backup_file(file, copy_file=True)
history.load_data(datadir=None, ticker_interval='1m', pairs=['UNITTEST/BTC'])
assert os.path.isfile(file) is True
assert not log_has('Download the pair: "UNITTEST/BTC", Interval: 1m', caplog.record_tuples)
assert not log_has(
'Download history data for pair: "UNITTEST/BTC", interval: 1m '
'and store in None.',
caplog.record_tuples
)
_clean_test_file(file)
@@ -100,7 +109,7 @@ def test_load_data_with_new_pair_1min(ticker_history_list, mocker, caplog, defau
pair='MEME/BTC')
assert os.path.isfile(file) is False
assert log_has(
'No data for pair: "MEME/BTC", Interval: 1m. '
'No history data for pair: "MEME/BTC", interval: 1m. '
'Use --refresh-pairs-cached option or download_backtest_data.py '
'script to download the data',
caplog.record_tuples
@@ -113,7 +122,11 @@ def test_load_data_with_new_pair_1min(ticker_history_list, mocker, caplog, defau
exchange=exchange,
pair='MEME/BTC')
assert os.path.isfile(file) is True
assert log_has('Download the pair: "MEME/BTC", Interval: 1m', caplog.record_tuples)
assert log_has(
'Download history data for pair: "MEME/BTC", interval: 1m '
'and store in None.',
caplog.record_tuples
)
with pytest.raises(OperationalException, match=r'Exchange needs to be initialized when.*'):
history.load_pair_history(datadir=None,
ticker_interval='1m',
@@ -293,7 +306,7 @@ def test_download_pair_history2(mocker, default_conf) -> None:
def test_download_backtesting_data_exception(ticker_history, mocker, caplog, default_conf) -> None:
mocker.patch('freqtrade.exchange.Exchange.get_history',
side_effect=BaseException('File Error'))
side_effect=Exception('File Error'))
exchange = get_patched_exchange(mocker, default_conf)
@@ -308,7 +321,11 @@ def test_download_backtesting_data_exception(ticker_history, mocker, caplog, def
# clean files freshly downloaded
_clean_test_file(file1_1)
_clean_test_file(file1_5)
assert log_has('Failed to download the pair: "MEME/BTC", Interval: 1m', caplog.record_tuples)
assert log_has(
'Failed to download history data for pair: "MEME/BTC", interval: 1m. '
'Error: File Error',
caplog.record_tuples
)
def test_load_tickerdata_file() -> None:
@@ -479,3 +496,62 @@ def test_file_dump_json_tofile() -> None:
# Remove the file
_clean_test_file(file)
def test_get_timeframe(default_conf, mocker) -> None:
patch_exchange(mocker)
strategy = DefaultStrategy(default_conf)
data = strategy.tickerdata_to_dataframe(
history.load_data(
datadir=None,
ticker_interval='1m',
pairs=['UNITTEST/BTC']
)
)
min_date, max_date = history.get_timeframe(data)
assert min_date.isoformat() == '2017-11-04T23:02:00+00:00'
assert max_date.isoformat() == '2017-11-14T22:58:00+00:00'
def test_validate_backtest_data_warn(default_conf, mocker, caplog) -> None:
patch_exchange(mocker)
strategy = DefaultStrategy(default_conf)
data = strategy.tickerdata_to_dataframe(
history.load_data(
datadir=None,
ticker_interval='1m',
pairs=['UNITTEST/BTC'],
fill_up_missing=False
)
)
min_date, max_date = history.get_timeframe(data)
caplog.clear()
assert history.validate_backtest_data(data, min_date, max_date,
timeframe_to_minutes('1m'))
assert len(caplog.record_tuples) == 1
assert log_has(
"UNITTEST/BTC has missing frames: expected 14396, got 13680, that's 716 missing values",
caplog.record_tuples)
def test_validate_backtest_data(default_conf, mocker, caplog) -> None:
patch_exchange(mocker)
strategy = DefaultStrategy(default_conf)
timerange = TimeRange('index', 'index', 200, 250)
data = strategy.tickerdata_to_dataframe(
history.load_data(
datadir=None,
ticker_interval='5m',
pairs=['UNITTEST/BTC'],
timerange=timerange
)
)
min_date, max_date = history.get_timeframe(data)
caplog.clear()
assert not history.validate_backtest_data(data, min_date, max_date,
timeframe_to_minutes('5m'))
assert len(caplog.record_tuples) == 0

View File

@@ -10,10 +10,11 @@ import numpy as np
import pytest
from pandas import DataFrame, to_datetime
from freqtrade import OperationalException
from freqtrade.data.converter import parse_ticker_dataframe
from freqtrade.edge import Edge, PairInfo
from freqtrade.strategy.interface import SellType
from freqtrade.tests.conftest import get_patched_freqtradebot
from freqtrade.tests.conftest import get_patched_freqtradebot, log_has
from freqtrade.tests.optimize import (BTContainer, BTrade,
_build_backtest_dataframe,
_get_frame_time_from_offset)
@@ -30,7 +31,50 @@ ticker_start_time = arrow.get(2018, 10, 3)
ticker_interval_in_minute = 60
_ohlc = {'date': 0, 'buy': 1, 'open': 2, 'high': 3, 'low': 4, 'close': 5, 'sell': 6, 'volume': 7}
# Helpers for this test file
def _validate_ohlc(buy_ohlc_sell_matrice):
for index, ohlc in enumerate(buy_ohlc_sell_matrice):
# if not high < open < low or not high < close < low
if not ohlc[3] >= ohlc[2] >= ohlc[4] or not ohlc[3] >= ohlc[5] >= ohlc[4]:
raise Exception('Line ' + str(index + 1) + ' of ohlc has invalid values!')
return True
def _build_dataframe(buy_ohlc_sell_matrice):
_validate_ohlc(buy_ohlc_sell_matrice)
tickers = []
for ohlc in buy_ohlc_sell_matrice:
ticker = {
'date': ticker_start_time.shift(
minutes=(
ohlc[0] *
ticker_interval_in_minute)).timestamp *
1000,
'buy': ohlc[1],
'open': ohlc[2],
'high': ohlc[3],
'low': ohlc[4],
'close': ohlc[5],
'sell': ohlc[6]}
tickers.append(ticker)
frame = DataFrame(tickers)
frame['date'] = to_datetime(frame['date'],
unit='ms',
utc=True,
infer_datetime_format=True)
return frame
def _time_on_candle(number):
return np.datetime64(ticker_start_time.shift(
minutes=(number * ticker_interval_in_minute)).timestamp * 1000, 'ms')
# End helper functions
# Open trade should be removed from the end
tc0 = BTContainer(data=[
# D O H L C V B S
@@ -203,46 +247,6 @@ def test_nonexisting_stake_amount(mocker, edge_conf):
assert edge.stake_amount('N/O', 1, 2, 1) == 0.15
def _validate_ohlc(buy_ohlc_sell_matrice):
for index, ohlc in enumerate(buy_ohlc_sell_matrice):
# if not high < open < low or not high < close < low
if not ohlc[3] >= ohlc[2] >= ohlc[4] or not ohlc[3] >= ohlc[5] >= ohlc[4]:
raise Exception('Line ' + str(index + 1) + ' of ohlc has invalid values!')
return True
def _build_dataframe(buy_ohlc_sell_matrice):
_validate_ohlc(buy_ohlc_sell_matrice)
tickers = []
for ohlc in buy_ohlc_sell_matrice:
ticker = {
'date': ticker_start_time.shift(
minutes=(
ohlc[0] *
ticker_interval_in_minute)).timestamp *
1000,
'buy': ohlc[1],
'open': ohlc[2],
'high': ohlc[3],
'low': ohlc[4],
'close': ohlc[5],
'sell': ohlc[6]}
tickers.append(ticker)
frame = DataFrame(tickers)
frame['date'] = to_datetime(frame['date'],
unit='ms',
utc=True,
infer_datetime_format=True)
return frame
def _time_on_candle(number):
return np.datetime64(ticker_start_time.shift(
minutes=(number * ticker_interval_in_minute)).timestamp * 1000, 'ms')
def test_edge_heartbeat_calculate(mocker, edge_conf):
freqtrade = get_patched_freqtradebot(mocker, edge_conf)
edge = Edge(edge_conf, freqtrade.exchange, freqtrade.strategy)
@@ -298,6 +302,40 @@ def test_edge_process_downloaded_data(mocker, edge_conf):
assert edge._last_updated <= arrow.utcnow().timestamp + 2
def test_edge_process_no_data(mocker, edge_conf, caplog):
edge_conf['datadir'] = None
freqtrade = get_patched_freqtradebot(mocker, edge_conf)
mocker.patch('freqtrade.exchange.Exchange.get_fee', MagicMock(return_value=0.001))
mocker.patch('freqtrade.data.history.load_data', MagicMock(return_value={}))
edge = Edge(edge_conf, freqtrade.exchange, freqtrade.strategy)
assert not edge.calculate()
assert len(edge._cached_pairs) == 0
assert log_has("No data found. Edge is stopped ...", caplog.record_tuples)
assert edge._last_updated == 0
def test_edge_process_no_trades(mocker, edge_conf, caplog):
edge_conf['datadir'] = None
freqtrade = get_patched_freqtradebot(mocker, edge_conf)
mocker.patch('freqtrade.exchange.Exchange.get_fee', MagicMock(return_value=0.001))
mocker.patch('freqtrade.data.history.load_data', mocked_load_data)
# Return empty
mocker.patch('freqtrade.edge.Edge._find_trades_for_stoploss_range', MagicMock(return_value=[]))
edge = Edge(edge_conf, freqtrade.exchange, freqtrade.strategy)
assert not edge.calculate()
assert len(edge._cached_pairs) == 0
assert log_has("No trades found.", caplog.record_tuples)
def test_edge_init_error(mocker, edge_conf,):
edge_conf['stake_amount'] = 0.5
mocker.patch('freqtrade.exchange.Exchange.get_fee', MagicMock(return_value=0.001))
with pytest.raises(OperationalException, match='Edge works only with unlimited stake amount'):
get_patched_freqtradebot(mocker, edge_conf)
def test_process_expectancy(mocker, edge_conf):
edge_conf['edge']['min_trade_number'] = 2
freqtrade = get_patched_freqtradebot(mocker, edge_conf)
@@ -360,3 +398,11 @@ def test_process_expectancy(mocker, edge_conf):
assert round(final['TEST/BTC'].risk_reward_ratio, 10) == 306.5384615384
assert round(final['TEST/BTC'].required_risk_reward, 10) == 2.0
assert round(final['TEST/BTC'].expectancy, 10) == 101.5128205128
# Pop last item so no trade is profitable
trades.pop()
trades_df = DataFrame(trades)
trades_df = edge._fill_calculable_fields(trades_df)
final = edge._process_expectancy(trades_df)
assert len(final) == 0
assert isinstance(final, dict)

View File

@@ -1016,7 +1016,7 @@ def test_refresh_latest_ohlcv(mocker, default_conf, caplog) -> None:
exchange.refresh_latest_ohlcv([('IOTA/ETH', '5m'), ('XRP/ETH', '5m')])
assert exchange._api_async.fetch_ohlcv.call_count == 2
assert log_has(f"Using cached ohlcv data for {pairs[0][0]}, {pairs[0][1]} ...",
assert log_has(f"Using cached ohlcv data for pair {pairs[0][0]}, interval {pairs[0][1]} ...",
caplog.record_tuples)

View File

@@ -2,17 +2,17 @@
import logging
from unittest.mock import MagicMock
from pandas import DataFrame
import pytest
from pandas import DataFrame
from freqtrade.optimize import get_timeframe
from freqtrade.data.history import get_timeframe
from freqtrade.optimize.backtesting import Backtesting
from freqtrade.strategy.interface import SellType
from freqtrade.tests.optimize import (BTrade, BTContainer, _build_backtest_dataframe,
_get_frame_time_from_offset, tests_ticker_interval)
from freqtrade.tests.conftest import patch_exchange
from freqtrade.tests.optimize import (BTContainer, BTrade,
_build_backtest_dataframe,
_get_frame_time_from_offset,
tests_ticker_interval)
# Test 1 Minus 8% Close
# Test with Stop-loss at 1%

View File

@@ -17,9 +17,9 @@ 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)
from freqtrade.data.history import get_timeframe
from freqtrade.optimize import setup_configuration, start_backtesting
from freqtrade.optimize.backtesting import Backtesting
from freqtrade.state import RunMode
from freqtrade.strategy.default_strategy import DefaultStrategy
from freqtrade.strategy.interface import SellType
@@ -33,7 +33,7 @@ def get_args(args) -> List[str]:
def trim_dictlist(dict_list, num):
new = {}
for pair, pair_data in dict_list.items():
new[pair] = pair_data[num:]
new[pair] = pair_data[num:].reset_index()
return new
@@ -178,7 +178,7 @@ def test_setup_configuration_without_arguments(mocker, default_conf, caplog) ->
'backtesting'
]
config = setup_configuration(get_args(args))
config = setup_configuration(get_args(args), RunMode.BACKTEST)
assert 'max_open_trades' in config
assert 'stake_currency' in config
assert 'stake_amount' in config
@@ -228,7 +228,7 @@ def test_setup_bt_configuration_with_arguments(mocker, default_conf, caplog) ->
'--export-filename', 'foo_bar.json'
]
config = setup_configuration(get_args(args))
config = setup_configuration(get_args(args), RunMode.BACKTEST)
assert 'max_open_trades' in config
assert 'stake_currency' in config
assert 'stake_amount' in config
@@ -290,7 +290,7 @@ def test_setup_configuration_unlimited_stake_amount(mocker, default_conf, caplog
]
with pytest.raises(DependencyException, match=r'.*stake amount.*'):
setup_configuration(get_args(args))
setup_configuration(get_args(args), RunMode.BACKTEST)
def test_start(mocker, fee, default_conf, caplog) -> None:
@@ -307,7 +307,7 @@ def test_start(mocker, fee, default_conf, caplog) -> None:
'backtesting'
]
args = get_args(args)
start(args)
start_backtesting(args)
assert log_has(
'Starting freqtrade in Backtesting mode',
caplog.record_tuples
@@ -472,7 +472,7 @@ def test_backtesting_start(default_conf, mocker, caplog) -> None:
return Arrow(2017, 11, 14, 21, 17), Arrow(2017, 11, 14, 22, 59)
mocker.patch('freqtrade.data.history.load_data', mocked_load_data)
mocker.patch('freqtrade.optimize.get_timeframe', get_timeframe)
mocker.patch('freqtrade.data.history.get_timeframe', get_timeframe)
mocker.patch('freqtrade.exchange.Exchange.refresh_latest_ohlcv', MagicMock())
patch_exchange(mocker)
mocker.patch.multiple(
@@ -495,7 +495,7 @@ def test_backtesting_start(default_conf, mocker, caplog) -> None:
'Using local backtesting data (using whitelist in given config) ...',
'Using stake_currency: BTC ...',
'Using stake_amount: 0.001 ...',
'Measuring data from 2017-11-14T21:17:00+00:00 '
'Backtesting with data from 2017-11-14T21:17:00+00:00 '
'up to 2017-11-14T22:59:00+00:00 (0 days)..'
]
for line in exists:
@@ -507,7 +507,7 @@ def test_backtesting_start_no_data(default_conf, mocker, caplog) -> None:
return Arrow(2017, 11, 14, 21, 17), Arrow(2017, 11, 14, 22, 59)
mocker.patch('freqtrade.data.history.load_data', MagicMock(return_value={}))
mocker.patch('freqtrade.optimize.get_timeframe', get_timeframe)
mocker.patch('freqtrade.data.history.get_timeframe', get_timeframe)
mocker.patch('freqtrade.exchange.Exchange.refresh_latest_ohlcv', MagicMock())
patch_exchange(mocker)
mocker.patch.multiple(
@@ -708,7 +708,7 @@ def test_backtest_multi_pair(default_conf, fee, mocker, tres, pair):
data = trim_dictlist(data, -500)
# Remove data for one pair from the beginning of the data
data[pair] = data[pair][tres:]
data[pair] = data[pair][tres:].reset_index()
# We need to enable sell-signal - otherwise it sells on ROI!!
default_conf['experimental'] = {"use_sell_signal": True}
default_conf['ticker_interval'] = '5m'
@@ -847,7 +847,7 @@ def test_backtest_start_live(default_conf, mocker, caplog):
'--disable-max-market-positions'
]
args = get_args(args)
start(args)
start_backtesting(args)
# check the logs, that will contain the backtest result
exists = [
'Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...',
@@ -858,7 +858,8 @@ def test_backtest_start_live(default_conf, mocker, caplog):
'Using stake_currency: BTC ...',
'Using stake_amount: 0.001 ...',
'Downloading data for all pairs in whitelist ...',
'Measuring data from 2017-11-14T19:31:00+00:00 up to 2017-11-14T22:58:00+00:00 (0 days)..',
'Backtesting with data from 2017-11-14T19:31:00+00:00 '
'up to 2017-11-14T22:58:00+00:00 (0 days)..',
'Parameter --enable-position-stacking detected ...'
]
@@ -900,7 +901,7 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog):
'TestStrategy',
]
args = get_args(args)
start(args)
start_backtesting(args)
# 2 backtests, 4 tables
assert backtestmock.call_count == 2
assert gen_table_mock.call_count == 4
@@ -916,7 +917,8 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog):
'Using stake_currency: BTC ...',
'Using stake_amount: 0.001 ...',
'Downloading data for all pairs in whitelist ...',
'Measuring data from 2017-11-14T19:31:00+00:00 up to 2017-11-14T22:58:00+00:00 (0 days)..',
'Backtesting with data from 2017-11-14T19:31:00+00:00 '
'up to 2017-11-14T22:58:00+00:00 (0 days)..',
'Parameter --enable-position-stacking detected ...',
'Running backtesting for Strategy DefaultStrategy',
'Running backtesting for Strategy TestStrategy',

View File

@@ -7,7 +7,8 @@ from unittest.mock import MagicMock
from freqtrade.arguments import Arguments
from freqtrade.edge import PairInfo
from freqtrade.optimize.edge_cli import EdgeCli, setup_configuration, start
from freqtrade.optimize import start_edge, setup_configuration
from freqtrade.optimize.edge_cli import EdgeCli
from freqtrade.state import RunMode
from freqtrade.tests.conftest import log_has, log_has_re, patch_exchange
@@ -27,8 +28,8 @@ def test_setup_configuration_without_arguments(mocker, default_conf, caplog) ->
'edge'
]
config = setup_configuration(get_args(args))
assert config['runmode'] == RunMode.EDGECLI
config = setup_configuration(get_args(args), RunMode.EDGE)
assert config['runmode'] == RunMode.EDGE
assert 'max_open_trades' in config
assert 'stake_currency' in config
@@ -67,14 +68,14 @@ def test_setup_edge_configuration_with_arguments(mocker, edge_conf, caplog) -> N
'--stoplosses=-0.01,-0.10,-0.001'
]
config = setup_configuration(get_args(args))
config = setup_configuration(get_args(args), RunMode.EDGE)
assert 'max_open_trades' in config
assert 'stake_currency' in config
assert 'stake_amount' in config
assert 'exchange' in config
assert 'pair_whitelist' in config['exchange']
assert 'datadir' in config
assert config['runmode'] == RunMode.EDGECLI
assert config['runmode'] == RunMode.EDGE
assert log_has(
'Using data folder: {} ...'.format(config['datadir']),
caplog.record_tuples
@@ -106,7 +107,7 @@ def test_start(mocker, fee, edge_conf, caplog) -> None:
'edge'
]
args = get_args(args)
start(args)
start_edge(args)
assert log_has(
'Starting freqtrade in Edge mode',
caplog.record_tuples

View File

@@ -3,6 +3,7 @@ import json
import os
from datetime import datetime
from unittest.mock import MagicMock
from filelock import Timeout
import pandas as pd
import pytest
@@ -11,8 +12,9 @@ from freqtrade import DependencyException
from freqtrade.data.converter import parse_ticker_dataframe
from freqtrade.data.history import load_tickerdata_file
from freqtrade.optimize.default_hyperopt import DefaultHyperOpts
from freqtrade.optimize.hyperopt import Hyperopt, setup_configuration, start
from freqtrade.resolvers import HyperOptResolver
from freqtrade.optimize.hyperopt import Hyperopt, HYPEROPT_LOCKFILE
from freqtrade.optimize import setup_configuration, start_hyperopt
from freqtrade.resolvers.hyperopt_resolver import HyperOptResolver
from freqtrade.state import RunMode
from freqtrade.tests.conftest import log_has, log_has_re, patch_exchange
from freqtrade.tests.optimize.test_backtesting import get_args
@@ -52,7 +54,7 @@ def test_setup_hyperopt_configuration_without_arguments(mocker, default_conf, ca
'hyperopt'
]
config = setup_configuration(get_args(args))
config = setup_configuration(get_args(args), RunMode.HYPEROPT)
assert 'max_open_trades' in config
assert 'stake_currency' in config
assert 'stake_amount' in config
@@ -100,7 +102,7 @@ def test_setup_hyperopt_configuration_with_arguments(mocker, default_conf, caplo
'--print-all'
]
config = setup_configuration(get_args(args))
config = setup_configuration(get_args(args), RunMode.HYPEROPT)
assert 'max_open_trades' in config
assert 'stake_currency' in config
assert 'stake_amount' in config
@@ -183,7 +185,7 @@ def test_start(mocker, default_conf, caplog) -> None:
'--epochs', '5'
]
args = get_args(args)
start(args)
start_hyperopt(args)
import pprint
pprint.pprint(caplog.record_tuples)
@@ -195,6 +197,33 @@ def test_start(mocker, default_conf, caplog) -> None:
assert start_mock.call_count == 1
def test_start_no_data(mocker, default_conf, caplog) -> None:
mocker.patch(
'freqtrade.configuration.Configuration._load_config_file',
lambda *args, **kwargs: default_conf
)
mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock(return_value={}))
mocker.patch(
'freqtrade.optimize.hyperopt.get_timeframe',
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))
)
patch_exchange(mocker)
args = [
'--config', 'config.json',
'hyperopt',
'--epochs', '5'
]
args = get_args(args)
start_hyperopt(args)
import pprint
pprint.pprint(caplog.record_tuples)
assert log_has('No data found. Terminating.', caplog.record_tuples)
def test_start_failure(mocker, default_conf, caplog) -> None:
start_mock = MagicMock()
mocker.patch(
@@ -212,13 +241,35 @@ def test_start_failure(mocker, default_conf, caplog) -> None:
]
args = get_args(args)
with pytest.raises(DependencyException):
start(args)
start_hyperopt(args)
assert log_has(
"Please don't use --strategy for hyperopt.",
caplog.record_tuples
)
def test_start_filelock(mocker, default_conf, caplog) -> None:
start_mock = MagicMock(side_effect=Timeout(HYPEROPT_LOCKFILE))
mocker.patch(
'freqtrade.configuration.Configuration._load_config_file',
lambda *args, **kwargs: default_conf
)
mocker.patch('freqtrade.optimize.hyperopt.Hyperopt.start', start_mock)
patch_exchange(mocker)
args = [
'--config', 'config.json',
'hyperopt',
'--epochs', '5'
]
args = get_args(args)
start_hyperopt(args)
assert log_has(
"Another running instance of freqtrade Hyperopt detected.",
caplog.record_tuples
)
def test_loss_calculation_prefer_correct_trade_count(hyperopt) -> None:
correct = hyperopt.calculate_loss(1, hyperopt.target_trades, 20)
@@ -249,11 +300,12 @@ def test_log_results_if_loss_improves(hyperopt, capsys) -> None:
'loss': 1,
'current_tries': 1,
'total_tries': 2,
'result': 'foo'
'result': 'foo.',
'initial_point': False
}
)
out, err = capsys.readouterr()
assert ' 1/2: foo. Loss 1.00000' in out
assert ' 2/2: foo. Objective: 1.00000' in out
def test_no_log_if_loss_does_not_improve(hyperopt, caplog) -> None:
@@ -309,6 +361,11 @@ def test_roi_table_generation(hyperopt) -> None:
def test_start_calls_optimizer(mocker, default_conf, caplog) -> None:
dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock())
mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock())
mocker.patch(
'freqtrade.optimize.hyperopt.get_timeframe',
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))
)
parallel = mocker.patch(
'freqtrade.optimize.hyperopt.Hyperopt.run_optimizer_parallel',
MagicMock(return_value=[{'loss': 1, 'result': 'foo result', 'params': {}}])
@@ -459,7 +516,7 @@ def test_generate_optimizer(mocker, default_conf) -> None:
response_expected = {
'loss': 1.9840569076926293,
'result': ' 1 trades. Avg profit 2.31%. Total profit 0.00023300 BTC '
'(0.0231Σ%). Avg duration 100.0 mins.',
'( 2.31Σ%). Avg duration 100.0 mins.',
'params': optimizer_param
}

View File

@@ -1,66 +0,0 @@
# pragma pylint: disable=missing-docstring, protected-access, C0103
from freqtrade import optimize
from freqtrade.arguments import TimeRange
from freqtrade.data import history
from freqtrade.exchange import timeframe_to_minutes
from freqtrade.strategy.default_strategy import DefaultStrategy
from freqtrade.tests.conftest import log_has, patch_exchange
def test_get_timeframe(default_conf, mocker) -> None:
patch_exchange(mocker)
strategy = DefaultStrategy(default_conf)
data = strategy.tickerdata_to_dataframe(
history.load_data(
datadir=None,
ticker_interval='1m',
pairs=['UNITTEST/BTC']
)
)
min_date, max_date = optimize.get_timeframe(data)
assert min_date.isoformat() == '2017-11-04T23:02:00+00:00'
assert max_date.isoformat() == '2017-11-14T22:58:00+00:00'
def test_validate_backtest_data_warn(default_conf, mocker, caplog) -> None:
patch_exchange(mocker)
strategy = DefaultStrategy(default_conf)
data = strategy.tickerdata_to_dataframe(
history.load_data(
datadir=None,
ticker_interval='1m',
pairs=['UNITTEST/BTC'],
fill_up_missing=False
)
)
min_date, max_date = optimize.get_timeframe(data)
caplog.clear()
assert optimize.validate_backtest_data(data, min_date, max_date,
timeframe_to_minutes('1m'))
assert len(caplog.record_tuples) == 1
assert log_has(
"UNITTEST/BTC has missing frames: expected 14396, got 13680, that's 716 missing values",
caplog.record_tuples)
def test_validate_backtest_data(default_conf, mocker, caplog) -> None:
patch_exchange(mocker)
strategy = DefaultStrategy(default_conf)
timerange = TimeRange('index', 'index', 200, 250)
data = strategy.tickerdata_to_dataframe(
history.load_data(
datadir=None,
ticker_interval='5m',
pairs=['UNITTEST/BTC'],
timerange=timerange
)
)
min_date, max_date = optimize.get_timeframe(data)
caplog.clear()
assert not optimize.validate_backtest_data(data, min_date, max_date,
timeframe_to_minutes('5m'))
assert len(caplog.record_tuples) == 0

View File

@@ -47,12 +47,14 @@ def test_rpc_trade_status(default_conf, ticker, fee, markets, mocker) -> None:
freqtradebot.create_trade()
results = rpc._rpc_trade_status()
assert {
'trade_id': 1,
'pair': 'ETH/BTC',
'base_currency': 'BTC',
'date': ANY,
'open_date': ANY,
'open_date_hum': ANY,
'close_date': None,
'close_date_hum': None,
'open_rate': 1.099e-05,
'close_rate': None,
'current_rate': 1.098e-05,
@@ -78,7 +80,10 @@ def test_rpc_trade_status(default_conf, ticker, fee, markets, mocker) -> None:
'trade_id': 1,
'pair': 'ETH/BTC',
'base_currency': 'BTC',
'date': ANY,
'open_date': ANY,
'open_date_hum': ANY,
'close_date': None,
'close_date_hum': None,
'open_rate': 1.099e-05,
'close_rate': None,
'current_rate': ANY,
@@ -114,7 +119,7 @@ def test_rpc_status_table(default_conf, ticker, fee, markets, mocker) -> None:
freqtradebot.create_trade()
result = rpc._rpc_status_table()
assert 'just now' in result['Since'].all()
assert 'instantly' in result['Since'].all()
assert 'ETH/BTC' in result['Pair'].all()
assert '-0.59%' in result['Profit'].all()
@@ -123,7 +128,7 @@ def test_rpc_status_table(default_conf, ticker, fee, markets, mocker) -> None:
# invalidate ticker cache
rpc._freqtrade.exchange._cached_ticker = {}
result = rpc._rpc_status_table()
assert 'just now' in result['Since'].all()
assert 'instantly' in result['Since'].all()
assert 'ETH/BTC' in result['Pair'].all()
assert 'nan%' in result['Profit'].all()

View File

@@ -192,7 +192,10 @@ def test_status(default_conf, update, mocker, fee, ticker, markets) -> None:
'trade_id': 1,
'pair': 'ETH/BTC',
'base_currency': 'BTC',
'date': arrow.utcnow(),
'open_date': arrow.utcnow(),
'open_date_hum': arrow.utcnow().humanize,
'close_date': None,
'close_date_hum': None,
'open_rate': 1.099e-05,
'close_rate': None,
'current_rate': 1.098e-05,
@@ -519,6 +522,11 @@ def test_telegram_balance_handle(default_conf, update, mocker) -> None:
'total': 1.0,
'free': 1.0,
'used': 0.0
},
'EUR': {
'total': 10.0,
'free': 10.0,
'used': 0.0
}
}
@@ -562,6 +570,7 @@ def test_telegram_balance_handle(default_conf, update, mocker) -> None:
assert '*BTC:*' in result
assert '*ETH:*' not in result
assert '*USDT:*' in result
assert '*EUR:*' in result
assert 'Balance:' in result
assert 'Est. BTC:' in result
assert 'BTC: 12.00000000' in result

View File

@@ -1,5 +1,4 @@
# pragma pylint: disable=missing-docstring, C0103
import argparse
import pytest
@@ -185,3 +184,22 @@ def test_testdata_dl_options() -> None:
assert args.export == 'export/folder'
assert args.days == 30
assert args.exchange == 'binance'
def test_check_int_positive() -> None:
assert Arguments.check_int_positive("3") == 3
assert Arguments.check_int_positive("1") == 1
assert Arguments.check_int_positive("100") == 100
with pytest.raises(argparse.ArgumentTypeError):
Arguments.check_int_positive("-2")
with pytest.raises(argparse.ArgumentTypeError):
Arguments.check_int_positive("0")
with pytest.raises(argparse.ArgumentTypeError):
Arguments.check_int_positive("3.5")
with pytest.raises(argparse.ArgumentTypeError):
Arguments.check_int_positive("DeadBeef")

View File

@@ -19,7 +19,7 @@ def test_parse_args_backtesting(mocker) -> None:
Test that main() can start backtesting and also ensure we can pass some specific arguments
further argument parsing is done in test_arguments.py
"""
backtesting_mock = mocker.patch('freqtrade.optimize.backtesting.start', MagicMock())
backtesting_mock = mocker.patch('freqtrade.optimize.start_backtesting', MagicMock())
# it's sys.exit(0) at the end of backtesting
with pytest.raises(SystemExit):
main(['backtesting'])
@@ -34,7 +34,7 @@ def test_parse_args_backtesting(mocker) -> None:
def test_main_start_hyperopt(mocker) -> None:
hyperopt_mock = mocker.patch('freqtrade.optimize.hyperopt.start', MagicMock())
hyperopt_mock = mocker.patch('freqtrade.optimize.start_hyperopt', MagicMock())
# it's sys.exit(0) at the end of hyperopt
with pytest.raises(SystemExit):
main(['hyperopt'])

View File

@@ -6,7 +6,7 @@ from unittest.mock import MagicMock
from freqtrade.data.converter import parse_ticker_dataframe
from freqtrade.misc import (common_datearray, datesarray_to_datetimearray,
file_dump_json, file_load_json, format_ms_time, shorten_date)
from freqtrade.data.history import load_tickerdata_file, make_testdata_path
from freqtrade.data.history import load_tickerdata_file, pair_data_filename
from freqtrade.strategy.default_strategy import DefaultStrategy
@@ -60,13 +60,13 @@ def test_file_dump_json(mocker) -> None:
def test_file_load_json(mocker) -> None:
# 7m .json does not exist
ret = file_load_json(make_testdata_path(None).joinpath('UNITTEST_BTC-7m.json'))
ret = file_load_json(pair_data_filename(None, 'UNITTEST/BTC', '7m'))
assert not ret
# 1m json exists (but no .gz exists)
ret = file_load_json(make_testdata_path(None).joinpath('UNITTEST_BTC-1m.json'))
ret = file_load_json(pair_data_filename(None, 'UNITTEST/BTC', '1m'))
assert ret
# 8 .json is empty and will fail if it's loaded. .json.gz is a copy of 1.json
ret = file_load_json(make_testdata_path(None).joinpath('UNITTEST_BTC-8m.json'))
ret = file_load_json(pair_data_filename(None, 'UNITTEST/BTC', '8m'))
assert ret

View File

@@ -1,7 +1,8 @@
# pragma pylint: disable=missing-docstring, C0103
from unittest.mock import MagicMock
import logging
from unittest.mock import MagicMock
import arrow
import pytest
from sqlalchemy import create_engine
@@ -710,3 +711,69 @@ def test_get_open(default_conf, fee):
Trade.session.add(trade)
assert len(Trade.get_open_trades()) == 2
def test_to_json(default_conf, fee):
init(default_conf)
# Simulate dry_run entries
trade = Trade(
pair='ETH/BTC',
stake_amount=0.001,
amount=123.0,
fee_open=fee.return_value,
fee_close=fee.return_value,
open_date=arrow.utcnow().shift(hours=-2).datetime,
open_rate=0.123,
exchange='bittrex',
open_order_id='dry_run_buy_12345'
)
result = trade.to_json()
assert isinstance(result, dict)
print(result)
assert result == {'trade_id': None,
'pair': 'ETH/BTC',
'open_date_hum': '2 hours ago',
'open_date': trade.open_date.strftime("%Y-%m-%d %H:%M:%S"),
'close_date_hum': None,
'close_date': None,
'open_rate': 0.123,
'close_rate': None,
'amount': 123.0,
'stake_amount': 0.001,
'stop_loss': None,
'stop_loss_pct': None,
'initial_stop_loss': None,
'initial_stop_loss_pct': None}
# Simulate dry_run entries
trade = Trade(
pair='XRP/BTC',
stake_amount=0.001,
amount=100.0,
fee_open=fee.return_value,
fee_close=fee.return_value,
open_date=arrow.utcnow().shift(hours=-2).datetime,
close_date=arrow.utcnow().shift(hours=-1).datetime,
open_rate=0.123,
close_rate=0.125,
exchange='bittrex',
)
result = trade.to_json()
assert isinstance(result, dict)
assert result == {'trade_id': None,
'pair': 'XRP/BTC',
'open_date_hum': '2 hours ago',
'open_date': trade.open_date.strftime("%Y-%m-%d %H:%M:%S"),
'close_date_hum': 'an hour ago',
'close_date': trade.close_date.strftime("%Y-%m-%d %H:%M:%S"),
'open_rate': 0.123,
'close_rate': 0.125,
'amount': 100.0,
'stake_amount': 0.001,
'stop_loss': None,
'stop_loss_pct': None,
'initial_stop_loss': None,
'initial_stop_loss_pct': None}