def test_api_count(botclient, mocker, ticker, fee, markets): ftbot, client = botclient patch_get_signal(ftbot, (True, False)) mocker.patch.multiple( 'freqtrade.exchange.Exchange', get_balances=MagicMock(return_value=ticker), fetch_ticker=ticker, get_fee=fee, markets=PropertyMock(return_value=markets) ) rc = client_get(client, f"{BASE_URI}/count") assert_response(rc) assert rc.json()["current"] == 0 assert rc.json()["max"] == 1 # Create some test data create_mock_trades(fee) rc = client_get(client, f"{BASE_URI}/count") assert_response(rc) assert rc.json()["current"] == 4 assert rc.json()["max"] == 1 ftbot.config['max_open_trades'] = float('inf') rc = client_get(client, f"{BASE_URI}/count") assert rc.json()["max"] == -1
def test_api_stats( botclient, mocker, ticker, fee, markets, ): ftbot, client = botclient patch_get_signal(ftbot, (True, False, None)) mocker.patch.multiple('freqtrade.exchange.Exchange', get_balances=MagicMock(return_value=ticker), fetch_ticker=ticker, get_fee=fee, markets=PropertyMock(return_value=markets)) rc = client_get(client, f"{BASE_URI}/stats") assert_response(rc, 200) assert 'durations' in rc.json() assert 'sell_reasons' in rc.json() create_mock_trades(fee) rc = client_get(client, f"{BASE_URI}/stats") assert_response(rc, 200) assert 'durations' in rc.json() assert 'sell_reasons' in rc.json() assert 'wins' in rc.json()['durations'] assert 'losses' in rc.json()['durations'] assert 'draws' in rc.json()['durations']
def test_total_open_trades_stakes(fee): res = Trade.total_open_trades_stakes() assert res == 0 create_mock_trades(fee) res = Trade.total_open_trades_stakes() assert res == 0.004
def test_sell_reason_performance_handle_2(mocker, default_conf, markets, fee): mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch.multiple( 'freqtrade.exchange.Exchange', markets=PropertyMock(return_value=markets) ) freqtradebot = get_patched_freqtradebot(mocker, default_conf) create_mock_trades(fee) rpc = RPC(freqtradebot) res = rpc._rpc_sell_reason_performance(None) assert len(res) == 2 assert res[0]['sell_reason'] == 'sell_signal' assert res[0]['count'] == 1 assert prec_satoshi(res[0]['profit_pct'], 0.5) assert res[1]['sell_reason'] == 'roi' assert res[1]['count'] == 1 assert prec_satoshi(res[1]['profit_pct'], 1.0) # Test for a specific pair res = rpc._rpc_sell_reason_performance('ETC/BTC') assert len(res) == 1 assert res[0]['count'] == 1 assert res[0]['sell_reason'] == 'sell_signal' assert prec_satoshi(res[0]['profit_pct'], 0.5)
def test_api_trades(botclient, mocker, fee, markets): ftbot, client = botclient patch_get_signal(ftbot) mocker.patch.multiple( 'freqtrade.exchange.Exchange', markets=PropertyMock(return_value=markets) ) rc = client_get(client, f"{BASE_URI}/trades") assert_response(rc) assert len(rc.json()) == 3 assert rc.json()['trades_count'] == 0 assert rc.json()['total_trades'] == 0 create_mock_trades(fee) rc = client_get(client, f"{BASE_URI}/trades") assert_response(rc) assert len(rc.json()['trades']) == 2 assert rc.json()['trades_count'] == 2 assert rc.json()['total_trades'] == 2 rc = client_get(client, f"{BASE_URI}/trades?limit=1") assert_response(rc) assert len(rc.json()['trades']) == 1 assert rc.json()['trades_count'] == 1 assert rc.json()['total_trades'] == 2
def test_show_trades(mocker, fee, capsys, caplog): mocker.patch("freqtrade.persistence.init_db") create_mock_trades(fee, False) args = ["show-trades", "--db-url", "sqlite:///"] pargs = get_args(args) pargs['config'] = None start_show_trades(pargs) assert log_has(f"Printing {MOCK_TRADE_COUNT} Trades: ", caplog) captured = capsys.readouterr() assert "Trade(id=1" in captured.out assert "Trade(id=2" in captured.out assert "Trade(id=3" in captured.out args = [ "show-trades", "--db-url", "sqlite:///", "--print-json", "--trade-ids", "1", "2" ] pargs = get_args(args) pargs['config'] = None start_show_trades(pargs) captured = capsys.readouterr() assert log_has("Printing 2 Trades: ", caplog) assert '"trade_id": 1' in captured.out assert '"trade_id": 2' in captured.out assert '"trade_id": 3' not in captured.out args = [ "show-trades", ] pargs = get_args(args) pargs['config'] = None with pytest.raises(OperationalException, match=r"--db-url is required for this command."): start_show_trades(pargs)
def test_sync_wallet_futures_dry(mocker, default_conf, fee): default_conf['dry_run'] = True default_conf['trading_mode'] = 'futures' default_conf['margin_mode'] = 'isolated' freqtrade = get_patched_freqtradebot(mocker, default_conf) assert len(freqtrade.wallets._wallets) == 1 assert len(freqtrade.wallets._positions) == 0 create_mock_trades(fee, is_short=None) freqtrade.wallets.update() assert len(freqtrade.wallets._wallets) == 1 assert len(freqtrade.wallets._positions) == 4 positions = freqtrade.wallets.get_all_positions() positions['ETH/BTC'].side == 'short' positions['ETC/BTC'].side == 'long' positions['XRP/BTC'].side == 'long' positions['LTC/BTC'].side == 'short' assert freqtrade.wallets.get_starting_balance( ) == default_conf['dry_run_wallet'] total = freqtrade.wallets.get_total('BTC') free = freqtrade.wallets.get_free('BTC') used = freqtrade.wallets.get_used('BTC') assert free + used == total
def test_get_open(fee, use_db): Trade.use_db = use_db Trade.reset_trades() create_mock_trades(fee, use_db) assert len(Trade.get_open_trades()) == 4 Trade.use_db = True
def test_get_overall_performance(fee): create_mock_trades(fee) res = Trade.get_overall_performance() assert len(res) == 1 assert 'pair' in res[0] assert 'profit' in res[0] assert 'count' in res[0]
def test_get_best_pair(fee): res = Trade.get_best_pair() assert res is None create_mock_trades(fee) res = Trade.get_best_pair() assert len(res) == 2 assert res[0] == 'ETC/BTC' assert res[1] == 0.005
def test_total_open_trades_stakes(fee, use_db): Trade.use_db = use_db res = Trade.total_open_trades_stakes() assert res == 0 create_mock_trades(fee, use_db) res = Trade.total_open_trades_stakes() assert res == 0.004 Trade.use_db = True
def test_get_total_closed_profit(fee, use_db): Trade.use_db = use_db Trade.reset_trades() res = Trade.get_total_closed_profit() assert res == 0 create_mock_trades(fee, use_db) res = Trade.get_total_closed_profit() assert res == 0.000739127 Trade.use_db = True
def test_rpc_delete_trade(mocker, default_conf, fee, markets, caplog): mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) stoploss_mock = MagicMock() cancel_mock = MagicMock() mocker.patch.multiple( 'freqtrade.exchange.Exchange', markets=PropertyMock(return_value=markets), cancel_order=cancel_mock, cancel_stoploss_order=stoploss_mock, ) freqtradebot = get_patched_freqtradebot(mocker, default_conf) freqtradebot.strategy.order_types['stoploss_on_exchange'] = True create_mock_trades(fee) rpc = RPC(freqtradebot) with pytest.raises(RPCException, match='invalid argument'): rpc._rpc_delete('200') create_mock_trades(fee) trades = Trade.query.all() trades[1].stoploss_order_id = '1234' trades[2].stoploss_order_id = '1234' assert len(trades) > 2 res = rpc._rpc_delete('1') assert isinstance(res, dict) assert res['result'] == 'success' assert res['trade_id'] == '1' assert res['cancel_order_count'] == 1 assert cancel_mock.call_count == 1 assert stoploss_mock.call_count == 0 cancel_mock.reset_mock() stoploss_mock.reset_mock() res = rpc._rpc_delete('2') assert isinstance(res, dict) assert cancel_mock.call_count == 1 assert stoploss_mock.call_count == 1 assert res['cancel_order_count'] == 2 stoploss_mock = mocker.patch( 'freqtrade.exchange.Exchange.cancel_stoploss_order', side_effect=InvalidOrderException) res = rpc._rpc_delete('3') assert stoploss_mock.call_count == 1 stoploss_mock.reset_mock() cancel_mock = mocker.patch('freqtrade.exchange.Exchange.cancel_order', side_effect=InvalidOrderException) res = rpc._rpc_delete('4') assert cancel_mock.call_count == 1 assert stoploss_mock.call_count == 0
def test_api_profit(botclient, mocker, ticker, fee, markets): ftbot, client = botclient patch_get_signal(ftbot) mocker.patch.multiple( 'freqtrade.exchange.Exchange', get_balances=MagicMock(return_value=ticker), fetch_ticker=ticker, get_fee=fee, markets=PropertyMock(return_value=markets) ) rc = client_get(client, f"{BASE_URI}/profit") assert_response(rc, 200) assert rc.json()['trade_count'] == 0 create_mock_trades(fee) # Simulate fulfilled LIMIT_BUY order for trade rc = client_get(client, f"{BASE_URI}/profit") assert_response(rc) assert rc.json() == {'avg_duration': ANY, 'best_pair': 'XRP/BTC', 'best_rate': 1.0, 'best_pair_profit_ratio': 0.01, 'first_trade_date': ANY, 'first_trade_timestamp': ANY, 'latest_trade_date': '5 minutes ago', 'latest_trade_timestamp': ANY, 'profit_all_coin': -44.0631579, 'profit_all_fiat': -543959.6842755, 'profit_all_percent_mean': -66.41, 'profit_all_ratio_mean': -0.6641100666666667, 'profit_all_percent_sum': -398.47, 'profit_all_ratio_sum': -3.9846604, 'profit_all_percent': -4.41, 'profit_all_ratio': -0.044063014216106644, 'profit_closed_coin': 0.00073913, 'profit_closed_fiat': 9.124559849999999, 'profit_closed_ratio_mean': 0.0075, 'profit_closed_percent_mean': 0.75, 'profit_closed_ratio_sum': 0.015, 'profit_closed_percent_sum': 1.5, 'profit_closed_ratio': 7.391275897987988e-07, 'profit_closed_percent': 0.0, 'trade_count': 6, 'closed_trade_count': 2, 'winning_trades': 2, 'losing_trades': 0, }
def test_get_trades_proxy(fee, use_db): Trade.use_db = use_db Trade.reset_trades() create_mock_trades(fee, use_db) trades = Trade.get_trades_proxy() assert len(trades) == 6 assert isinstance(trades[0], Trade) assert len(Trade.get_trades_proxy(is_open=True)) == 4 assert len(Trade.get_trades_proxy(is_open=False)) == 2 opendate = datetime.now(tz=timezone.utc) - timedelta(minutes=15) assert len(Trade.get_trades_proxy(open_date=opendate)) == 3 Trade.use_db = True
def test_api_trade_single(botclient, mocker, fee, ticker, markets): ftbot, client = botclient patch_get_signal(ftbot) mocker.patch.multiple( 'freqtrade.exchange.Exchange', markets=PropertyMock(return_value=markets), fetch_ticker=ticker, ) rc = client_get(client, f"{BASE_URI}/trade/3") assert_response(rc, 404) assert rc.json()['detail'] == 'Trade not found.' create_mock_trades(fee) rc = client_get(client, f"{BASE_URI}/trade/3") assert_response(rc) assert rc.json()['trade_id'] == 3
def test_load_trades_from_db(default_conf, fee, mocker): create_mock_trades(fee) # remove init so it does not init again init_mock = mocker.patch('freqtrade.persistence.init', MagicMock()) trades = load_trades_from_db(db_url=default_conf['db_url']) assert init_mock.call_count == 1 assert len(trades) == 3 assert isinstance(trades, DataFrame) assert "pair" in trades.columns assert "open_time" in trades.columns assert "profit_percent" in trades.columns for col in BT_DATA_COLUMNS: if col not in ['index', 'open_at_end']: assert col in trades.columns
def test_select_order(fee): create_mock_trades(fee) trades = Trade.get_trades().all() # Open buy order, no sell order order = trades[0].select_order('buy', True) assert order is None order = trades[0].select_order('buy', False) assert order is not None order = trades[0].select_order('sell', None) assert order is None # closed buy order, and open sell order order = trades[1].select_order('buy', True) assert order is None order = trades[1].select_order('buy', False) assert order is not None order = trades[1].select_order('buy', None) assert order is not None order = trades[1].select_order('sell', True) assert order is None order = trades[1].select_order('sell', False) assert order is not None # Has open buy order order = trades[3].select_order('buy', True) assert order is not None order = trades[3].select_order('buy', False) assert order is None # Open sell order order = trades[4].select_order('buy', True) assert order is None order = trades[4].select_order('buy', False) assert order is not None order = trades[4].select_order('sell', True) assert order is not None assert order.ft_order_side == 'stoploss' order = trades[4].select_order('sell', False) assert order is None
def test_api_delete_trade(botclient, mocker, fee, markets): ftbot, client = botclient patch_get_signal(ftbot) stoploss_mock = MagicMock() cancel_mock = MagicMock() mocker.patch.multiple( 'freqtrade.exchange.Exchange', markets=PropertyMock(return_value=markets), cancel_order=cancel_mock, cancel_stoploss_order=stoploss_mock, ) rc = client_delete(client, f"{BASE_URI}/trades/1") # Error - trade won't exist yet. assert_response(rc, 502) create_mock_trades(fee) ftbot.strategy.order_types['stoploss_on_exchange'] = True trades = Trade.query.all() trades[1].stoploss_order_id = '1234' Trade.commit() assert len(trades) > 2 rc = client_delete(client, f"{BASE_URI}/trades/1") assert_response(rc) assert rc.json()['result_msg'] == 'Deleted trade 1. Closed 1 open orders.' assert len(trades) - 1 == len(Trade.query.all()) assert cancel_mock.call_count == 1 cancel_mock.reset_mock() rc = client_delete(client, f"{BASE_URI}/trades/1") # Trade is gone now. assert_response(rc, 502) assert cancel_mock.call_count == 0 assert len(trades) - 1 == len(Trade.query.all()) rc = client_delete(client, f"{BASE_URI}/trades/2") assert_response(rc) assert rc.json()['result_msg'] == 'Deleted trade 2. Closed 2 open orders.' assert len(trades) - 2 == len(Trade.query.all()) assert stoploss_mock.call_count == 1
def test_rpc_trade_history(mocker, default_conf, markets, fee): mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch.multiple('freqtrade.exchange.Exchange', markets=PropertyMock(return_value=markets)) freqtradebot = get_patched_freqtradebot(mocker, default_conf) create_mock_trades(fee) rpc = RPC(freqtradebot) rpc._fiat_converter = CryptoToFiatConverter() trades = rpc._rpc_trade_history(2) assert len(trades['trades']) == 2 assert trades['trades_count'] == 2 assert isinstance(trades['trades'][0], dict) assert isinstance(trades['trades'][1], dict) trades = rpc._rpc_trade_history(0) assert len(trades['trades']) == 2 assert trades['trades_count'] == 2 # The first closed trade is for ETC ... sorting is descending assert trades['trades'][-1]['pair'] == 'ETC/BTC' assert trades['trades'][0]['pair'] == 'XRP/BTC'
def test_load_trades_from_db(default_conf, fee, mocker): create_mock_trades(fee) # remove init so it does not init again init_mock = mocker.patch('freqtrade.data.btanalysis.init_db', MagicMock()) trades = load_trades_from_db(db_url=default_conf['db_url']) assert init_mock.call_count == 1 assert len(trades) == MOCK_TRADE_COUNT assert isinstance(trades, DataFrame) assert "pair" in trades.columns assert "open_date" in trades.columns assert "profit_ratio" in trades.columns for col in BT_DATA_COLUMNS: if col not in ['index', 'open_at_end']: assert col in trades.columns trades = load_trades_from_db(db_url=default_conf['db_url'], strategy='DefaultStrategy') assert len(trades) == 4 trades = load_trades_from_db(db_url=default_conf['db_url'], strategy='NoneStrategy') assert len(trades) == 0
def test_api_status(botclient, mocker, ticker, fee, markets): ftbot, client = botclient patch_get_signal(ftbot, (True, False)) mocker.patch.multiple( 'freqtrade.exchange.Exchange', get_balances=MagicMock(return_value=ticker), fetch_ticker=ticker, get_fee=fee, markets=PropertyMock(return_value=markets), fetch_order=MagicMock(return_value={}), ) rc = client_get(client, f"{BASE_URI}/status") assert_response(rc, 200) assert rc.json() == [] create_mock_trades(fee) rc = client_get(client, f"{BASE_URI}/status") assert_response(rc) assert len(rc.json()) == 4 assert rc.json()[0] == { 'amount': 123.0, 'amount_requested': 123.0, 'close_date': None, 'close_timestamp': None, 'close_profit': None, 'close_profit_pct': None, 'close_profit_abs': None, 'close_rate': None, 'current_profit': ANY, 'current_profit_pct': ANY, 'current_profit_abs': ANY, 'profit_ratio': ANY, 'profit_pct': ANY, 'profit_abs': ANY, 'profit_fiat': ANY, 'current_rate': 1.099e-05, 'open_date': ANY, 'open_timestamp': ANY, 'open_order': None, 'open_rate': 0.123, 'pair': 'ETH/BTC', 'stake_amount': 0.001, 'stop_loss_abs': ANY, 'stop_loss_pct': ANY, 'stop_loss_ratio': ANY, 'stoploss_order_id': None, 'stoploss_last_update': ANY, 'stoploss_last_update_timestamp': ANY, 'initial_stop_loss_abs': 0.0, 'initial_stop_loss_pct': ANY, 'initial_stop_loss_ratio': ANY, 'stoploss_current_dist': ANY, 'stoploss_current_dist_ratio': ANY, 'stoploss_current_dist_pct': ANY, 'stoploss_entry_dist': ANY, 'stoploss_entry_dist_ratio': ANY, 'trade_id': 1, 'close_rate_requested': ANY, 'fee_close': 0.0025, 'fee_close_cost': None, 'fee_close_currency': None, 'fee_open': 0.0025, 'fee_open_cost': None, 'fee_open_currency': None, 'is_open': True, 'max_rate': ANY, 'min_rate': ANY, 'open_order_id': 'dry_run_buy_12345', 'open_rate_requested': ANY, 'open_trade_value': 15.1668225, 'sell_reason': None, 'sell_order_status': None, 'strategy': 'DefaultStrategy', 'timeframe': 5, 'exchange': 'binance', } mocker.patch( 'freqtrade.exchange.Exchange.get_sell_rate', MagicMock(side_effect=ExchangeError("Pair 'ETH/BTC' not available"))) rc = client_get(client, f"{BASE_URI}/status") assert_response(rc) resp_values = rc.json() assert len(resp_values) == 4 assert isnan(resp_values[0]['profit_abs'])
def test_get_open(fee): create_mock_trades(fee) assert len(Trade.get_open_trades()) == 4
def test_get_open(default_conf, fee): create_mock_trades(fee) assert len(Trade.get_open_trades()) == 2