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'
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)
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)
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'
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)
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)
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)
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)
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()
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)
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()
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'