def test_api_backtesting(botclient, mocker, fee, caplog):
    ftbot, client = botclient
    mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)

    # Backtesting not started yet
    rc = client_get(client, f"{BASE_URI}/backtest")
    assert_response(rc)

    result = rc.json()
    assert result['status'] == 'not_started'
    assert not result['running']
    assert result['status_msg'] == 'Backtest not yet executed'
    assert result['progress'] == 0

    # Reset backtesting
    rc = client_delete(client, f"{BASE_URI}/backtest")
    assert_response(rc)
    result = rc.json()
    assert result['status'] == 'reset'
    assert not result['running']
    assert result['status_msg'] == 'Backtest reset'

    # start backtesting
    data = {
        "strategy": "DefaultStrategy",
        "timeframe": "5m",
        "timerange": "20180110-20180111",
        "max_open_trades": 3,
        "stake_amount": 100,
        "dry_run_wallet": 1000,
        "enable_protections": False
    }
    rc = client_post(client, f"{BASE_URI}/backtest", data=json.dumps(data))
    assert_response(rc)
    result = rc.json()

    assert result['status'] == 'running'
    assert result['progress'] == 0
    assert result['running']
    assert result['status_msg'] == 'Backtest started'

    rc = client_get(client, f"{BASE_URI}/backtest")
    assert_response(rc)

    result = rc.json()
    assert result['status'] == 'ended'
    assert not result['running']
    assert result['status_msg'] == 'Backtest ended'
    assert result['progress'] == 1
    assert result['backtest_result']

    rc = client_get(client, f"{BASE_URI}/backtest/abort")
    assert_response(rc)
    result = rc.json()
    assert result['status'] == 'not_running'
    assert not result['running']
    assert result['status_msg'] == 'Backtest ended'

    # Simulate running backtest
    ApiServer._bgtask_running = True
    rc = client_get(client, f"{BASE_URI}/backtest/abort")
    assert_response(rc)
    result = rc.json()
    assert result['status'] == 'stopping'
    assert not result['running']
    assert result['status_msg'] == 'Backtest ended'

    # Get running backtest...
    rc = client_get(client, f"{BASE_URI}/backtest")
    assert_response(rc)
    result = rc.json()
    assert result['status'] == 'running'
    assert result['running']
    assert result['step'] == "backtest"
    assert result['status_msg'] == "Backtest running"

    # Try delete with task still running
    rc = client_delete(client, f"{BASE_URI}/backtest")
    assert_response(rc)
    result = rc.json()
    assert result['status'] == 'running'

    # Post to backtest that's still running
    rc = client_post(client, f"{BASE_URI}/backtest", data=json.dumps(data))
    assert_response(rc, 502)
    result = rc.json()
    assert 'Bot Background task already running' in result['error']

    ApiServer._bgtask_running = False

    mocker.patch(
        'freqtrade.optimize.backtesting.Backtesting.backtest_one_strategy',
        side_effect=DependencyException())
    rc = client_post(client, f"{BASE_URI}/backtest", data=json.dumps(data))
    assert log_has("Backtesting caused an error: ", caplog)

    # Delete backtesting to avoid leakage since the backtest-object may stick around.
    rc = client_delete(client, f"{BASE_URI}/backtest")
    assert_response(rc)

    result = rc.json()
    assert result['status'] == 'reset'
    assert not result['running']
    assert result['status_msg'] == 'Backtest reset'
Exemple #2
0
def test_api_run(default_conf, mocker, caplog):
    default_conf.update({
        "api_server": {
            "enabled": True,
            "listen_ip_address": "127.0.0.1",
            "listen_port": 8080,
            "username": "******",
            "password": "******",
        }
    })
    mocker.patch('freqtrade.rpc.telegram.Updater', MagicMock())

    server_mock = MagicMock()
    mocker.patch('freqtrade.rpc.api_server.webserver.UvicornServer',
                 server_mock)

    apiserver = ApiServer(RPC(get_patched_freqtradebot(mocker, default_conf)),
                          default_conf)

    assert server_mock.call_count == 1
    assert apiserver._config == default_conf
    apiserver.start_api()
    assert server_mock.call_count == 2
    assert server_mock.call_args_list[0][0][0].host == "127.0.0.1"
    assert server_mock.call_args_list[0][0][0].port == 8080
    assert isinstance(server_mock.call_args_list[0][0][0].app, FastAPI)

    assert log_has("Starting HTTP Server at 127.0.0.1:8080", caplog)
    assert log_has("Starting Local Rest Server.", caplog)

    # Test binding to public
    caplog.clear()
    server_mock.reset_mock()
    apiserver._config.update({
        "api_server": {
            "enabled": True,
            "listen_ip_address": "0.0.0.0",
            "listen_port": 8089,
            "password": "",
        }
    })
    apiserver.start_api()

    assert server_mock.call_count == 1
    assert server_mock.call_args_list[0][0][0].host == "0.0.0.0"
    assert server_mock.call_args_list[0][0][0].port == 8089
    assert isinstance(server_mock.call_args_list[0][0][0].app, FastAPI)
    assert log_has("Starting HTTP Server at 0.0.0.0:8089", caplog)
    assert log_has("Starting Local Rest Server.", caplog)
    assert log_has(
        "SECURITY WARNING - Local Rest Server listening to external connections",
        caplog)
    assert log_has(
        "SECURITY WARNING - This is insecure please set to your loopback,"
        "e.g 127.0.0.1 in config.json", caplog)
    assert log_has(
        "SECURITY WARNING - No password for local REST Server defined. "
        "Please make sure that this is intentional!", caplog)
    assert log_has_re(
        "SECURITY WARNING - `jwt_secret_key` seems to be default.*", caplog)

    # Test crashing API server
    caplog.clear()
    mocker.patch('freqtrade.rpc.api_server.webserver.UvicornServer',
                 MagicMock(side_effect=Exception))
    apiserver.start_api()
    assert log_has("Api server failed to start.", caplog)
def test_migrate_mid_state(mocker, default_conf, fee, caplog):
    """
    Test Database migration (starting with new pairformat)
    """
    caplog.set_level(logging.DEBUG)
    amount = 103.223
    create_table_old = """CREATE TABLE IF NOT EXISTS "trades" (
                                id INTEGER NOT NULL,
                                exchange VARCHAR NOT NULL,
                                pair VARCHAR NOT NULL,
                                is_open BOOLEAN NOT NULL,
                                fee_open FLOAT NOT NULL,
                                fee_close FLOAT NOT NULL,
                                open_rate FLOAT,
                                close_rate FLOAT,
                                close_profit FLOAT,
                                stake_amount FLOAT NOT NULL,
                                amount FLOAT,
                                open_date DATETIME NOT NULL,
                                close_date DATETIME,
                                open_order_id VARCHAR,
                                PRIMARY KEY (id),
                                CHECK (is_open IN (0, 1))
                                );"""
    insert_table_old = """INSERT INTO trades (exchange, pair, is_open, fee_open, fee_close,
                          open_rate, stake_amount, amount, open_date)
                          VALUES ('binance', 'ETC/BTC', 1, {fee}, {fee},
                          0.00258580, {stake}, {amount},
                          '2019-11-28 12:44:24.000000')
                          """.format(fee=fee.return_value,
                                     stake=default_conf.get("stake_amount"),
                                     amount=amount)
    engine = create_engine('sqlite://')
    mocker.patch('freqtrade.persistence.models.create_engine',
                 lambda *args, **kwargs: engine)

    # Create table using the old format
    engine.execute(create_table_old)
    engine.execute(insert_table_old)

    # Run init to test migration
    init(default_conf['db_url'], default_conf['dry_run'])

    assert len(Trade.query.filter(Trade.id == 1).all()) == 1
    trade = Trade.query.filter(Trade.id == 1).first()
    assert trade.fee_open == fee.return_value
    assert trade.fee_close == fee.return_value
    assert trade.open_rate_requested is None
    assert trade.close_rate_requested is None
    assert trade.is_open == 1
    assert trade.amount == amount
    assert trade.stake_amount == default_conf.get("stake_amount")
    assert trade.pair == "ETC/BTC"
    assert trade.exchange == "binance"
    assert trade.max_rate == 0.0
    assert trade.stop_loss == 0.0
    assert trade.initial_stop_loss == 0.0
    assert trade.open_trade_price == trade._calc_open_trade_price()
    assert log_has("trying trades_bak0", caplog)
    assert log_has(
        "Running database migration for trades - backup: trades_bak0", caplog)
Exemple #4
0
def test_VolumePairList_whitelist_gen(mocker, whitelist_conf, shitcoinmarkets,
                                      tickers, ohlcv_history, pairlists,
                                      base_currency, whitelist_result,
                                      caplog) -> None:
    whitelist_conf['pairlists'] = pairlists
    whitelist_conf['stake_currency'] = base_currency

    ohlcv_data = {
        ('ETH/BTC', '1d'): ohlcv_history,
        ('TKN/BTC', '1d'): ohlcv_history,
        ('LTC/BTC', '1d'): ohlcv_history,
        ('XRP/BTC', '1d'): ohlcv_history,
        ('HOT/BTC', '1d'): ohlcv_history,
    }

    mocker.patch('freqtrade.exchange.Exchange.exchange_has',
                 MagicMock(return_value=True))

    if whitelist_result == 'static_in_the_middle':
        with pytest.raises(
                OperationalException,
                match=r"StaticPairList can only be used in the first position "
                r"in the list of Pairlist Handlers."):
            freqtrade = get_patched_freqtradebot(mocker, whitelist_conf)
        return

    freqtrade = get_patched_freqtradebot(mocker, whitelist_conf)
    mocker.patch.multiple('freqtrade.exchange.Exchange',
                          get_tickers=tickers,
                          markets=PropertyMock(return_value=shitcoinmarkets))
    mocker.patch.multiple(
        'freqtrade.exchange.Exchange',
        refresh_latest_ohlcv=MagicMock(return_value=ohlcv_data),
    )

    # Provide for PerformanceFilter's dependency
    mocker.patch.multiple('freqtrade.persistence.Trade',
                          get_overall_performance=MagicMock(return_value=[]))

    # Set whitelist_result to None if pairlist is invalid and should produce exception
    if whitelist_result == 'filter_at_the_beginning':
        with pytest.raises(
                OperationalException,
                match=
                r"This Pairlist Handler should not be used at the first position "
                r"in the list of Pairlist Handlers."):
            freqtrade.pairlists.refresh_pairlist()
    else:
        freqtrade.pairlists.refresh_pairlist()
        whitelist = freqtrade.pairlists.whitelist

        assert isinstance(whitelist, list)

        # Verify length of pairlist matches (used for ShuffleFilter without seed)
        if type(whitelist_result) is list:
            assert whitelist == whitelist_result
        else:
            len(whitelist) == whitelist_result

        for pairlist in pairlists:
            if pairlist['method'] == 'AgeFilter' and pairlist['min_days_listed'] and \
                    len(ohlcv_history) <= pairlist['min_days_listed']:
                assert log_has_re(
                    r'^Removed .* from whitelist, because age .* is less than '
                    r'.* day.*', caplog)
            if pairlist['method'] == 'PrecisionFilter' and whitelist_result:
                assert log_has_re(
                    r'^Removed .* from whitelist, because stop price .* '
                    r'would be <= stop limit.*', caplog)
            if pairlist['method'] == 'PriceFilter' and whitelist_result:
                assert (
                    log_has_re(
                        r'^Removed .* from whitelist, because 1 unit is .*%$',
                        caplog) or log_has_re(
                            r'^Removed .* from whitelist, '
                            r'because last price < .*%$', caplog)
                    or log_has_re(
                        r'^Removed .* from whitelist, '
                        r'because last price > .*%$', caplog)
                    or log_has_re(
                        r"^Removed .* from whitelist, because ticker\['last'\] "
                        r"is empty.*", caplog))
            if pairlist['method'] == 'VolumePairList':
                logmsg = (
                    "DEPRECATED: using any key other than quoteVolume for "
                    "VolumePairList is deprecated.")
                if pairlist['sort_key'] != 'quoteVolume':
                    assert log_has(logmsg, caplog)
                else:
                    assert not log_has(logmsg, caplog)
Exemple #5
0
def test_download_trades_history(trades_history, mocker, default_conf,
                                 testdatadir, caplog) -> None:

    ght_mock = MagicMock(
        side_effect=lambda pair, *args, **kwargs: (pair, trades_history))
    mocker.patch('freqtrade.exchange.Exchange.get_historic_trades', ght_mock)
    exchange = get_patched_exchange(mocker, default_conf)
    file1 = testdatadir / 'ETH_BTC-trades.json.gz'
    data_handler = get_datahandler(testdatadir, data_format='jsongz')
    _backup_file(file1)

    assert not file1.is_file()

    assert _download_trades_history(data_handler=data_handler,
                                    exchange=exchange,
                                    pair='ETH/BTC')
    assert log_has("New Amount of trades: 5", caplog)
    assert file1.is_file()

    ght_mock.reset_mock()
    since_time = int(trades_history[-3][0] // 1000)
    since_time2 = int(trades_history[-1][0] // 1000)
    timerange = TimeRange('date', None, since_time, 0)
    assert _download_trades_history(data_handler=data_handler,
                                    exchange=exchange,
                                    pair='ETH/BTC',
                                    timerange=timerange)

    assert ght_mock.call_count == 1
    # Check this in seconds - since we had to convert to seconds above too.
    assert int(ght_mock.call_args_list[0][1]['since'] //
               1000) == since_time2 - 5
    assert ght_mock.call_args_list[0][1]['from_id'] is not None

    # clean files freshly downloaded
    _clean_test_file(file1)

    mocker.patch('freqtrade.exchange.Exchange.get_historic_trades',
                 MagicMock(side_effect=ValueError))

    assert not _download_trades_history(
        data_handler=data_handler, exchange=exchange, pair='ETH/BTC')
    assert log_has_re(
        'Failed to download historic trades for pair: "ETH/BTC".*', caplog)

    file2 = testdatadir / 'XRP_ETH-trades.json.gz'

    _backup_file(file2, True)

    ght_mock.reset_mock()
    mocker.patch('freqtrade.exchange.Exchange.get_historic_trades', ght_mock)
    # Since before first start date
    since_time = int(trades_history[0][0] // 1000) - 500
    timerange = TimeRange('date', None, since_time, 0)

    assert _download_trades_history(data_handler=data_handler,
                                    exchange=exchange,
                                    pair='XRP/ETH',
                                    timerange=timerange)

    assert ght_mock.call_count == 1

    assert int(ght_mock.call_args_list[0][1]['since'] // 1000) == since_time
    assert ght_mock.call_args_list[0][1]['from_id'] is None
    assert log_has_re(
        r'Start earlier than available data. Redownloading trades for.*',
        caplog)
    _clean_test_file(file2)
def test_migrate_new(mocker, default_conf, fee, caplog):
    """
    Test Database migration (starting with new pairformat)
    """
    caplog.set_level(logging.DEBUG)
    amount = 103.223
    # Always create all columns apart from the last!
    create_table_old = """CREATE TABLE IF NOT EXISTS "trades" (
                                id INTEGER NOT NULL,
                                exchange VARCHAR NOT NULL,
                                pair VARCHAR NOT NULL,
                                is_open BOOLEAN NOT NULL,
                                fee FLOAT NOT NULL,
                                open_rate FLOAT,
                                close_rate FLOAT,
                                close_profit FLOAT,
                                stake_amount FLOAT NOT NULL,
                                amount FLOAT,
                                open_date DATETIME NOT NULL,
                                close_date DATETIME,
                                open_order_id VARCHAR,
                                stop_loss FLOAT,
                                initial_stop_loss FLOAT,
                                max_rate FLOAT,
                                sell_reason VARCHAR,
                                strategy VARCHAR,
                                ticker_interval INTEGER,
                                stoploss_order_id VARCHAR,
                                PRIMARY KEY (id),
                                CHECK (is_open IN (0, 1))
                                );"""
    insert_table_old = """INSERT INTO trades (exchange, pair, is_open, fee,
                          open_rate, stake_amount, amount, open_date,
                          stop_loss, initial_stop_loss, max_rate, ticker_interval,
                          open_order_id, stoploss_order_id)
                          VALUES ('binance', 'ETC/BTC', 1, {fee},
                          0.00258580, {stake}, {amount},
                          '2019-11-28 12:44:24.000000',
                          0.0, 0.0, 0.0, '5m',
                          'buy_order', 'stop_order_id222')
                          """.format(fee=fee.return_value,
                                     stake=default_conf.get("stake_amount"),
                                     amount=amount)
    engine = create_engine('sqlite://')
    mocker.patch('freqtrade.persistence.models.create_engine',
                 lambda *args, **kwargs: engine)

    # Create table using the old format
    engine.execute(create_table_old)
    engine.execute("create index ix_trades_is_open on trades(is_open)")
    engine.execute("create index ix_trades_pair on trades(pair)")
    engine.execute(insert_table_old)

    # fake previous backup
    engine.execute("create table trades_bak as select * from trades")

    engine.execute("create table trades_bak1 as select * from trades")
    # Run init to test migration
    init(default_conf['db_url'], default_conf['dry_run'])

    assert len(Trade.query.filter(Trade.id == 1).all()) == 1
    trade = Trade.query.filter(Trade.id == 1).first()
    assert trade.fee_open == fee.return_value
    assert trade.fee_close == fee.return_value
    assert trade.open_rate_requested is None
    assert trade.close_rate_requested is None
    assert trade.is_open == 1
    assert trade.amount == amount
    assert trade.amount_requested == amount
    assert trade.stake_amount == default_conf.get("stake_amount")
    assert trade.pair == "ETC/BTC"
    assert trade.exchange == "binance"
    assert trade.max_rate == 0.0
    assert trade.min_rate is None
    assert trade.stop_loss == 0.0
    assert trade.initial_stop_loss == 0.0
    assert trade.sell_reason is None
    assert trade.strategy is None
    assert trade.timeframe == '5m'
    assert trade.stoploss_order_id == 'stop_order_id222'
    assert trade.stoploss_last_update is None
    assert log_has("trying trades_bak1", caplog)
    assert log_has("trying trades_bak2", caplog)
    assert log_has(
        "Running database migration for trades - backup: trades_bak2", caplog)
    assert trade.open_trade_price == trade._calc_open_trade_price()
    assert trade.close_profit_abs is None

    assert log_has("Moving open orders to Orders table.", caplog)
    orders = Order.query.all()
    assert len(orders) == 2
    assert orders[0].order_id == 'buy_order'
    assert orders[0].ft_order_side == 'buy'

    assert orders[1].order_id == 'stop_order_id222'
    assert orders[1].ft_order_side == 'stoploss'
Exemple #7
0
def test_setup_bt_configuration_with_arguments(mocker, default_conf,
                                               caplog) -> None:
    patched_configuration_load_config_file(mocker, default_conf)
    mocker.patch('freqtrade.configuration.configuration.create_datadir',
                 lambda c, x: x)

    args = [
        'backtesting',
        '--config',
        'config.json',
        '--strategy',
        'DefaultStrategy',
        '--datadir',
        '/foo/bar',
        '--ticker-interval',
        '1m',
        '--enable-position-stacking',
        '--disable-max-market-positions',
        '--timerange',
        ':100',
        '--export',
        '/bar/foo',
        '--export-filename',
        'foo_bar.json',
        '--fee',
        '0',
    ]

    config = setup_configuration(get_args(args), RunMode.BACKTEST)
    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.BACKTEST

    assert log_has('Using data directory: {} ...'.format(config['datadir']),
                   caplog)
    assert 'ticker_interval' in config
    assert log_has(
        'Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...',
        caplog)

    assert 'position_stacking' in config
    assert log_has('Parameter --enable-position-stacking detected ...', caplog)

    assert 'use_max_market_positions' in config
    assert log_has('Parameter --disable-max-market-positions detected ...',
                   caplog)
    assert log_has('max_open_trades set to unlimited ...', caplog)

    assert 'timerange' in config
    assert log_has(
        'Parameter --timerange detected: {} ...'.format(config['timerange']),
        caplog)

    assert 'export' in config
    assert log_has(
        'Parameter --export detected: {} ...'.format(config['export']), caplog)
    assert 'exportfilename' in config
    assert log_has(
        'Storing backtest results to {} ...'.format(config['exportfilename']),
        caplog)

    assert 'fee' in config
    assert log_has(
        'Parameter --fee detected, setting fee to: {} ...'.format(
            config['fee']), caplog)
Exemple #8
0
def test_backtest_start_multi_strat(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)
    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)
    patched_configuration_load_config_file(mocker, default_conf)

    args = [
        'backtesting',
        '--config',
        'config.json',
        '--datadir',
        str(testdatadir),
        '--strategy-path',
        str(Path(__file__).parents[2] / 'freqtrade/templates'),
        '--ticker-interval',
        '1m',
        '--timerange',
        '1510694220-1510700340',
        '--enable-position-stacking',
        '--disable-max-market-positions',
        '--strategy-list',
        'DefaultStrategy',
        'SampleStrategy',
    ]
    args = get_args(args)
    start_backtesting(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 ...',
        '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 SampleStrategy',
    ]

    for line in exists:
        assert log_has(line, caplog)
Exemple #9
0
def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir):

    default_conf['ask_strategy'].update({
        "use_sell_signal": True,
        "sell_profit_only": False,
        "sell_profit_offset": 0.0,
        "ignore_roi_if_buy_signal": False,
    })
    patch_exchange(mocker)
    backtestmock = MagicMock(
        return_value={
            'results': pd.DataFrame(columns=BT_DATA_COLUMNS),
            'config': default_conf,
            'locks': [],
            'final_balance': 1000,
        })
    mocker.patch('freqtrade.plugins.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_comparison=strat_summary,
        generate_daily_stats=MagicMock(),
    )
    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} ...',
        'Loading data from 2017-11-14 20:57:00 '
        'up to 2017-11-14 22:58:00 (0 days)..',
        'Backtesting with data from 2017-11-14 21:17:00 '
        'up to 2017-11-14 22:58: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 #10
0
def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog,
                                           testdatadir, capsys):
    default_conf['ask_strategy'].update({
        "use_sell_signal": True,
        "sell_profit_only": False,
        "sell_profit_offset": 0.0,
        "ignore_roi_if_buy_signal": False,
    })
    patch_exchange(mocker)
    result1 = pd.DataFrame({
        'pair': ['XRP/BTC', 'LTC/BTC'],
        'profit_ratio': [0.0, 0.0],
        'profit_abs': [0.0, 0.0],
        'open_date':
        pd.to_datetime([
            '2018-01-29 18:40:00',
            '2018-01-30 03:30:00',
        ],
                       utc=True),
        'close_date':
        pd.to_datetime([
            '2018-01-29 20:45:00',
            '2018-01-30 05:35:00',
        ],
                       utc=True),
        'trade_duration': [235, 40],
        'is_open': [False, False],
        'stake_amount': [0.01, 0.01],
        'open_rate': [0.104445, 0.10302485],
        'close_rate': [0.104969, 0.103541],
        'sell_reason': [SellType.ROI, SellType.ROI]
    })
    result2 = pd.DataFrame({
        'pair': ['XRP/BTC', 'LTC/BTC', 'ETH/BTC'],
        'profit_ratio': [0.03, 0.01, 0.1],
        'profit_abs': [0.01, 0.02, 0.2],
        'open_date':
        pd.to_datetime([
            '2018-01-29 18:40:00', '2018-01-30 03:30:00', '2018-01-30 05:30:00'
        ],
                       utc=True),
        'close_date':
        pd.to_datetime([
            '2018-01-29 20:45:00', '2018-01-30 05:35:00', '2018-01-30 08:30:00'
        ],
                       utc=True),
        'trade_duration': [47, 40, 20],
        'is_open': [False, False, False],
        'stake_amount': [0.01, 0.01, 0.01],
        '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]
    })
    backtestmock = MagicMock(side_effect=[{
        'results': result1,
        'config': default_conf,
        'locks': [],
        'final_balance': 1000,
    }, {
        'results': result2,
        'config': default_conf,
        'locks': [],
        'final_balance': 1000,
    }])
    mocker.patch('freqtrade.plugins.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} ...',
        'Loading data from 2017-11-14 20:57:00 '
        'up to 2017-11-14 22:58:00 (0 days)..',
        'Backtesting with data from 2017-11-14 21:17:00 '
        'up to 2017-11-14 22:58: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_update_with_bittrex(limit_buy_order, limit_sell_order, fee, caplog):
    """
    On this test we will buy and sell a crypto currency.

    Buy
    - Buy: 90.99181073 Crypto at 0.00001099 BTC
        (90.99181073*0.00001099 = 0.0009999 BTC)
    - Buying fee: 0.25%
    - Total cost of buy trade: 0.001002500 BTC
        ((90.99181073*0.00001099) + ((90.99181073*0.00001099)*0.0025))

    Sell
    - Sell: 90.99181073 Crypto at 0.00001173 BTC
        (90.99181073*0.00001173 = 0,00106733394 BTC)
    - Selling fee: 0.25%
    - Total cost of sell trade: 0.001064666 BTC
        ((90.99181073*0.00001173) - ((90.99181073*0.00001173)*0.0025))

    Profit/Loss: +0.000062166 BTC
        (Sell:0.001064666 - Buy:0.001002500)
    Profit/Loss percentage: 0.0620
        ((0.001064666/0.001002500)-1 = 6.20%)

    :param limit_buy_order:
    :param limit_sell_order:
    :return:
    """

    trade = Trade(
        id=2,
        pair='ETH/BTC',
        stake_amount=0.001,
        open_rate=0.01,
        amount=5,
        fee_open=fee.return_value,
        fee_close=fee.return_value,
        exchange='bittrex',
    )
    assert trade.open_order_id is None
    assert trade.close_profit is None
    assert trade.close_date is None

    trade.open_order_id = 'something'
    trade.update(limit_buy_order)
    assert trade.open_order_id is None
    assert trade.open_rate == 0.00001099
    assert trade.close_profit is None
    assert trade.close_date is None
    assert log_has("LIMIT_BUY has been fulfilled for Trade(id=2, "
                   "pair=ETH/BTC, amount=90.99181073, open_rate=0.00001099, open_since=closed).",
                   caplog)

    caplog.clear()
    trade.open_order_id = 'something'
    trade.update(limit_sell_order)
    assert trade.open_order_id is None
    assert trade.close_rate == 0.00001173
    assert trade.close_profit == 0.06201058
    assert trade.close_date is not None
    assert log_has("LIMIT_SELL has been fulfilled for Trade(id=2, "
                   "pair=ETH/BTC, amount=90.99181073, open_rate=0.00001099, open_since=closed).",
                   caplog)
Exemple #12
0
def test_hyperopt_list(mocker, capsys, caplog, saved_hyperopt_results, tmpdir):
    csv_file = Path(tmpdir) / "test.csv"
    mocker.patch(
        'freqtrade.optimize.hyperopt_tools.HyperoptTools._test_hyperopt_results_exist',
        return_value=True)

    def fake_iterator(*args, **kwargs):
        yield from [saved_hyperopt_results]

    mocker.patch(
        'freqtrade.optimize.hyperopt_tools.HyperoptTools._read_results',
        side_effect=fake_iterator)

    args = [
        "hyperopt-list",
        "--no-details",
        "--no-color",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [
        " 1/12", " 2/12", " 3/12", " 4/12", " 5/12", " 6/12", " 7/12", " 8/12",
        " 9/12", " 10/12", " 11/12", " 12/12"
    ])
    args = [
        "hyperopt-list",
        "--best",
        "--no-details",
        "--no-color",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [" 1/12", " 5/12", " 10/12"])
    assert all(x not in captured.out for x in [
        " 2/12", " 3/12", " 4/12", " 6/12", " 7/12", " 8/12", " 9/12",
        " 11/12", " 12/12"
    ])
    args = [
        "hyperopt-list",
        "--profitable",
        "--no-details",
        "--no-color",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [" 2/12", " 10/12"])
    assert all(x not in captured.out for x in [
        " 1/12", " 3/12", " 4/12", " 5/12", " 6/12", " 7/12", " 8/12", " 9/12",
        " 11/12", " 12/12"
    ])
    args = [
        "hyperopt-list",
        "--profitable",
        "--no-color",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [
        " 2/12", " 10/12", "Best result:", "Buy hyperspace params",
        "Sell hyperspace params", "ROI table", "Stoploss"
    ])
    assert all(x not in captured.out for x in [
        " 1/12", " 3/12", " 4/12", " 5/12", " 6/12", " 7/12", " 8/12", " 9/12",
        " 11/12", " 12/12"
    ])
    args = [
        "hyperopt-list",
        "--no-details",
        "--no-color",
        "--min-trades",
        "20",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out
               for x in [" 3/12", " 6/12", " 7/12", " 9/12", " 11/12"])
    assert all(
        x not in captured.out for x in
        [" 1/12", " 2/12", " 4/12", " 5/12", " 8/12", " 10/12", " 12/12"])
    args = [
        "hyperopt-list",
        "--profitable",
        "--no-details",
        "--no-color",
        "--max-trades",
        "20",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [" 2/12", " 10/12"])
    assert all(x not in captured.out for x in [
        " 1/12", " 3/12", " 4/12", " 5/12", " 6/12", " 7/12", " 8/12", " 9/12",
        " 11/12", " 12/12"
    ])
    args = [
        "hyperopt-list",
        "--profitable",
        "--no-details",
        "--no-color",
        "--min-avg-profit",
        "0.11",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [" 2/12"])
    assert all(x not in captured.out for x in [
        " 1/12", " 3/12", " 4/12", " 5/12", " 6/12", " 7/12", " 8/12", " 9/12",
        " 10/12", " 11/12", " 12/12"
    ])
    args = [
        "hyperopt-list",
        "--no-details",
        "--no-color",
        "--max-avg-profit",
        "0.10",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [
        " 1/12", " 3/12", " 5/12", " 6/12", " 7/12", " 8/12", " 9/12", " 11/12"
    ])
    assert all(x not in captured.out
               for x in [" 2/12", " 4/12", " 10/12", " 12/12"])
    args = [
        "hyperopt-list",
        "--no-details",
        "--no-color",
        "--min-total-profit",
        "0.4",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [" 10/12"])
    assert all(x not in captured.out for x in [
        " 1/12", " 2/12", " 3/12", " 4/12", " 5/12", " 6/12", " 7/12", " 8/12",
        " 9/12", " 11/12", " 12/12"
    ])
    args = [
        "hyperopt-list",
        "--no-details",
        "--no-color",
        "--max-total-profit",
        "0.4",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [
        " 1/12", " 2/12", " 3/12", " 5/12", " 6/12", " 7/12", " 8/12", " 9/12",
        " 11/12"
    ])
    assert all(x not in captured.out for x in [" 4/12", " 10/12", " 12/12"])
    args = [
        "hyperopt-list",
        "--no-details",
        "--no-color",
        "--min-objective",
        "0.1",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [" 10/12"])
    assert all(x not in captured.out for x in [
        " 1/12", " 2/12", " 3/12", " 4/12", " 5/12", " 6/12", " 7/12", " 8/12",
        " 9/12", " 11/12", " 12/12"
    ])
    args = [
        "hyperopt-list",
        "--no-details",
        "--max-objective",
        "0.1",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [
        " 1/12", " 2/12", " 3/12", " 5/12", " 6/12", " 7/12", " 8/12", " 9/12",
        " 11/12"
    ])
    assert all(x not in captured.out for x in [" 4/12", " 10/12", " 12/12"])
    args = [
        "hyperopt-list",
        "--profitable",
        "--no-details",
        "--no-color",
        "--min-avg-time",
        "2000",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [" 10/12"])
    assert all(x not in captured.out for x in [
        " 1/12", " 2/12", " 3/12", " 4/12", " 5/12", " 6/12", " 7/12", " 8/12",
        " 9/12", " 11/12", " 12/12"
    ])
    args = [
        "hyperopt-list",
        "--no-details",
        "--no-color",
        "--max-avg-time",
        "1500",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [" 2/12", " 6/12"])
    assert all(x not in captured.out for x in [
        " 1/12", " 3/12", " 4/12", " 5/12", " 7/12", " 8/12"
        " 9/12", " 10/12", " 11/12", " 12/12"
    ])
    args = [
        "hyperopt-list",
        "--no-details",
        "--no-color",
        "--export-csv",
        str(csv_file),
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    log_has("CSV file created: test_file.csv", caplog)
    assert csv_file.is_file()
    line = csv_file.read_text()
    assert (
        'Best,1,2,-1.25%,-1.2222,-0.00125625,,-2.51,"3,930.0 m",0.43662'
        in line
        or "Best,1,2,-1.25%,-1.2222,-0.00125625,,-2.51,2 days 17:30:00,0.43662"
        in line)
    csv_file.unlink()
Exemple #13
0
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,
        generate_daily_stats=MagicMock(),
    )
    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-14 20:57:00 '
        'up to 2017-11-14 22:58:00 (0 days)..',
        'Backtesting with data from 2017-11-14 21:17:00 '
        'up to 2017-11-14 22:58: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 #14
0
def test_hyperopt_list(mocker, capsys, caplog, hyperopt_results):
    mocker.patch('freqtrade.optimize.hyperopt.Hyperopt.load_previous_results',
                 MagicMock(return_value=hyperopt_results))

    args = [
        "hyperopt-list",
        "--no-details",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [
        " 1/12", " 2/12", " 3/12", " 4/12", " 5/12", " 6/12", " 7/12", " 8/12",
        " 9/12", " 10/12", " 11/12", " 12/12"
    ])
    args = [
        "hyperopt-list",
        "--best",
        "--no-details",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [" 1/12", " 5/12", " 10/12"])
    assert all(x not in captured.out for x in [
        " 2/12", " 3/12", " 4/12", " 6/12", " 7/12", " 8/12", " 9/12",
        " 11/12", " 12/12"
    ])
    args = [
        "hyperopt-list",
        "--profitable",
        "--no-details",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [" 2/12", " 10/12"])
    assert all(x not in captured.out for x in [
        " 1/12", " 3/12", " 4/12", " 5/12", " 6/12", " 7/12", " 8/12", " 9/12",
        " 11/12", " 12/12"
    ])
    args = [
        "hyperopt-list",
        "--profitable",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [
        " 2/12", " 10/12", "Best result:", "Buy hyperspace params",
        "Sell hyperspace params", "ROI table", "Stoploss"
    ])
    assert all(x not in captured.out for x in [
        " 1/12", " 3/12", " 4/12", " 5/12", " 6/12", " 7/12", " 8/12", " 9/12",
        " 11/12", " 12/12"
    ])
    args = [
        "hyperopt-list",
        "--no-details",
        "--no-color",
        "--min-trades",
        "20",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out
               for x in [" 3/12", " 6/12", " 7/12", " 9/12", " 11/12"])
    assert all(
        x not in captured.out for x in
        [" 1/12", " 2/12", " 4/12", " 5/12", " 8/12", " 10/12", " 12/12"])
    args = [
        "hyperopt-list",
        "--profitable",
        "--no-details",
        "--max-trades",
        "20",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [" 2/12", " 10/12"])
    assert all(x not in captured.out for x in [
        " 1/12", " 3/12", " 4/12", " 5/12", " 6/12", " 7/12", " 8/12", " 9/12",
        " 11/12", " 12/12"
    ])
    args = [
        "hyperopt-list",
        "--profitable",
        "--no-details",
        "--min-avg-profit",
        "0.11",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [" 2/12"])
    assert all(x not in captured.out for x in [
        " 1/12", " 3/12", " 4/12", " 5/12", " 6/12", " 7/12", " 8/12", " 9/12",
        " 10/12", " 11/12", " 12/12"
    ])
    args = [
        "hyperopt-list",
        "--no-details",
        "--max-avg-profit",
        "0.10",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [
        " 1/12", " 3/12", " 5/12", " 6/12", " 7/12", " 8/12", " 9/12", " 11/12"
    ])
    assert all(x not in captured.out
               for x in [" 2/12", " 4/12", " 10/12", " 12/12"])
    args = [
        "hyperopt-list",
        "--no-details",
        "--min-total-profit",
        "0.4",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [" 10/12"])
    assert all(x not in captured.out for x in [
        " 1/12", " 2/12", " 3/12", " 4/12", " 5/12", " 6/12", " 7/12", " 8/12",
        " 9/12", " 11/12", " 12/12"
    ])
    args = [
        "hyperopt-list",
        "--no-details",
        "--max-total-profit",
        "0.4",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [
        " 1/12", " 2/12", " 3/12", " 5/12", " 6/12", " 7/12", " 8/12", " 9/12",
        " 11/12"
    ])
    assert all(x not in captured.out for x in [" 4/12", " 10/12", " 12/12"])
    args = [
        "hyperopt-list",
        "--no-details",
        "--min-objective",
        "0.1",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [" 10/12"])
    assert all(x not in captured.out for x in [
        " 1/12", " 2/12", " 3/12", " 4/12", " 5/12", " 6/12", " 7/12", " 8/12",
        " 9/12", " 11/12", " 12/12"
    ])
    args = [
        "hyperopt-list",
        "--no-details",
        "--max-objective",
        "0.1",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [
        " 1/12", " 2/12", " 3/12", " 5/12", " 6/12", " 7/12", " 8/12", " 9/12",
        " 11/12"
    ])
    assert all(x not in captured.out for x in [" 4/12", " 10/12", " 12/12"])
    args = [
        "hyperopt-list",
        "--profitable",
        "--no-details",
        "--min-avg-time",
        "2000",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [" 10/12"])
    assert all(x not in captured.out for x in [
        " 1/12", " 2/12", " 3/12", " 4/12", " 5/12", " 6/12", " 7/12", " 8/12",
        " 9/12", " 11/12", " 12/12"
    ])
    args = [
        "hyperopt-list",
        "--no-details",
        "--max-avg-time",
        "1500",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    assert all(x in captured.out for x in [" 2/12", " 6/12"])
    assert all(x not in captured.out for x in [
        " 1/12", " 3/12", " 4/12", " 5/12", " 7/12", " 8/12"
        " 9/12", " 10/12", " 11/12", " 12/12"
    ])
    args = [
        "hyperopt-list",
        "--no-details",
        "--export-csv",
        "test_file.csv",
    ]
    pargs = get_args(args)
    pargs['config'] = None
    start_hyperopt_list(pargs)
    captured = capsys.readouterr()
    log_has("CSV file created: test_file.csv", caplog)
    f = Path("test_file.csv")
    assert 'Best,1,2,-1.25%,-0.00125625,,-2.51,"3,930.0 m",0.43662' in f.read_text(
    )
    assert f.is_file()
    f.unlink()
Exemple #15
0
def test_migrate_new(mocker, default_conf, fee, caplog):
    """
    Test Database migration (starting with new pairformat)
    """
    caplog.set_level(logging.DEBUG)
    amount = 103.223
    # Always create all columns apart from the last!
    create_table_old = """CREATE TABLE IF NOT EXISTS "trades" (
                                id INTEGER NOT NULL,
                                exchange VARCHAR NOT NULL,
                                pair VARCHAR NOT NULL,
                                is_open BOOLEAN NOT NULL,
                                fee FLOAT NOT NULL,
                                open_rate FLOAT,
                                close_rate FLOAT,
                                close_profit FLOAT,
                                stake_amount FLOAT NOT NULL,
                                amount FLOAT,
                                open_date DATETIME NOT NULL,
                                close_date DATETIME,
                                open_order_id VARCHAR,
                                stop_loss FLOAT,
                                initial_stop_loss FLOAT,
                                max_rate FLOAT,
                                sell_reason VARCHAR,
                                strategy VARCHAR,
                                ticker_interval INTEGER,
                                stoploss_order_id VARCHAR,
                                PRIMARY KEY (id),
                                CHECK (is_open IN (0, 1))
                                );"""
    insert_table_old = """INSERT INTO trades (exchange, pair, is_open, fee,
                          open_rate, stake_amount, amount, open_date,
                          stop_loss, initial_stop_loss, max_rate, ticker_interval,
                          open_order_id, stoploss_order_id)
                          VALUES ('binance', 'ETC/BTC', 1, {fee},
                          0.00258580, {stake}, {amount},
                          '2019-11-28 12:44:24.000000',
                          0.0, 0.0, 0.0, '5m',
                          'buy_order', 'stop_order_id222')
                          """.format(fee=fee.return_value,
                                     stake=default_conf.get("stake_amount"),
                                     amount=amount)
    engine = create_engine('sqlite://')
    mocker.patch('freqtrade.persistence.models.create_engine',
                 lambda *args, **kwargs: engine)

    # Create table using the old format
    with engine.begin() as connection:
        connection.execute(text(create_table_old))
        connection.execute(
            text("create index ix_trades_is_open on trades(is_open)"))
        connection.execute(text("create index ix_trades_pair on trades(pair)"))
        connection.execute(text(insert_table_old))

        # fake previous backup
        connection.execute(
            text("create table trades_bak as select * from trades"))

        connection.execute(
            text("create table trades_bak1 as select * from trades"))
    # Run init to test migration
    init_db(default_conf['db_url'], default_conf['dry_run'])

    assert len(Trade.query.filter(Trade.id == 1).all()) == 1
    trade = Trade.query.filter(Trade.id == 1).first()
    assert trade.fee_open == fee.return_value
    assert trade.fee_close == fee.return_value
    assert trade.open_rate_requested is None
    assert trade.close_rate_requested is None
    assert trade.is_open == 1
    assert trade.amount == amount
    assert trade.amount_requested == amount
    assert trade.stake_amount == default_conf.get("stake_amount")
    assert trade.pair == "ETC/BTC"
    assert trade.exchange == "binance"
    assert trade.max_rate == 0.0
    assert trade.min_rate is None
    assert trade.stop_loss == 0.0
    assert trade.initial_stop_loss == 0.0
    assert trade.sell_reason is None
    assert trade.strategy is None
    assert trade.timeframe == '5m'
    assert trade.stoploss_order_id == 'stop_order_id222'
    assert trade.stoploss_last_update is None
    assert log_has("trying trades_bak1", caplog)
    assert log_has("trying trades_bak2", caplog)
    assert log_has(
        "Running database migration for trades - backup: trades_bak2", caplog)
    assert trade.open_trade_value == trade._calc_open_trade_value()
    assert trade.close_profit_abs is None

    assert log_has("Moving open orders to Orders table.", caplog)
    orders = Order.query.all()
    assert len(orders) == 2
    assert orders[0].order_id == 'buy_order'
    assert orders[0].ft_order_side == 'buy'

    assert orders[1].order_id == 'stop_order_id222'
    assert orders[1].ft_order_side == 'stoploss'

    caplog.clear()
    # Drop latest column
    with engine.begin() as connection:
        connection.execute(text("alter table orders rename to orders_bak"))
    inspector = inspect(engine)

    with engine.begin() as connection:
        for index in inspector.get_indexes('orders_bak'):
            connection.execute(text(f"drop index {index['name']}"))
        # Recreate table
        connection.execute(
            text("""
            CREATE TABLE orders (
                id INTEGER NOT NULL,
                ft_trade_id INTEGER,
                ft_order_side VARCHAR NOT NULL,
                ft_pair VARCHAR NOT NULL,
                ft_is_open BOOLEAN NOT NULL,
                order_id VARCHAR NOT NULL,
                status VARCHAR,
                symbol VARCHAR,
                order_type VARCHAR,
                side VARCHAR,
                price FLOAT,
                amount FLOAT,
                filled FLOAT,
                remaining FLOAT,
                cost FLOAT,
                order_date DATETIME,
                order_filled_date DATETIME,
                order_update_date DATETIME,
                PRIMARY KEY (id),
                CONSTRAINT _order_pair_order_id UNIQUE (ft_pair, order_id),
                FOREIGN KEY(ft_trade_id) REFERENCES trades (id)
            )
            """))

        connection.execute(
            text("""
        insert into orders ( id, ft_trade_id, ft_order_side, ft_pair, ft_is_open, order_id, status,
            symbol, order_type, side, price, amount, filled, remaining, cost, order_date,
            order_filled_date, order_update_date)
            select id, ft_trade_id, ft_order_side, ft_pair, ft_is_open, order_id, status,
            symbol, order_type, side, price, amount, filled, remaining, cost, order_date,
            order_filled_date, order_update_date
            from orders_bak
        """))

    # Run init to test migration
    init_db(default_conf['db_url'], default_conf['dry_run'])

    assert log_has("trying orders_bak1", caplog)

    orders = Order.query.all()
    assert len(orders) == 2
    assert orders[0].order_id == 'buy_order'
    assert orders[0].ft_order_side == 'buy'

    assert orders[1].order_id == 'stop_order_id222'
    assert orders[1].ft_order_side == 'stoploss'