Merge branch 'develop' into fix/3579
This commit is contained in:
@@ -8,7 +8,7 @@ import pytest
|
||||
from numpy import isnan
|
||||
|
||||
from freqtrade.edge import PairInfo
|
||||
from freqtrade.exceptions import ExchangeError, TemporaryError
|
||||
from freqtrade.exceptions import ExchangeError, InvalidOrderException, TemporaryError
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.rpc import RPC, RPCException
|
||||
from freqtrade.rpc.fiat_convert import CryptoToFiatConverter
|
||||
@@ -286,12 +286,66 @@ def test_rpc_trade_history(mocker, default_conf, markets, fee):
|
||||
assert isinstance(trades['trades'][1], dict)
|
||||
|
||||
trades = rpc._rpc_trade_history(0)
|
||||
assert len(trades['trades']) == 3
|
||||
assert trades['trades_count'] == 3
|
||||
# The first trade is for ETH ... sorting is descending
|
||||
assert trades['trades'][-1]['pair'] == 'ETH/BTC'
|
||||
assert trades['trades'][0]['pair'] == 'ETC/BTC'
|
||||
assert trades['trades'][1]['pair'] == 'ETC/BTC'
|
||||
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_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_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
|
||||
|
@@ -50,6 +50,12 @@ def client_get(client, url):
|
||||
'Origin': 'http://example.com'})
|
||||
|
||||
|
||||
def client_delete(client, url):
|
||||
# Add fake Origin to ensure CORS kicks in
|
||||
return client.delete(url, headers={'Authorization': _basic_auth_str(_TEST_USER, _TEST_PASS),
|
||||
'Origin': 'http://example.com'})
|
||||
|
||||
|
||||
def assert_response(response, expected_code=200, needs_cors=True):
|
||||
assert response.status_code == expected_code
|
||||
assert response.content_type == "application/json"
|
||||
@@ -352,7 +358,7 @@ def test_api_daily(botclient, mocker, ticker, fee, markets):
|
||||
assert rc.json['data'][0]['date'] == str(datetime.utcnow().date())
|
||||
|
||||
|
||||
def test_api_trades(botclient, mocker, ticker, fee, markets):
|
||||
def test_api_trades(botclient, mocker, fee, markets):
|
||||
ftbot, client = botclient
|
||||
patch_get_signal(ftbot, (True, False))
|
||||
mocker.patch.multiple(
|
||||
@@ -368,12 +374,53 @@ def test_api_trades(botclient, mocker, ticker, fee, markets):
|
||||
|
||||
rc = client_get(client, f"{BASE_URI}/trades")
|
||||
assert_response(rc)
|
||||
assert len(rc.json['trades']) == 3
|
||||
assert rc.json['trades_count'] == 3
|
||||
rc = client_get(client, f"{BASE_URI}/trades?limit=2")
|
||||
assert_response(rc)
|
||||
assert len(rc.json['trades']) == 2
|
||||
assert rc.json['trades_count'] == 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
|
||||
|
||||
|
||||
def test_api_delete_trade(botclient, mocker, fee, markets):
|
||||
ftbot, client = botclient
|
||||
patch_get_signal(ftbot, (True, False))
|
||||
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'
|
||||
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_api_edge_disabled(botclient, mocker, ticker, fee, markets):
|
||||
|
@@ -21,8 +21,9 @@ from freqtrade.rpc import RPCMessageType
|
||||
from freqtrade.rpc.telegram import Telegram, authorized_only
|
||||
from freqtrade.state import State
|
||||
from freqtrade.strategy.interface import SellType
|
||||
from tests.conftest import (get_patched_freqtradebot, log_has, patch_exchange,
|
||||
patch_get_signal, patch_whitelist)
|
||||
from tests.conftest import (create_mock_trades, get_patched_freqtradebot,
|
||||
log_has, patch_exchange, patch_get_signal,
|
||||
patch_whitelist)
|
||||
|
||||
|
||||
class DummyCls(Telegram):
|
||||
@@ -60,7 +61,7 @@ def test__init__(default_conf, mocker) -> None:
|
||||
assert telegram._config == default_conf
|
||||
|
||||
|
||||
def test_init(default_conf, mocker, caplog) -> None:
|
||||
def test_telegram_init(default_conf, mocker, caplog) -> None:
|
||||
start_polling = MagicMock()
|
||||
mocker.patch('freqtrade.rpc.telegram.Updater', MagicMock(return_value=start_polling))
|
||||
|
||||
@@ -72,10 +73,10 @@ def test_init(default_conf, mocker, caplog) -> None:
|
||||
assert start_polling.start_polling.call_count == 1
|
||||
|
||||
message_str = ("rpc.telegram is listening for following commands: [['status'], ['profit'], "
|
||||
"['balance'], ['start'], ['stop'], ['forcesell'], ['forcebuy'], "
|
||||
"['performance'], ['daily'], ['count'], ['reload_config', 'reload_conf'], "
|
||||
"['show_config', 'show_conf'], ['stopbuy'], ['whitelist'], ['blacklist'], "
|
||||
"['edge'], ['help'], ['version']]")
|
||||
"['balance'], ['start'], ['stop'], ['forcesell'], ['forcebuy'], ['trades'], "
|
||||
"['delete'], ['performance'], ['daily'], ['count'], ['reload_config', "
|
||||
"'reload_conf'], ['show_config', 'show_conf'], ['stopbuy'], "
|
||||
"['whitelist'], ['blacklist'], ['edge'], ['help'], ['version']]")
|
||||
|
||||
assert log_has(message_str, caplog)
|
||||
|
||||
@@ -725,6 +726,7 @@ def test_telegram_forcesell_handle(default_conf, update, ticker, fee,
|
||||
last_msg = rpc_mock.call_args_list[-1][0][0]
|
||||
assert {
|
||||
'type': RPCMessageType.SELL_NOTIFICATION,
|
||||
'trade_id': 1,
|
||||
'exchange': 'Bittrex',
|
||||
'pair': 'ETH/BTC',
|
||||
'gain': 'profit',
|
||||
@@ -784,6 +786,7 @@ def test_telegram_forcesell_down_handle(default_conf, update, ticker, fee,
|
||||
last_msg = rpc_mock.call_args_list[-1][0][0]
|
||||
assert {
|
||||
'type': RPCMessageType.SELL_NOTIFICATION,
|
||||
'trade_id': 1,
|
||||
'exchange': 'Bittrex',
|
||||
'pair': 'ETH/BTC',
|
||||
'gain': 'loss',
|
||||
@@ -832,6 +835,7 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None
|
||||
msg = rpc_mock.call_args_list[0][0][0]
|
||||
assert {
|
||||
'type': RPCMessageType.SELL_NOTIFICATION,
|
||||
'trade_id': 1,
|
||||
'exchange': 'Bittrex',
|
||||
'pair': 'ETH/BTC',
|
||||
'gain': 'loss',
|
||||
@@ -1143,6 +1147,63 @@ def test_edge_enabled(edge_conf, update, mocker) -> None:
|
||||
assert 'Pair Winrate Expectancy Stoploss' in msg_mock.call_args_list[0][0][0]
|
||||
|
||||
|
||||
def test_telegram_trades(mocker, update, default_conf, fee):
|
||||
msg_mock = MagicMock()
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.rpc.telegram.Telegram',
|
||||
_init=MagicMock(),
|
||||
_send_msg=msg_mock
|
||||
)
|
||||
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
telegram = Telegram(freqtradebot)
|
||||
context = MagicMock()
|
||||
context.args = []
|
||||
|
||||
telegram._trades(update=update, context=context)
|
||||
assert "<b>0 recent trades</b>:" in msg_mock.call_args_list[0][0][0]
|
||||
assert "<pre>" not in msg_mock.call_args_list[0][0][0]
|
||||
|
||||
msg_mock.reset_mock()
|
||||
create_mock_trades(fee)
|
||||
|
||||
context = MagicMock()
|
||||
context.args = [5]
|
||||
telegram._trades(update=update, context=context)
|
||||
msg_mock.call_count == 1
|
||||
assert "2 recent trades</b>:" in msg_mock.call_args_list[0][0][0]
|
||||
assert "Profit (" in msg_mock.call_args_list[0][0][0]
|
||||
assert "Open Date" in msg_mock.call_args_list[0][0][0]
|
||||
assert "<pre>" in msg_mock.call_args_list[0][0][0]
|
||||
|
||||
|
||||
def test_telegram_delete_trade(mocker, update, default_conf, fee):
|
||||
msg_mock = MagicMock()
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.rpc.telegram.Telegram',
|
||||
_init=MagicMock(),
|
||||
_send_msg=msg_mock
|
||||
)
|
||||
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
telegram = Telegram(freqtradebot)
|
||||
context = MagicMock()
|
||||
context.args = []
|
||||
|
||||
telegram._delete_trade(update=update, context=context)
|
||||
assert "invalid argument" in msg_mock.call_args_list[0][0][0]
|
||||
|
||||
msg_mock.reset_mock()
|
||||
create_mock_trades(fee)
|
||||
|
||||
context = MagicMock()
|
||||
context.args = [1]
|
||||
telegram._delete_trade(update=update, context=context)
|
||||
msg_mock.call_count == 1
|
||||
assert "Deleted trade 1." in msg_mock.call_args_list[0][0][0]
|
||||
assert "Please make sure to take care of this asset" in msg_mock.call_args_list[0][0][0]
|
||||
|
||||
|
||||
def test_help_handle(default_conf, update, mocker) -> None:
|
||||
msg_mock = MagicMock()
|
||||
mocker.patch.multiple(
|
||||
|
Reference in New Issue
Block a user