Exemple #1
0
def test_validate_backtest_data_warn(default_conf, mocker, caplog,
                                     testdatadir) -> None:
    patch_exchange(mocker)

    default_conf.update({'strategy': 'DefaultStrategy'})
    strategy = StrategyResolver.load_strategy(default_conf)

    data = strategy.ohlcvdata_to_dataframe(
        load_data(datadir=testdatadir,
                  timeframe='1m',
                  pairs=['UNITTEST/BTC'],
                  fill_up_missing=False))
    min_date, max_date = get_timerange(data)
    caplog.clear()
    assert validate_backtest_data(data['UNITTEST/BTC'],
                                  'UNITTEST/BTC', 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)
Exemple #2
0
def test_simplified_interface_failed(mocker, hyperopt_conf, method, space) -> None:
    mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock())
    mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data',
                 MagicMock(return_value=(MagicMock(), None)))
    mocker.patch(
        'freqtrade.optimize.hyperopt.get_timerange',
        MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))
    )

    patch_exchange(mocker)

    hyperopt_conf.update({'spaces': space})

    hyperopt = Hyperopt(hyperopt_conf)
    hyperopt.backtesting.strategy.ohlcvdata_to_dataframe = MagicMock()
    hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})

    delattr(hyperopt.custom_hyperopt.__class__, method)

    with pytest.raises(OperationalException, match=f"The '{space}' space is included into *"):
        hyperopt.start()
Exemple #3
0
def test_validate_backtest_data(default_conf, mocker, caplog, testdatadir) -> None:
    patch_exchange(mocker)

    default_conf.update({'strategy': 'DefaultStrategy'})
    strategy = StrategyResolver.load_strategy(default_conf)

    timerange = TimeRange('index', 'index', 200, 250)
    data = strategy.ohlcvdata_to_dataframe(
        load_data(
            datadir=testdatadir,
            timeframe='5m',
            pairs=['UNITTEST/BTC'],
            timerange=timerange
        )
    )

    min_date, max_date = get_timerange(data)
    caplog.clear()
    assert not validate_backtest_data(data['UNITTEST/BTC'], 'UNITTEST/BTC',
                                      min_date, max_date, timeframe_to_minutes('5m'))
    assert len(caplog.record_tuples) == 0
def test_print_json_spaces_roi_stoploss(mocker, default_conf, caplog,
                                        capsys) -> 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,
            'results_explanation': 'foo result',
            'params': {}
        }]))
    patch_exchange(mocker)

    default_conf.update({
        'config': 'config.json.example',
        'epochs': 1,
        'timerange': None,
        'spaces': 'roi stoploss',
        'hyperopt_jobs': 1,
        'print_json': True,
    })

    hyperopt = Hyperopt(default_conf)
    hyperopt.backtesting.strategy.tickerdata_to_dataframe = MagicMock()
    hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})

    hyperopt.start()

    parallel.assert_called_once()

    out, err = capsys.readouterr()
    assert '{"minimal_roi":{},"stoploss":null}' in out
    assert dumper.called
    # Should be called twice, once for tickerdata, once to save evaluations
    assert dumper.call_count == 2
Exemple #5
0
def test_backtest_start_timerange(default_conf, mocker, caplog, testdatadir):
    default_conf['exchange']['pair_whitelist'] = ['UNITTEST/BTC']

    async def load_pairs(pair, timeframe, since):
        return _load_pair_as_ticks(pair, timeframe)

    api_mock = MagicMock()
    api_mock.fetch_ohlcv = load_pairs

    patch_exchange(mocker, api_mock)
    mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest',
                 MagicMock())
    mocker.patch(
        'freqtrade.optimize.backtesting.Backtesting._generate_text_table',
        MagicMock())
    patched_configuration_load_config_file(mocker, default_conf)

    args = [
        '--config', 'config.json', '--strategy', 'DefaultStrategy',
        '--datadir',
        str(testdatadir), 'backtesting', '--ticker-interval', '1m',
        '--timerange', '-100', '--enable-position-stacking',
        '--disable-max-market-positions'
    ]
    args = get_args(args)
    start_backtesting(args)
    # check the logs, that will contain the backtest result
    exists = [
        'Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...',
        'Ignoring max_open_trades (--disable-max-market-positions was used) ...',
        'Parameter --timerange detected: -100 ...',
        f'Using data directory: {testdatadir} ...',
        'Using stake_currency: BTC ...', 'Using stake_amount: 0.001 ...',
        'Backtesting with data from 2017-11-14T21:17:00+00:00 '
        'up to 2017-11-14T22:58:00+00:00 (0 days)..',
        'Parameter --enable-position-stacking detected ...'
    ]

    for line in exists:
        assert log_has(line, caplog)
def test_backtesting_start_no_data(default_conf, mocker, caplog,
                                   testdatadir) -> None:
    def get_timerange(input1):
        return Arrow(2017, 11, 14, 21, 17), Arrow(2017, 11, 14, 22, 59)

    mocker.patch('freqtrade.data.history.history_utils.load_pair_history',
                 MagicMock(return_value=pd.DataFrame()))
    mocker.patch('freqtrade.data.history.get_timerange', get_timerange)
    patch_exchange(mocker)
    mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest')
    mocker.patch('freqtrade.plugins.pairlistmanager.PairListManager.whitelist',
                 PropertyMock(return_value=['UNITTEST/BTC']))

    default_conf['timeframe'] = "1m"
    default_conf['datadir'] = testdatadir
    default_conf['export'] = None
    default_conf['timerange'] = '20180101-20180102'

    backtesting = Backtesting(default_conf)
    with pytest.raises(OperationalException,
                       match='No data found. Terminating.'):
        backtesting.start()
Exemple #7
0
def test_in_strategy_auto_hyperopt(mocker, hyperopt_conf, tmpdir, fee) -> None:
    patch_exchange(mocker)
    mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
    (Path(tmpdir) / 'hyperopt_results').mkdir(parents=True)
    # No hyperopt needed
    del hyperopt_conf['hyperopt']
    hyperopt_conf.update({
        'strategy': 'HyperoptableStrategy',
        'user_data_dir': Path(tmpdir),
    })
    hyperopt = Hyperopt(hyperopt_conf)
    assert isinstance(hyperopt.custom_hyperopt, HyperOptAuto)
    assert isinstance(hyperopt.backtesting.strategy.buy_rsi, IntParameter)

    assert hyperopt.backtesting.strategy.buy_rsi.in_space is True
    assert hyperopt.backtesting.strategy.buy_rsi.value == 35
    buy_rsi_range = hyperopt.backtesting.strategy.buy_rsi.range
    assert isinstance(buy_rsi_range, range)
    # Range from 0 - 50 (inclusive)
    assert len(list(buy_rsi_range)) == 51

    hyperopt.start()
def test_backtest_1min_timeframe(default_conf, fee, mocker, testdatadir) -> None:
    default_conf['ask_strategy']['use_sell_signal'] = False
    mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
    patch_exchange(mocker)
    backtesting = Backtesting(default_conf)

    # Run a backtesting for an exiting 1min timeframe
    timerange = TimeRange.parse_timerange('1510688220-1510700340')
    data = history.load_data(datadir=testdatadir, timeframe='1m', pairs=['UNITTEST/BTC'],
                             timerange=timerange)
    processed = backtesting.strategy.ohlcvdata_to_dataframe(data)
    min_date, max_date = get_timerange(processed)
    results = backtesting.backtest(
        processed=processed,
        stake_amount=default_conf['stake_amount'],
        start_date=min_date,
        end_date=max_date,
        max_open_trades=1,
        position_stacking=False,
    )
    assert not results.empty
    assert len(results) == 1
def test_simplified_interface_failed(mocker, hyperopt_conf, space) -> None:
    mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock())
    mocker.patch('freqtrade.optimize.hyperopt.file_dump_json')
    mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data',
                 MagicMock(return_value=(MagicMock(), None)))
    mocker.patch(
        'freqtrade.optimize.hyperopt.get_timerange',
        MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))
    )
    mocker.patch('freqtrade.optimize.hyperopt_auto.HyperOptAuto._generate_indicator_space',
                 return_value=[])

    patch_exchange(mocker)

    hyperopt_conf.update({'spaces': space})

    hyperopt = Hyperopt(hyperopt_conf)
    hyperopt.backtesting.strategy.advise_all_indicators = MagicMock()
    hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})

    with pytest.raises(OperationalException, match=f"The '{space}' space is included into *"):
        hyperopt.start()
def test_backtest_start_timerange(default_conf, mocker, caplog, testdatadir):

    patch_exchange(mocker)
    mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest')
    mocker.patch('freqtrade.optimize.backtesting.generate_backtest_stats')
    mocker.patch('freqtrade.optimize.backtesting.show_backtest_results')
    mocker.patch('freqtrade.pairlist.pairlistmanager.PairListManager.whitelist',
                 PropertyMock(return_value=['UNITTEST/BTC']))
    patched_configuration_load_config_file(mocker, default_conf)

    args = [
        'backtesting',
        '--config', 'config.json',
        '--strategy', 'DefaultStrategy',
        '--datadir', str(testdatadir),
        '--timeframe', '1m',
        '--timerange', '1510694220-1510700340',
        '--enable-position-stacking',
        '--disable-max-market-positions'
    ]
    args = get_args(args)
    start_backtesting(args)
    # check the logs, that will contain the backtest result
    exists = [
        'Parameter -i/--timeframe detected ... Using timeframe: 1m ...',
        'Ignoring max_open_trades (--disable-max-market-positions was used) ...',
        'Parameter --timerange detected: 1510694220-1510700340 ...',
        f'Using data directory: {testdatadir} ...',
        'Using stake_currency: BTC ...',
        'Using stake_amount: 0.001 ...',
        'Loading data from 2017-11-14T20:57:00+00:00 '
        'up to 2017-11-14T22:58:00+00:00 (0 days)..',
        'Backtesting with data from 2017-11-14T21:17:00+00:00 '
        'up to 2017-11-14T22:58:00+00:00 (0 days)..',
        'Parameter --enable-position-stacking detected ...'
    ]

    for line in exists:
        assert log_has(line, caplog)
Exemple #11
0
def _make_backtest_conf(mocker,
                        datadir,
                        conf=None,
                        pair='UNITTEST/BTC',
                        record=None):
    data = history.load_data(datadir=datadir,
                             ticker_interval='1m',
                             pairs=[pair])
    data = trim_dictlist(data, -201)
    patch_exchange(mocker)
    backtesting = Backtesting(conf)
    processed = backtesting.strategy.tickerdata_to_dataframe(data)
    min_date, max_date = get_timeframe(processed)
    return {
        'stake_amount': conf['stake_amount'],
        'processed': processed,
        'max_open_trades': 10,
        'position_stacking': False,
        'record': record,
        'start_date': min_date,
        'end_date': max_date,
    }
Exemple #12
0
def test_generate_text_table_strategyn(default_conf, mocker):
    """
    Test Backtesting.generate_text_table_sell_reason() method
    """
    patch_exchange(mocker)
    default_conf['max_open_trades'] = 2
    backtesting = Backtesting(default_conf)
    results = {}
    results['ETH/BTC'] = pd.DataFrame({
        'pair': ['ETH/BTC', 'ETH/BTC', 'ETH/BTC'],
        'profit_percent': [0.1, 0.2, 0.3],
        'profit_abs': [0.2, 0.4, 0.5],
        'trade_duration': [10, 30, 10],
        'profit': [2, 0, 0],
        'loss': [0, 0, 1],
        'sell_reason': [SellType.ROI, SellType.ROI, SellType.STOP_LOSS]
    })
    results['LTC/BTC'] = pd.DataFrame({
        'pair': ['LTC/BTC', 'LTC/BTC', 'LTC/BTC'],
        'profit_percent': [0.4, 0.2, 0.3],
        'profit_abs': [0.4, 0.4, 0.5],
        'trade_duration': [15, 30, 15],
        'profit': [4, 1, 0],
        'loss': [0, 0, 1],
        'sell_reason': [SellType.ROI, SellType.ROI, SellType.STOP_LOSS]
    })

    result_str = (
        '| Strategy   |   buy count |   avg profit % |   cum profit % '
        '|   tot profit BTC |   tot profit % | avg duration   |   profit |   loss |\n'
        '|:-----------|------------:|---------------:|---------------:'
        '|-----------------:|---------------:|:---------------|---------:|-------:|\n'
        '| ETH/BTC    |           3 |          20.00 |          60.00 '
        '|       1.10000000 |          30.00 | 0:17:00        |        3 |      0 |\n'
        '| LTC/BTC    |           3 |          30.00 |          90.00 '
        '|       1.30000000 |          45.00 | 0:20:00        |        3 |      0 |'
    )
    assert backtesting._generate_text_table_strategy(
        all_results=results) == result_str
Exemple #13
0
def test_rpc_count(mocker, default_conf, ticker, fee, markets) -> None:
    patch_exchange(mocker)
    mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
    mocker.patch.multiple(
        'freqtrade.exchange.Exchange',
        get_balances=MagicMock(return_value=ticker),
        get_ticker=ticker,
        get_fee=fee,
        markets=PropertyMock(return_value=markets)
    )

    freqtradebot = FreqtradeBot(default_conf)
    patch_get_signal(freqtradebot, (True, False))
    rpc = RPC(freqtradebot)

    counts = rpc._rpc_count()
    assert counts["current"] == 0

    # Create some test data
    freqtradebot.create_trades()
    counts = rpc._rpc_count()
    assert counts["current"] == 1
Exemple #14
0
def test_forcebuy_handle(default_conf, update, markets, mocker) -> None:
    mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price',
                 return_value=15000.0)
    mocker.patch('freqtrade.rpc.telegram.Telegram._send_msg', MagicMock())
    mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock())
    patch_exchange(mocker)
    mocker.patch.multiple(
        'freqtrade.exchange.Exchange',
        markets=PropertyMock(markets),
    )
    fbuy_mock = MagicMock(return_value=None)
    mocker.patch('freqtrade.rpc.RPC._rpc_forcebuy', fbuy_mock)

    freqtradebot = FreqtradeBot(default_conf)
    patch_get_signal(freqtradebot, (True, False))
    telegram = Telegram(freqtradebot)

    # /forcebuy ETH/BTC
    context = MagicMock()
    context.args = ["ETH/BTC"]
    telegram._forcebuy(update=update, context=context)

    assert fbuy_mock.call_count == 1
    assert fbuy_mock.call_args_list[0][0][0] == 'ETH/BTC'
    assert fbuy_mock.call_args_list[0][0][1] is None

    # Reset and retry with specified price
    fbuy_mock = MagicMock(return_value=None)
    mocker.patch('freqtrade.rpc.RPC._rpc_forcebuy', fbuy_mock)
    # /forcebuy ETH/BTC 0.055
    context = MagicMock()
    context.args = ["ETH/BTC", "0.055"]
    telegram._forcebuy(update=update, context=context)

    assert fbuy_mock.call_count == 1
    assert fbuy_mock.call_args_list[0][0][0] == 'ETH/BTC'
    assert isinstance(fbuy_mock.call_args_list[0][0][1], float)
    assert fbuy_mock.call_args_list[0][0][1] == 0.055
Exemple #15
0
def test_download_data_all_pairs(mocker, markets):

    mocker.patch.object(Path, "exists", MagicMock(return_value=False))

    dl_mock = mocker.patch('freqtrade.commands.data_commands.refresh_backtest_ohlcv_data',
                           MagicMock(return_value=["ETH/BTC", "XRP/BTC"]))
    patch_exchange(mocker)
    mocker.patch(
        'freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets)
    )
    args = [
        "download-data",
        "--exchange",
        "binance",
        "--pairs",
        ".*/USDT"
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_download_data(pargs)
    expected = set(['ETH/USDT', 'XRP/USDT', 'NEO/USDT', 'TKN/USDT'])
    assert set(dl_mock.call_args_list[0][1]['pairs']) == expected
    assert dl_mock.call_count == 1

    dl_mock.reset_mock()
    args = [
        "download-data",
        "--exchange",
        "binance",
        "--pairs",
        ".*/USDT",
        "--include-inactive-pairs",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_download_data(pargs)
    expected = set(['ETH/USDT', 'LTC/USDT', 'XRP/USDT', 'NEO/USDT', 'TKN/USDT'])
    assert set(dl_mock.call_args_list[0][1]['pairs']) == expected
Exemple #16
0
def test_tickerdata_to_dataframe_bt(default_conf, mocker, testdatadir) -> None:
    patch_exchange(mocker)
    timerange = TimeRange(None, 'line', 0, -100)
    tick = history.load_tickerdata_file(testdatadir,
                                        'UNITTEST/BTC',
                                        '1m',
                                        timerange=timerange)
    tickerlist = {
        'UNITTEST/BTC':
        parse_ticker_dataframe(tick,
                               '1m',
                               pair="UNITTEST/BTC",
                               fill_missing=True)
    }

    backtesting = Backtesting(default_conf)
    data = backtesting.strategy.tickerdata_to_dataframe(tickerlist)
    assert len(data['UNITTEST/BTC']) == 102

    # Load strategy to compare the result between Backtesting function and strategy are the same
    strategy = DefaultStrategy(default_conf)
    data2 = strategy.tickerdata_to_dataframe(tickerlist)
    assert data['UNITTEST/BTC'].equals(data2['UNITTEST/BTC'])
def test_backtest_1min_timeframe(default_conf, fee, mocker, testdatadir) -> None:
    default_conf['use_sell_signal'] = False
    mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
    mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001)
    patch_exchange(mocker)
    backtesting = Backtesting(default_conf)
    backtesting._set_strategy(backtesting.strategylist[0])

    # Run a backtesting for an exiting 1min timeframe
    timerange = TimeRange.parse_timerange('1510688220-1510700340')
    data = history.load_data(datadir=testdatadir, timeframe='1m', pairs=['UNITTEST/BTC'],
                             timerange=timerange)
    processed = backtesting.strategy.advise_all_indicators(data)
    min_date, max_date = get_timerange(processed)
    results = backtesting.backtest(
        processed=processed,
        start_date=min_date,
        end_date=max_date,
        max_open_trades=1,
        position_stacking=False,
    )
    assert not results['results'].empty
    assert len(results['results']) == 1
Exemple #18
0
def test_start_not_installed(mocker, default_conf, import_fails) -> None:
    start_mock = MagicMock()
    patched_configuration_load_config_file(mocker, default_conf)

    mocker.patch('freqtrade.optimize.hyperopt.Hyperopt.start', start_mock)
    patch_exchange(mocker)

    args = [
        'hyperopt',
        '--config',
        'config.json',
        '--strategy',
        'HyperoptableStrategy',
        '--epochs',
        '5',
        '--hyperopt-loss',
        'SharpeHyperOptLossDaily',
    ]
    pargs = get_args(args)

    with pytest.raises(OperationalException,
                       match=r"Please ensure that the hyperopt dependencies"):
        start_hyperopt(pargs)
Exemple #19
0
def test_main_reload_conf(mocker, default_conf, caplog) -> None:
    patch_exchange(mocker)
    mocker.patch('freqtrade.freqtradebot.FreqtradeBot.cleanup', MagicMock())
    # Simulate Running, reload, running workflow
    worker_mock = MagicMock(side_effect=[State.RUNNING,
                                         State.RELOAD_CONF,
                                         State.RUNNING,
                                         OperationalException("Oh snap!")])
    mocker.patch('freqtrade.worker.Worker._worker', worker_mock)
    patched_configuration_load_config_file(mocker, default_conf)
    reconfigure_mock = mocker.patch('freqtrade.worker.Worker._reconfigure', MagicMock())

    mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
    mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock())

    args = Arguments(['trade', '-c', 'config.json.example']).get_parsed_arg()
    worker = Worker(args=args, config=default_conf)
    with pytest.raises(SystemExit):
        main(['trade', '-c', 'config.json.example'])

    assert log_has('Using config: config.json.example ...', caplog)
    assert worker_mock.call_count == 4
    assert reconfigure_mock.call_count == 1
    assert isinstance(worker.freqtrade, FreqtradeBot)
Exemple #20
0
def test_in_strategy_auto_hyperopt(mocker, hyperopt_conf, tmpdir, fee) -> None:
    patch_exchange(mocker)
    mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
    (Path(tmpdir) / 'hyperopt_results').mkdir(parents=True)
    # No hyperopt needed
    hyperopt_conf.update({
        'strategy': 'HyperoptableStrategy',
        'user_data_dir': Path(tmpdir),
        'hyperopt_random_state': 42,
        'spaces': ['all']
    })
    hyperopt = Hyperopt(hyperopt_conf)
    hyperopt.backtesting.exchange.get_max_leverage = MagicMock(
        return_value=1.0)
    assert isinstance(hyperopt.custom_hyperopt, HyperOptAuto)
    assert isinstance(hyperopt.backtesting.strategy.buy_rsi, IntParameter)

    assert hyperopt.backtesting.strategy.buy_rsi.in_space is True
    assert hyperopt.backtesting.strategy.buy_rsi.value == 35
    assert hyperopt.backtesting.strategy.sell_rsi.value == 74
    assert hyperopt.backtesting.strategy.protection_cooldown_lookback.value == 30
    buy_rsi_range = hyperopt.backtesting.strategy.buy_rsi.range
    assert isinstance(buy_rsi_range, range)
    # Range from 0 - 50 (inclusive)
    assert len(list(buy_rsi_range)) == 51

    hyperopt.start()
    # All values should've changed.
    assert hyperopt.backtesting.strategy.protection_cooldown_lookback.value != 30
    assert hyperopt.backtesting.strategy.buy_rsi.value != 35
    assert hyperopt.backtesting.strategy.sell_rsi.value != 74

    hyperopt.custom_hyperopt.generate_estimator = lambda *args, **kwargs: 'ET1'
    with pytest.raises(OperationalException,
                       match="Estimator ET1 not supported."):
        hyperopt.get_optimizer([], 2)
Exemple #21
0
def test_main_operational_exception1(mocker, default_conf, caplog) -> None:
    patch_exchange(mocker)
    mocker.patch(
        'freqtrade.commands.list_commands.validate_exchanges',
        MagicMock(side_effect=ValueError('Oh snap!'))
    )
    patched_configuration_load_config_file(mocker, default_conf)

    args = ['list-exchanges']

    # Test Main + the KeyboardInterrupt exception
    with pytest.raises(SystemExit):
        main(args)

    assert log_has('Fatal exception!', caplog)
    assert not log_has_re(r'SIGINT.*', caplog)
    mocker.patch(
        'freqtrade.commands.list_commands.validate_exchanges',
        MagicMock(side_effect=KeyboardInterrupt)
    )
    with pytest.raises(SystemExit):
        main(args)

    assert log_has_re(r'SIGINT.*', caplog)
Exemple #22
0
def test_performance_handle(default_conf, update, ticker, fee, limit_buy_order,
                            limit_sell_order, markets, mocker) -> None:
    patch_exchange(mocker)
    msg_mock = MagicMock()
    mocker.patch.multiple('freqtrade.rpc.telegram.Telegram',
                          _init=MagicMock(),
                          _send_msg=msg_mock)
    mocker.patch.multiple(
        'freqtrade.exchange.Exchange',
        get_ticker=ticker,
        get_fee=fee,
        markets=PropertyMock(markets),
    )
    mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
    freqtradebot = FreqtradeBot(default_conf)
    patch_get_signal(freqtradebot, (True, False))
    telegram = Telegram(freqtradebot)

    # Create some test data
    freqtradebot.create_trades()
    trade = Trade.query.first()
    assert trade

    # Simulate fulfilled LIMIT_BUY order for trade
    trade.update(limit_buy_order)

    # Simulate fulfilled LIMIT_SELL order for trade
    trade.update(limit_sell_order)

    trade.close_date = datetime.utcnow()
    trade.is_open = False
    telegram._performance(update=update, context=MagicMock())
    assert msg_mock.call_count == 1
    assert 'Performance' in msg_mock.call_args_list[0][0][0]
    assert '<code>ETH/BTC\t6.20% (1)</code>' in msg_mock.call_args_list[0][0][
        0]
Exemple #23
0
def test_count_handle(default_conf, update, ticker, fee, markets,
                      mocker) -> None:
    patch_exchange(mocker)
    msg_mock = MagicMock()
    mocker.patch.multiple('freqtrade.rpc.telegram.Telegram',
                          _init=MagicMock(),
                          _send_msg=msg_mock)
    mocker.patch.multiple(
        'freqtrade.exchange.Exchange',
        get_ticker=ticker,
        buy=MagicMock(return_value={'id': 'mocked_order_id'}),
        markets=PropertyMock(markets))
    mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
    freqtradebot = FreqtradeBot(default_conf)
    patch_get_signal(freqtradebot, (True, False))
    telegram = Telegram(freqtradebot)

    freqtradebot.state = State.STOPPED
    telegram._count(update=update, context=MagicMock())
    assert msg_mock.call_count == 1
    assert 'not running' in msg_mock.call_args_list[0][0][0]
    msg_mock.reset_mock()
    freqtradebot.state = State.RUNNING

    # Create some test data
    freqtradebot.create_trades()
    msg_mock.reset_mock()
    telegram._count(update=update, context=MagicMock())

    msg = '<pre>  current    max    total stake\n---------  -----  -------------\n' \
          '        1      {}          {}</pre>'\
        .format(
            default_conf['max_open_trades'],
            default_conf['stake_amount']
        )
    assert msg in msg_mock.call_args_list[0][0][0]
Exemple #24
0
def test_backtest_1min_ticker_interval(default_conf, fee, mocker,
                                       testdatadir) -> None:
    mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
    patch_exchange(mocker)
    backtesting = Backtesting(default_conf)

    # Run a backtesting for an exiting 1min ticker_interval
    timerange = TimeRange(None, 'line', 0, -200)
    data = history.load_data(datadir=testdatadir,
                             ticker_interval='1m',
                             pairs=['UNITTEST/BTC'],
                             timerange=timerange)
    processed = backtesting.strategy.tickerdata_to_dataframe(data)
    min_date, max_date = get_timeframe(processed)
    results = backtesting.backtest({
        'stake_amount': default_conf['stake_amount'],
        'processed': processed,
        'max_open_trades': 1,
        'position_stacking': False,
        'start_date': min_date,
        'end_date': max_date,
    })
    assert not results.empty
    assert len(results) == 1
Exemple #25
0
def test_simplified_interface_all_failed(mocker, hyperopt_conf) -> None:
    mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock())
    mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data',
                 MagicMock(return_value=(MagicMock(), None)))
    mocker.patch(
        'freqtrade.optimize.hyperopt.get_timerange',
        MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))
    )

    patch_exchange(mocker)

    hyperopt_conf.update({'spaces': 'all', })

    hyperopt = Hyperopt(hyperopt_conf)
    hyperopt.backtesting.strategy.ohlcvdata_to_dataframe = MagicMock()
    hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})

    del hyperopt.custom_hyperopt.__class__.buy_strategy_generator
    del hyperopt.custom_hyperopt.__class__.sell_strategy_generator
    del hyperopt.custom_hyperopt.__class__.indicator_space
    del hyperopt.custom_hyperopt.__class__.sell_indicator_space

    with pytest.raises(OperationalException, match=r"The 'buy' space is included into *"):
        hyperopt.start()
def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdatadir, capsys):

    patch_exchange(mocker)
    backtestmock = MagicMock(side_effect=[
        pd.DataFrame({'pair': ['XRP/BTC', 'LTC/BTC'],
                      'profit_percent': [0.0, 0.0],
                      'profit_abs': [0.0, 0.0],
                      'open_time': pd.to_datetime(['2018-01-29 18:40:00',
                                                   '2018-01-30 03:30:00', ], utc=True
                                                  ),
                      'close_time': pd.to_datetime(['2018-01-29 20:45:00',
                                                    '2018-01-30 05:35:00', ], utc=True),
                      'open_index': [78, 184],
                      'close_index': [125, 192],
                      'trade_duration': [235, 40],
                      'open_at_end': [False, False],
                      'open_rate': [0.104445, 0.10302485],
                      'close_rate': [0.104969, 0.103541],
                      'sell_reason': [SellType.ROI, SellType.ROI]
                      }),
        pd.DataFrame({'pair': ['XRP/BTC', 'LTC/BTC', 'ETH/BTC'],
                      'profit_percent': [0.03, 0.01, 0.1],
                      'profit_abs': [0.01, 0.02, 0.2],
                      'open_time': pd.to_datetime(['2018-01-29 18:40:00',
                                                   '2018-01-30 03:30:00',
                                                   '2018-01-30 05:30:00'], utc=True
                                                  ),
                      'close_time': pd.to_datetime(['2018-01-29 20:45:00',
                                                    '2018-01-30 05:35:00',
                                                    '2018-01-30 08:30:00'], utc=True),
                      'open_index': [78, 184, 185],
                      'close_index': [125, 224, 205],
                      'trade_duration': [47, 40, 20],
                      'open_at_end': [False, False, False],
                      'open_rate': [0.104445, 0.10302485, 0.122541],
                      'close_rate': [0.104969, 0.103541, 0.123541],
                      'sell_reason': [SellType.ROI, SellType.ROI, SellType.STOP_LOSS]
                      }),
    ])
    mocker.patch('freqtrade.pairlist.pairlistmanager.PairListManager.whitelist',
                 PropertyMock(return_value=['UNITTEST/BTC']))
    mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest', backtestmock)

    patched_configuration_load_config_file(mocker, default_conf)

    args = [
        'backtesting',
        '--config', 'config.json',
        '--datadir', str(testdatadir),
        '--strategy-path', str(Path(__file__).parents[1] / 'strategy/strats'),
        '--timeframe', '1m',
        '--timerange', '1510694220-1510700340',
        '--enable-position-stacking',
        '--disable-max-market-positions',
        '--strategy-list',
        'DefaultStrategy',
        'TestStrategyLegacy',
    ]
    args = get_args(args)
    start_backtesting(args)

    # check the logs, that will contain the backtest result
    exists = [
        'Parameter -i/--timeframe detected ... Using timeframe: 1m ...',
        'Ignoring max_open_trades (--disable-max-market-positions was used) ...',
        'Parameter --timerange detected: 1510694220-1510700340 ...',
        f'Using data directory: {testdatadir} ...',
        'Using stake_currency: BTC ...',
        'Using stake_amount: 0.001 ...',
        'Loading data from 2017-11-14T20:57:00+00:00 '
        'up to 2017-11-14T22:58:00+00:00 (0 days)..',
        'Backtesting with data from 2017-11-14T21:17: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 TestStrategyLegacy',
    ]

    for line in exists:
        assert log_has(line, caplog)

    captured = capsys.readouterr()
    assert 'BACKTESTING REPORT' in captured.out
    assert 'SELL REASON STATS' in captured.out
    assert 'LEFT OPEN TRADES REPORT' in captured.out
    assert 'STRATEGY SUMMARY' in captured.out
def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir):

    patch_exchange(mocker)
    backtestmock = MagicMock()
    mocker.patch('freqtrade.pairlist.pairlistmanager.PairListManager.whitelist',
                 PropertyMock(return_value=['UNITTEST/BTC']))
    mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest', backtestmock)
    text_table_mock = MagicMock()
    sell_reason_mock = MagicMock()
    strattable_mock = MagicMock()
    strat_summary = MagicMock()

    mocker.patch.multiple('freqtrade.optimize.optimize_reports',
                          text_table_bt_results=text_table_mock,
                          text_table_strategy=strattable_mock,
                          generate_pair_metrics=MagicMock(),
                          generate_sell_reason_stats=sell_reason_mock,
                          generate_strategy_metrics=strat_summary,
                          )
    patched_configuration_load_config_file(mocker, default_conf)

    args = [
        'backtesting',
        '--config', 'config.json',
        '--datadir', str(testdatadir),
        '--strategy-path', str(Path(__file__).parents[1] / 'strategy/strats'),
        '--timeframe', '1m',
        '--timerange', '1510694220-1510700340',
        '--enable-position-stacking',
        '--disable-max-market-positions',
        '--strategy-list',
        'DefaultStrategy',
        'TestStrategyLegacy',
    ]
    args = get_args(args)
    start_backtesting(args)
    # 2 backtests, 4 tables
    assert backtestmock.call_count == 2
    assert text_table_mock.call_count == 4
    assert strattable_mock.call_count == 1
    assert sell_reason_mock.call_count == 2
    assert strat_summary.call_count == 1

    # check the logs, that will contain the backtest result
    exists = [
        'Parameter -i/--timeframe detected ... Using timeframe: 1m ...',
        'Ignoring max_open_trades (--disable-max-market-positions was used) ...',
        'Parameter --timerange detected: 1510694220-1510700340 ...',
        f'Using data directory: {testdatadir} ...',
        'Using stake_currency: BTC ...',
        'Using stake_amount: 0.001 ...',
        'Loading data from 2017-11-14T20:57:00+00:00 '
        'up to 2017-11-14T22:58:00+00:00 (0 days)..',
        'Backtesting with data from 2017-11-14T21:17: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 TestStrategyLegacy',
    ]

    for line in exists:
        assert log_has(line, caplog)
Exemple #28
0
def test_print_json_spaces_all(mocker, hyperopt_conf, capsys) -> None:
    dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock())
    mocker.patch('freqtrade.optimize.hyperopt.file_dump_json')

    mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data',
                 MagicMock(return_value=(MagicMock(), None)))
    mocker.patch(
        'freqtrade.optimize.hyperopt.get_timerange',
        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,
            'results_explanation': 'foo result',
            'params': {},
            'params_details': {
                'buy': {
                    'mfi-value': None
                },
                'sell': {
                    'sell-mfi-value': None
                },
                'roi': {},
                'stoploss': {
                    'stoploss': None
                },
                'trailing': {
                    'trailing_stop': None
                }
            },
            'results_metrics': {
                'trade_count': 1,
                'avg_profit': 0.1,
                'total_profit': 0.001,
                'profit': 1.0,
                'duration': 20.0
            }
        }]))
    patch_exchange(mocker)

    hyperopt_conf.update({
        'spaces': 'all',
        'hyperopt_jobs': 1,
        'print_json': True,
    })

    hyperopt = Hyperopt(hyperopt_conf)
    hyperopt.backtesting.strategy.ohlcvdata_to_dataframe = MagicMock()
    hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})

    hyperopt.start()

    parallel.assert_called_once()

    out, err = capsys.readouterr()
    result_str = (
        '{"params":{"mfi-value":null,"sell-mfi-value":null},"minimal_roi"'
        ':{},"stoploss":null,"trailing_stop":null}')
    assert result_str in out  # noqa: E501
    assert dumper.called
    # Should be called twice, once for historical candle data, once to save evaluations
    assert dumper.call_count == 2
Exemple #29
0
def test_generate_optimizer(mocker, hyperopt_conf) -> None:
    hyperopt_conf.update({
        'spaces': 'all',
        'hyperopt_min_trades': 1,
    })

    backtest_result = {
        'results':
        pd.DataFrame({
            "pair":
            ["UNITTEST/BTC", "UNITTEST/BTC", "UNITTEST/BTC", "UNITTEST/BTC"],
            "profit_ratio": [0.003312, 0.010801, 0.013803, 0.002780],
            "profit_abs": [0.000003, 0.000011, 0.000014, 0.000003],
            "open_date": [
                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_date": [
                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_rate": [0.002543, 0.003003, 0.003089, 0.003214],
            "close_rate": [0.002546, 0.003014, 0.003103, 0.003217],
            "trade_duration": [123, 34, 31, 14],
            "is_open": [False, False, False, True],
            "stake_amount": [0.01, 0.01, 0.01, 0.01],
            "sell_reason": [
                SellType.ROI, SellType.STOP_LOSS, SellType.ROI,
                SellType.FORCE_SELL
            ]
        }),
        'config':
        hyperopt_conf,
        'locks': [],
        'final_balance':
        1000,
    }

    mocker.patch('freqtrade.optimize.hyperopt.Backtesting.backtest',
                 return_value=backtest_result)
    mocker.patch('freqtrade.optimize.hyperopt.get_timerange',
                 return_value=(Arrow(2017, 12, 10), Arrow(2017, 12, 13)))
    patch_exchange(mocker)
    mocker.patch('freqtrade.optimize.hyperopt.load',
                 return_value={'XRP/BTC': None})

    optimizer_param = {
        'adx-value': 0,
        'fastd-value': 35,
        'mfi-value': 0,
        'rsi-value': 0,
        'adx-enabled': False,
        'fastd-enabled': True,
        'mfi-enabled': False,
        'rsi-enabled': False,
        'trigger': 'macd_cross_signal',
        'sell-adx-value': 0,
        'sell-fastd-value': 75,
        'sell-mfi-value': 0,
        'sell-rsi-value': 0,
        'sell-adx-enabled': False,
        'sell-fastd-enabled': True,
        'sell-mfi-enabled': False,
        'sell-rsi-enabled': False,
        'sell-trigger': 'macd_cross_signal',
        'roi_t1': 60.0,
        'roi_t2': 30.0,
        'roi_t3': 20.0,
        'roi_p1': 0.01,
        'roi_p2': 0.01,
        'roi_p3': 0.1,
        'stoploss': -0.4,
        'trailing_stop': True,
        'trailing_stop_positive': 0.02,
        'trailing_stop_positive_offset_p1': 0.05,
        'trailing_only_offset_is_reached': False,
    }
    response_expected = {
        'loss':
        1.9147239021396234,
        'results_explanation':
        ('     4 trades. 4/0/0 Wins/Draws/Losses. '
         'Avg profit   0.77%. Median profit   0.71%. Total profit  '
         '0.00003100 BTC (   0.00\N{GREEK CAPITAL LETTER SIGMA}%). '
         'Avg duration 0:50:00 min.').encode(locale.getpreferredencoding(),
                                             'replace').decode('utf-8'),
        'params_details': {
            'buy': {
                'adx-enabled': False,
                'adx-value': 0,
                'fastd-enabled': True,
                'fastd-value': 35,
                'mfi-enabled': False,
                'mfi-value': 0,
                'rsi-enabled': False,
                'rsi-value': 0,
                'trigger': 'macd_cross_signal'
            },
            'roi': {
                0: 0.12000000000000001,
                20.0: 0.02,
                50.0: 0.01,
                110.0: 0
            },
            'sell': {
                'sell-adx-enabled': False,
                'sell-adx-value': 0,
                'sell-fastd-enabled': True,
                'sell-fastd-value': 75,
                'sell-mfi-enabled': False,
                'sell-mfi-value': 0,
                'sell-rsi-enabled': False,
                'sell-rsi-value': 0,
                'sell-trigger': 'macd_cross_signal'
            },
            'stoploss': {
                'stoploss': -0.4
            },
            'trailing': {
                'trailing_only_offset_is_reached': False,
                'trailing_stop': True,
                'trailing_stop_positive': 0.02,
                'trailing_stop_positive_offset': 0.07
            }
        },
        'params_dict':
        optimizer_param,
        'params_not_optimized': {
            'buy': {},
            'sell': {}
        },
        'results_metrics':
        ANY,
        'total_profit':
        3.1e-08
    }

    hyperopt = Hyperopt(hyperopt_conf)
    hyperopt.min_date = Arrow(2017, 12, 10)
    hyperopt.max_date = Arrow(2017, 12, 13)
    hyperopt.init_spaces()
    hyperopt.dimensions = hyperopt.dimensions
    generate_optimizer_value = hyperopt.generate_optimizer(
        list(optimizer_param.values()))
    assert generate_optimizer_value == response_expected
def test_backtest(default_conf, fee, mocker, testdatadir) -> None:
    default_conf['ask_strategy']['use_sell_signal'] = False
    mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
    patch_exchange(mocker)
    backtesting = Backtesting(default_conf)
    pair = 'UNITTEST/BTC'
    timerange = TimeRange('date', None, 1517227800, 0)
    data = history.load_data(datadir=testdatadir,
                             timeframe='5m',
                             pairs=['UNITTEST/BTC'],
                             timerange=timerange)
    processed = backtesting.strategy.ohlcvdata_to_dataframe(data)
    min_date, max_date = get_timerange(processed)
    results = backtesting.backtest(
        processed=processed,
        stake_amount=default_conf['stake_amount'],
        start_date=min_date,
        end_date=max_date,
        max_open_trades=10,
        position_stacking=False,
    )
    assert not results.empty
    assert len(results) == 2

    expected = pd.DataFrame({
        'pair': [pair, pair],
        'profit_percent': [0.0, 0.0],
        'profit_abs': [0.0, 0.0],
        'open_date':
        pd.to_datetime([
            Arrow(2018, 1, 29, 18, 40, 0).datetime,
            Arrow(2018, 1, 30, 3, 30, 0).datetime
        ],
                       utc=True),
        'open_rate': [0.104445, 0.10302485],
        'open_fee': [0.0025, 0.0025],
        'close_date':
        pd.to_datetime([
            Arrow(2018, 1, 29, 22, 35, 0).datetime,
            Arrow(2018, 1, 30, 4, 10, 0).datetime
        ],
                       utc=True),
        'close_rate': [0.104969, 0.103541],
        'close_fee': [0.0025, 0.0025],
        'amount': [0.00957442, 0.0097064],
        'trade_duration': [235, 40],
        'open_at_end': [False, False],
        'sell_reason': [SellType.ROI, SellType.ROI]
    })
    pd.testing.assert_frame_equal(results, expected)
    data_pair = processed[pair]
    for _, t in results.iterrows():
        ln = data_pair.loc[data_pair["date"] == t["open_date"]]
        # Check open trade rate alignes to open rate
        assert ln is not None
        assert round(ln.iloc[0]["open"], 6) == round(t["open_rate"], 6)
        # check close trade rate alignes to close rate or is between high and low
        ln = data_pair.loc[data_pair["date"] == t["close_date"]]
        assert (round(ln.iloc[0]["open"], 6) == round(t["close_rate"], 6)
                or round(ln.iloc[0]["low"], 6) < round(
                    t["close_rate"], 6) < round(ln.iloc[0]["high"], 6))