예제 #1
0
def test_performance_handle(default_conf, ticker, limit_buy_order, fee,
                            limit_sell_order, markets, mocker) -> None:
    patch_coinmarketcap(mocker)
    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,
                          get_markets=markets)

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

    # Create some test data
    freqtradebot.create_trade()
    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
    res = rpc._rpc_performance()
    assert len(res) == 1
    assert res[0]['pair'] == 'ETH/BTC'
    assert res[0]['count'] == 1
    assert prec_satoshi(res[0]['profit'], 6.2)
예제 #2
0
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': {}}])
    )
    patch_exchange(mocker)

    default_conf.update({'config': 'config.json.example',
                         'epochs': 1,
                         'timerange': None,
                         'spaces': 'all',
                         'hyperopt_jobs': 1, })

    hyperopt = Hyperopt(default_conf)
    hyperopt.strategy.tickerdata_to_dataframe = MagicMock()

    hyperopt.start()
    parallel.assert_called_once()
    assert log_has('Best result:\nfoo result\nwith values:\n', caplog.record_tuples)
    assert dumper.called
    # Should be called twice, once for tickerdata, once to save evaluations
    assert dumper.call_count == 2
    assert hasattr(hyperopt, "advise_sell")
    assert hasattr(hyperopt, "advise_buy")
    assert hasattr(hyperopt, "max_open_trades")
    assert hyperopt.max_open_trades == default_conf['max_open_trades']
    assert hasattr(hyperopt, "position_stacking")
예제 #3
0
def test_generate_optimizer(mocker, default_conf) -> None:
    default_conf.update({'config': 'config.json.example'})
    default_conf.update({'timerange': None})
    default_conf.update({'spaces': 'all'})
    default_conf.update({'hyperopt_min_trades': 1})

    trades = [
        ('POWR/BTC', 0.023117, 0.000233, 100)
    ]
    labels = ['currency', 'profit_percent', 'profit_abs', 'trade_duration']
    backtest_result = pd.DataFrame.from_records(trades, columns=labels)

    mocker.patch(
        'freqtrade.optimize.hyperopt.Hyperopt.backtest',
        MagicMock(return_value=backtest_result)
    )
    mocker.patch(
        'freqtrade.optimize.hyperopt.get_timeframe',
        MagicMock(return_value=(Arrow(2017, 12, 10), Arrow(2017, 12, 13)))
    )
    patch_exchange(mocker)
    mocker.patch('freqtrade.optimize.hyperopt.load', MagicMock())

    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,
    }
    response_expected = {
        'loss': 1.9840569076926293,
        'result': '     1 trades. Avg profit  2.31%. Total profit  0.00023300 BTC '
                  '(   2.31Σ%). Avg duration 100.0 mins.',
        'params': optimizer_param
    }

    hyperopt = Hyperopt(default_conf)
    generate_optimizer_value = hyperopt.generate_optimizer(list(optimizer_param.values()))
    assert generate_optimizer_value == response_expected
예제 #4
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)
    mocker.patch('freqtrade.configuration.Configuration._load_config_file',
                 lambda *args, **kwargs: default_conf)
    reconfigure_mock = mocker.patch('freqtrade.main.Worker._reconfigure',
                                    MagicMock())

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

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

    assert log_has('Using config: config.json.example ...',
                   caplog.record_tuples)
    assert worker_mock.call_count == 4
    assert reconfigure_mock.call_count == 1
    assert isinstance(worker.freqtrade, FreqtradeBot)
예제 #5
0
def test_reconfigure(mocker, default_conf) -> None:
    patch_exchange(mocker)
    mocker.patch('freqtrade.freqtradebot.FreqtradeBot.cleanup', MagicMock())
    mocker.patch('freqtrade.worker.Worker._worker',
                 MagicMock(side_effect=OperationalException('Oh snap!')))
    mocker.patch('freqtrade.configuration.Configuration._load_config_file',
                 lambda *args, **kwargs: default_conf)
    mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
    mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock())

    args = Arguments(['-c', 'config.json.example'], '').get_parsed_arg()
    worker = Worker(args=args, config=default_conf)
    freqtrade = worker.freqtrade

    # Renew mock to return modified data
    conf = deepcopy(default_conf)
    conf['stake_amount'] += 1
    mocker.patch('freqtrade.configuration.Configuration._load_config_file',
                 lambda *args, **kwargs: conf)

    worker._config = conf
    # reconfigure should return a new instance
    worker._reconfigure()
    freqtrade2 = worker.freqtrade

    # Verify we have a new instance with the new config
    assert freqtrade is not freqtrade2
    assert freqtrade.config['stake_amount'] + 1 == freqtrade2.config[
        'stake_amount']
예제 #6
0
def test_rpc_edge_disabled(mocker, default_conf) -> None:
    patch_exchange(mocker)
    mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
    freqtradebot = FreqtradeBot(default_conf)
    rpc = RPC(freqtradebot)
    with pytest.raises(RPCException, match=r'Edge is not enabled.'):
        rpc._rpc_edge()
예제 #7
0
def test_daily_wrong_input(default_conf, update, ticker, mocker) -> None:
    patch_exchange(mocker)
    mocker.patch.multiple('freqtrade.exchange.Exchange', get_ticker=ticker)
    msg_mock = MagicMock()
    mocker.patch.multiple('freqtrade.rpc.telegram.Telegram',
                          _init=MagicMock(),
                          _send_msg=msg_mock)
    mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())

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

    # Try invalid data
    msg_mock.reset_mock()
    freqtradebot.state = State.RUNNING
    update.message.text = '/daily -2'
    telegram._daily(bot=MagicMock(), update=update)
    assert msg_mock.call_count == 1
    assert 'must be an integer greater than 0' in msg_mock.call_args_list[0][
        0][0]

    # Try invalid data
    msg_mock.reset_mock()
    freqtradebot.state = State.RUNNING
    update.message.text = '/daily today'
    telegram._daily(bot=MagicMock(), update=update)
    assert str('Daily Profit over the last 7 days'
               ) in msg_mock.call_args_list[0][0][0]
예제 #8
0
def test_backtesting_start_no_data(default_conf, mocker, caplog) -> None:
    def get_timeframe(input1, input2):
        return Arrow(2017, 11, 14, 21, 17), Arrow(2017, 11, 14, 22, 59)

    mocker.patch('freqtrade.optimize.load_data', MagicMock(return_value={}))
    mocker.patch('freqtrade.exchange.Exchange.refresh_tickers', MagicMock())
    patch_exchange(mocker)
    mocker.patch.multiple(
        'freqtrade.optimize.backtesting.Backtesting',
        backtest=MagicMock(),
        _generate_text_table=MagicMock(return_value='1'),
        get_timeframe=get_timeframe,
    )

    default_conf['exchange']['pair_whitelist'] = ['UNITTEST/BTC']
    default_conf['ticker_interval'] = "1m"
    default_conf['live'] = False
    default_conf['datadir'] = None
    default_conf['export'] = None
    default_conf['timerange'] = '20180101-20180102'

    backtesting = Backtesting(default_conf)
    backtesting.start()
    # check the logs, that will contain the backtest result

    assert log_has('No data found. Terminating.', caplog.record_tuples)
예제 #9
0
def test_backtest_multi_pair(default_conf, fee, mocker, tres, pair):
    def _trend_alternate_hold(dataframe=None, metadata=None):
        """
        Buy every xth candle - sell every other xth -2 (hold on to pairs a bit)
        """
        if metadata['pair'] in ('ETH/BTC', 'LTC/BTC'):
            multi = 20
        else:
            multi = 18
        dataframe['buy'] = np.where(dataframe.index % multi == 0, 1, 0)
        dataframe['sell'] = np.where(
            (dataframe.index + multi - 2) % multi == 0, 1, 0)
        return dataframe

    mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
    patch_exchange(mocker)

    pairs = ['ADA/BTC', 'DASH/BTC', 'ETH/BTC', 'LTC/BTC', 'NXT/BTC']
    data = history.load_data(datadir=None, ticker_interval='5m', pairs=pairs)
    # Only use 500 lines to increase performance
    data = trim_dictlist(data, -500)

    # Remove data for one pair from the beginning of the data
    data[pair] = data[pair][tres:]
    # We need to enable sell-signal - otherwise it sells on ROI!!
    default_conf['experimental'] = {"use_sell_signal": True}
    default_conf['ticker_interval'] = '5m'

    backtesting = Backtesting(default_conf)
    backtesting.advise_buy = _trend_alternate_hold  # Override
    backtesting.advise_sell = _trend_alternate_hold  # Override

    data_processed = backtesting.strategy.tickerdata_to_dataframe(data)
    min_date, max_date = get_timeframe(data_processed)
    backtest_conf = {
        'stake_amount': default_conf['stake_amount'],
        'processed': data_processed,
        'max_open_trades': 3,
        'position_stacking': False,
        'start_date': min_date,
        'end_date': max_date,
    }

    results = backtesting.backtest(backtest_conf)

    # Make sure we have parallel trades
    assert len(evaluate_result_multi(results, '5min', 2)) > 0
    # make sure we don't have trades with more than configured max_open_trades
    assert len(evaluate_result_multi(results, '5min', 3)) == 0

    backtest_conf = {
        'stake_amount': default_conf['stake_amount'],
        'processed': data_processed,
        'max_open_trades': 1,
        'position_stacking': False,
        'start_date': min_date,
        'end_date': max_date,
    }
    results = backtesting.backtest(backtest_conf)
    assert len(evaluate_result_multi(results, '5min', 1)) == 0
예제 #10
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),
                          validate_pairs=MagicMock(return_value={}))
    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_trade()
    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(bot=MagicMock(), update=update)
    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]
예제 #11
0
def test_main_keyboard_interrupt(mocker, default_conf, caplog) -> None:
    """
    Test main() function
    In this test we are skipping the while True loop by throwing an exception.
    """
    patch_exchange(mocker)
    mocker.patch.multiple(
        'freqtrade.freqtradebot.FreqtradeBot',
        _init_modules=MagicMock(),
        worker=MagicMock(side_effect=KeyboardInterrupt),
        cleanup=MagicMock(),
    )
    mocker.patch('freqtrade.configuration.Configuration._load_config_file',
                 lambda *args, **kwargs: default_conf)
    mocker.patch('freqtrade.freqtradebot.CryptoToFiatConverter', MagicMock())
    mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())

    args = ['-c', 'config.json.example']

    # Test Main + the KeyboardInterrupt exception
    with pytest.raises(SystemExit):
        main(args)
    assert log_has('Using config: config.json.example ...',
                   caplog.record_tuples)
    assert log_has('SIGINT received, aborting ...', caplog.record_tuples)
예제 #12
0
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.multiprocessing.cpu_count',
                 MagicMock(return_value=1))
    parallel = mocker.patch(
        'freqtrade.optimize.hyperopt.Hyperopt.run_optimizer_parallel',
        MagicMock(return_value=[{
            'loss': 1,
            'result': 'foo result',
            'params': {}
        }]))
    patch_exchange(mocker)

    default_conf.update({'config': 'config.json.example'})
    default_conf.update({'epochs': 1})
    default_conf.update({'timerange': None})
    default_conf.update({'spaces': 'all'})

    hyperopt = Hyperopt(default_conf)
    hyperopt.tickerdata_to_dataframe = MagicMock()

    hyperopt.start()
    parallel.assert_called_once()

    assert 'Best result:\nfoo result\nwith values:\n{}' in caplog.text
    assert dumper.called
예제 #13
0
def test_reconfigure(mocker, default_conf) -> None:
    """ Test recreate() function """
    patch_exchange(mocker)
    mocker.patch.multiple(
        'freqtrade.freqtradebot.FreqtradeBot',
        _init_modules=MagicMock(),
        worker=MagicMock(side_effect=OperationalException('Oh snap!')),
        cleanup=MagicMock(),
    )
    mocker.patch('freqtrade.configuration.Configuration._load_config_file',
                 lambda *args, **kwargs: default_conf)
    mocker.patch('freqtrade.freqtradebot.CryptoToFiatConverter', MagicMock())
    mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())

    freqtrade = FreqtradeBot(default_conf)

    # Renew mock to return modified data
    conf = deepcopy(default_conf)
    conf['stake_amount'] += 1
    mocker.patch('freqtrade.configuration.Configuration._load_config_file',
                 lambda *args, **kwargs: conf)

    # reconfigure should return a new instance
    freqtrade2 = reconfigure(
        freqtrade,
        Arguments(['-c', 'config.json.example'], '').get_parsed_arg())

    # Verify we have a new instance with the new config
    assert freqtrade is not freqtrade2
    assert freqtrade.config['stake_amount'] + 1 == freqtrade2.config[
        'stake_amount']
예제 #14
0
def test_main_reload_conf(mocker, default_conf, caplog) -> None:
    """
    Test main() function
    In this test we are skipping the while True loop by throwing an exception.
    """
    patch_exchange(mocker)
    mocker.patch.multiple(
        'freqtrade.freqtradebot.FreqtradeBot',
        _init_modules=MagicMock(),
        worker=MagicMock(return_value=State.RELOAD_CONF),
        cleanup=MagicMock(),
    )
    mocker.patch('freqtrade.configuration.Configuration._load_config_file',
                 lambda *args, **kwargs: default_conf)
    mocker.patch('freqtrade.freqtradebot.CryptoToFiatConverter', MagicMock())
    mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())

    # Raise exception as side effect to avoid endless loop
    reconfigure_mock = mocker.patch('freqtrade.main.reconfigure',
                                    MagicMock(side_effect=Exception))

    with pytest.raises(SystemExit):
        main(['-c', 'config.json.example'])

    assert reconfigure_mock.call_count == 1
    assert log_has('Using config: config.json.example ...',
                   caplog.record_tuples)
예제 #15
0
def test_fmin_throw_value_error(mocker, init_hyperopt, default_conf,
                                caplog) -> None:
    mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock())
    mocker.patch('freqtrade.optimize.hyperopt.fmin', side_effect=ValueError())

    conf = deepcopy(default_conf)
    conf.update({'config': 'config.json.example'})
    conf.update({'epochs': 1})
    conf.update({'timerange': None})
    conf.update({'spaces': 'all'})
    patch_exchange(mocker)

    StrategyResolver({'strategy': 'DefaultStrategy'})
    hyperopt = Hyperopt(conf)
    hyperopt.trials = create_trials(mocker)
    hyperopt.tickerdata_to_dataframe = MagicMock()

    hyperopt.start()

    exists = [
        'Best Result:',
        'Sorry, Hyperopt was not able to find good parameters. Please try with more epochs '
        '(param: -e).',
    ]

    for line in exists:
        assert line in caplog.text
예제 #16
0
def test_generate_text_table(default_conf, mocker):
    """
    Test Backtesting.generate_text_table() method
    """
    patch_exchange(mocker)
    backtesting = Backtesting(default_conf)

    results = pd.DataFrame({
        'pair': ['ETH/BTC', 'ETH/BTC'],
        'profit_percent': [0.1, 0.2],
        'profit_abs': [0.2, 0.4],
        'trade_duration': [10, 30],
        'profit': [2, 0],
        'loss': [0, 0]
    })

    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 |')
    assert backtesting._generate_text_table(data={'ETH/BTC': {}},
                                            results=results) == result_str
예제 #17
0
def test_download_data_days(mocker, markets, caplog):
    dl_mock = mocker.patch('freqtrade.utils.download_pair_history',
                           MagicMock())
    patch_exchange(mocker)
    mocker.patch('freqtrade.exchange.Exchange.markets',
                 PropertyMock(return_value=markets))
    mocker.patch.object(Path, "exists", MagicMock(return_value=True))
    mocker.patch.object(Path, "unlink", MagicMock())

    args = [
        "download-data",
        "--exchange",
        "binance",
        "--pairs",
        "ETH/BTC",
        "XRP/BTC",
        "--days",
        "20",
    ]

    start_download_data(get_args(args))

    assert dl_mock.call_count == 4
    assert dl_mock.call_args[1]['timerange'].starttype == 'date'

    assert log_has("Downloading pair ETH/BTC, interval 1m.", caplog)
예제 #18
0
def test_backtest_1min_ticker_interval(default_conf, fee, mocker) -> None:
    """
    Test Backtesting.backtest() method with 1 min ticker
    """
    mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
    patch_exchange(mocker)
    backtesting = Backtesting(default_conf)

    # Run a backtesting for an exiting 5min ticker_interval
    data = optimize.load_data(None,
                              ticker_interval='1m',
                              pairs=['UNITTEST/BTC'])
    data = trim_dictlist(data, -200)
    results = backtesting.backtest({
        'stake_amount':
        default_conf['stake_amount'],
        'processed':
        backtesting.tickerdata_to_dataframe(data),
        'max_open_trades':
        1,
        'realistic':
        True
    })
    assert not results.empty
    assert len(results) == 1
예제 #19
0
def test_rpc_status_table(default_conf, ticker, fee, markets, mocker) -> None:
    patch_exchange(mocker)
    mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
    mocker.patch.multiple('freqtrade.exchange.Exchange',
                          get_ticker=ticker,
                          get_fee=fee,
                          markets=PropertyMock(return_value=markets))

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

    freqtradebot.state = State.RUNNING
    with pytest.raises(RPCException, match=r'.*no active order*'):
        rpc._rpc_status_table()

    freqtradebot.create_trade()
    result = rpc._rpc_status_table()
    assert 'instantly' in result['Since'].all()
    assert 'ETH/BTC' in result['Pair'].all()
    assert '-0.59%' in result['Profit'].all()

    mocker.patch(
        'freqtrade.exchange.Exchange.get_ticker',
        MagicMock(
            side_effect=DependencyException(f"Pair 'ETH/BTC' not available")))
    # invalidate ticker cache
    rpc._freqtrade.exchange._cached_ticker = {}
    result = rpc._rpc_status_table()
    assert 'instantly' in result['Since'].all()
    assert 'ETH/BTC' in result['Pair'].all()
    assert 'nan%' in result['Profit'].all()
예제 #20
0
def test_authorized_only(default_conf, mocker, caplog) -> None:
    patch_coinmarketcap(mocker)
    patch_exchange(mocker, None)

    chat = Chat(0, 0)
    update = Update(randint(1, 100))
    update.message = Message(randint(1, 100), 0, datetime.utcnow(), chat)

    default_conf['telegram']['enabled'] = False
    bot = FreqtradeBot(default_conf)
    patch_get_signal(bot, (True, False))
    dummy = DummyCls(bot)
    dummy.dummy_handler(bot=MagicMock(), update=update)
    assert dummy.state['called'] is True
    assert log_has(
        'Executing handler: dummy_handler for chat_id: 0',
        caplog.record_tuples
    )
    assert not log_has(
        'Rejected unauthorized message from: 0',
        caplog.record_tuples
    )
    assert not log_has(
        'Exception occurred within Telegram module',
        caplog.record_tuples
    )
예제 #21
0
def test_edge_init(mocker, edge_conf) -> None:
    patch_exchange(mocker)
    edge_conf['stake_amount'] = 20
    edge_cli = EdgeCli(edge_conf)
    assert edge_cli.config == edge_conf
    assert edge_cli.config['stake_amount'] == 'unlimited'
    assert callable(edge_cli.edge.calculate)
예제 #22
0
def test_backtesting_start(default_conf, mocker, caplog) -> None:
    def get_timeframe(input1, input2):
        return Arrow(2017, 11, 14, 21, 17), Arrow(2017, 11, 14, 22, 59)

    mocker.patch('freqtrade.optimize.load_data', mocked_load_data)
    mocker.patch('freqtrade.exchange.Exchange.refresh_tickers', MagicMock())
    patch_exchange(mocker)
    mocker.patch.multiple(
        'freqtrade.optimize.backtesting.Backtesting',
        backtest=MagicMock(),
        _generate_text_table=MagicMock(return_value='1'),
        get_timeframe=get_timeframe,
    )

    default_conf['exchange']['pair_whitelist'] = ['UNITTEST/BTC']
    default_conf['ticker_interval'] = 1
    default_conf['live'] = False
    default_conf['datadir'] = None
    default_conf['export'] = None
    default_conf['timerange'] = '-100'

    backtesting = Backtesting(default_conf)
    backtesting.start()
    # check the logs, that will contain the backtest result
    exists = [
        '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 '
        'up to 2017-11-14T22:59:00+00:00 (0 days)..'
    ]
    for line in exists:
        assert log_has(line, caplog.record_tuples)
예제 #23
0
def test_rpc_status_table(default_conf, ticker, fee, markets, mocker) -> None:
    patch_coinmarketcap(mocker)
    patch_exchange(mocker)
    mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
    mocker.patch.multiple('freqtrade.exchange.Exchange',
                          get_ticker=ticker,
                          get_fee=fee,
                          get_markets=markets)

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

    freqtradebot.state = State.STOPPED
    with pytest.raises(RPCException, match=r'.*trader is not running*'):
        rpc._rpc_status_table()

    freqtradebot.state = State.RUNNING
    with pytest.raises(RPCException, match=r'.*no active order*'):
        rpc._rpc_status_table()

    freqtradebot.create_trade()
    result = rpc._rpc_status_table()
    assert 'just now' in result['Since'].all()
    assert 'ETH/BTC' in result['Pair'].all()
    assert '-0.59%' in result['Profit'].all()
예제 #24
0
def test_backtest(default_conf, fee, mocker) -> None:
    mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
    patch_exchange(mocker)
    backtesting = Backtesting(default_conf)
    pair = 'UNITTEST/BTC'
    timerange = TimeRange(None, 'line', 0, -201)
    data = history.load_data(datadir=None,
                             ticker_interval='5m',
                             pairs=['UNITTEST/BTC'],
                             timerange=timerange)
    data_processed = backtesting.strategy.tickerdata_to_dataframe(data)
    min_date, max_date = get_timeframe(data_processed)
    results = backtesting.backtest({
        'stake_amount': default_conf['stake_amount'],
        'processed': data_processed,
        'max_open_trades': 10,
        'position_stacking': False,
        'start_date': min_date,
        'end_date': max_date,
    })
    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_time':
        pd.to_datetime([
            Arrow(2018, 1, 29, 18, 40, 0).datetime,
            Arrow(2018, 1, 30, 3, 30, 0).datetime
        ],
                       utc=True),
        'close_time':
        pd.to_datetime([
            Arrow(2018, 1, 29, 22, 35, 0).datetime,
            Arrow(2018, 1, 30, 4, 10, 0).datetime
        ],
                       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.testing.assert_frame_equal(results, expected)
    data_pair = data_processed[pair]
    for _, t in results.iterrows():
        ln = data_pair.loc[data_pair["date"] == t["open_time"]]
        # 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_time"]]
        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))
예제 #25
0
def test_backtest_start_multi_strat(default_conf, mocker, caplog):
    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)
    backtestmock = MagicMock()
    mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest', backtestmock)
    gen_table_mock = MagicMock()
    mocker.patch('freqtrade.optimize.backtesting.Backtesting._generate_text_table', gen_table_mock)
    gen_strattable_mock = MagicMock()
    mocker.patch('freqtrade.optimize.backtesting.Backtesting._generate_text_table_strategy',
                 gen_strattable_mock)
    mocker.patch('freqtrade.configuration.open', mocker.mock_open(
        read_data=json.dumps(default_conf)
    ))

    args = [
        '--config', 'config.json',
        '--datadir', 'freqtrade/tests/testdata',
        'backtesting',
        '--ticker-interval', '1m',
        '--live',
        '--timerange', '-100',
        '--enable-position-stacking',
        '--disable-max-market-positions',
        '--strategy-list',
        'DefaultStrategy',
        'TestStrategy',
    ]
    args = get_args(args)
    start(args)
    # 2 backtests, 4 tables
    assert backtestmock.call_count == 2
    assert gen_table_mock.call_count == 4
    assert gen_strattable_mock.call_count == 1

    # check the logs, that will contain the backtest result
    exists = [
        'Parameter -i/--ticker-interval detected ...',
        'Using ticker_interval: 1m ...',
        'Parameter -l/--live detected ...',
        'Ignoring max_open_trades (--disable-max-market-positions was used) ...',
        'Parameter --timerange detected: -100 ...',
        'Using data folder: freqtrade/tests/testdata ...',
        '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)..',
        'Parameter --enable-position-stacking detected ...',
        'Running backtesting for Strategy DefaultStrategy',
        'Running backtesting for Strategy TestStrategy',
    ]

    for line in exists:
        assert log_has(line, caplog.record_tuples)
예제 #26
0
def test_status(default_conf, update, mocker, fee, ticker, markets) -> None:
    update.message.chat.id = 123
    default_conf['telegram']['enabled'] = False
    default_conf['telegram']['chat_id'] = 123

    patch_exchange(mocker)
    mocker.patch.multiple(
        'freqtrade.exchange.Exchange',
        get_ticker=ticker,
        get_fee=fee,
        markets=PropertyMock(markets)
    )
    msg_mock = MagicMock()
    status_table = MagicMock()
    mocker.patch.multiple(
        'freqtrade.rpc.telegram.Telegram',
        _init=MagicMock(),
        _rpc_trade_status=MagicMock(return_value=[{
            'trade_id': 1,
            'pair': 'ETH/BTC',
            'base_currency': 'BTC',
            '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,
            'amount': 90.99181074,
            'stake_amount': 90.99181074,
            'close_profit': None,
            'current_profit': -0.59,
            'initial_stop_loss': 1.098e-05,
            'stop_loss': 1.099e-05,
            'initial_stop_loss_pct': -0.05,
            'stop_loss_pct': -0.01,
            'open_order': '(limit buy rem=0.00000000)'
        }]),
        _status_table=status_table,
        _send_msg=msg_mock
    )
    mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())

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

    # Create some test data
    for _ in range(3):
        freqtradebot.create_trades()

    telegram._status(bot=MagicMock(), update=update)
    assert msg_mock.call_count == 1

    update.message.text = MagicMock()
    update.message.text.replace = MagicMock(return_value='table 2 3')
    telegram._status(bot=MagicMock(), update=update)
    assert status_table.call_count == 1
예제 #27
0
def test_rpc_whitelist(mocker, default_conf) -> None:
    patch_exchange(mocker)
    mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())

    freqtradebot = FreqtradeBot(default_conf)
    rpc = RPC(freqtradebot)
    ret = rpc._rpc_whitelist()
    assert ret['method'] == 'StaticPairList'
    assert ret['whitelist'] == default_conf['exchange']['pair_whitelist']
예제 #28
0
def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee,
                       limit_buy_order, limit_sell_order, markets, mocker) -> None:
    patch_coinmarketcap(mocker, value={'price_usd': 15000.0})
    patch_exchange(mocker)
    mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0)
    mocker.patch.multiple(
        'freqtrade.exchange.Exchange',
        get_ticker=ticker,
        get_fee=fee,
        get_markets=markets
    )
    msg_mock = MagicMock()
    mocker.patch.multiple(
        'freqtrade.rpc.telegram.Telegram',
        _init=MagicMock(),
        _send_msg=msg_mock
    )
    mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())

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

    telegram._profit(bot=MagicMock(), update=update)
    assert msg_mock.call_count == 1
    assert 'no closed trade' in msg_mock.call_args_list[0][0][0]
    msg_mock.reset_mock()

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

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

    telegram._profit(bot=MagicMock(), update=update)
    assert msg_mock.call_count == 1
    assert 'no closed trade' in msg_mock.call_args_list[-1][0][0]
    msg_mock.reset_mock()

    # Update the ticker with a market going up
    mocker.patch('freqtrade.exchange.Exchange.get_ticker', ticker_sell_up)
    trade.update(limit_sell_order)

    trade.close_date = datetime.utcnow()
    trade.is_open = False

    telegram._profit(bot=MagicMock(), update=update)
    assert msg_mock.call_count == 1
    assert '*ROI:* Close trades' in msg_mock.call_args_list[-1][0][0]
    assert '∙ `0.00006217 BTC (6.20%)`' in msg_mock.call_args_list[-1][0][0]
    assert '∙ `0.933 USD`' in msg_mock.call_args_list[-1][0][0]
    assert '*ROI:* All trades' in msg_mock.call_args_list[-1][0][0]
    assert '∙ `0.00006217 BTC (6.20%)`' in msg_mock.call_args_list[-1][0][0]
    assert '∙ `0.933 USD`' in msg_mock.call_args_list[-1][0][0]

    assert '*Best Performing:* `ETH/BTC: 6.20%`' in msg_mock.call_args_list[-1][0][0]
예제 #29
0
def test_get_timeframe(default_conf, mocker) -> None:
    patch_exchange(mocker)
    backtesting = Backtesting(default_conf)

    data = backtesting.tickerdata_to_dataframe(
        optimize.load_data(None, ticker_interval='1m', pairs=['UNITTEST/BTC']))
    min_date, max_date = backtesting.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'
예제 #30
0
def test_rpcforcebuy_disabled(mocker, default_conf) -> None:
    patch_exchange(mocker)
    mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())

    freqtradebot = FreqtradeBot(default_conf)
    patch_get_signal(freqtradebot, (True, False))
    rpc = RPC(freqtradebot)
    pair = 'ETH/BTC'
    with pytest.raises(RPCException, match=r'Forcebuy not enabled.'):
        rpc._rpc_forcebuy(pair, None)