Merge branch 'develop' into pr/thopd88/3611

This commit is contained in:
Matthias
2020-08-04 07:00:54 +02:00
34 changed files with 272 additions and 75 deletions

View File

@@ -1089,7 +1089,7 @@ def test_show_trades(mocker, fee, capsys, caplog):
pargs = get_args(args)
pargs['config'] = None
start_show_trades(pargs)
assert log_has("Printing 3 Trades: ", caplog)
assert log_has("Printing 4 Trades: ", caplog)
captured = capsys.readouterr()
assert "Trade(id=1" in captured.out
assert "Trade(id=2" in captured.out

View File

@@ -199,6 +199,20 @@ def create_mock_trades(fee):
)
Trade.session.add(trade)
trade = Trade(
pair='XRP/BTC',
stake_amount=0.001,
amount=123.0,
fee_open=fee.return_value,
fee_close=fee.return_value,
open_rate=0.05,
close_rate=0.06,
close_profit=0.01,
exchange='bittrex',
is_open=False,
)
Trade.session.add(trade)
# Simulate prod entry
trade = Trade(
pair='ETC/BTC',
@@ -661,7 +675,8 @@ def shitcoinmarkets(markets):
Fixture with shitcoin markets - used to test filters in pairlists
"""
shitmarkets = deepcopy(markets)
shitmarkets.update({'HOT/BTC': {
shitmarkets.update({
'HOT/BTC': {
'id': 'HOTBTC',
'symbol': 'HOT/BTC',
'base': 'HOT',
@@ -766,7 +781,32 @@ def shitcoinmarkets(markets):
"spot": True,
"future": False,
"active": True
},
},
'ADADOUBLE/USDT': {
"percentage": True,
"tierBased": False,
"taker": 0.001,
"maker": 0.001,
"precision": {
"base": 8,
"quote": 8,
"amount": 2,
"price": 4
},
"limits": {
},
"id": "ADADOUBLEUSDT",
"symbol": "ADADOUBLE/USDT",
"base": "ADADOUBLE",
"quote": "USDT",
"baseId": "ADADOUBLE",
"quoteId": "USDT",
"info": {},
"type": "spot",
"spot": True,
"future": False,
"active": True
},
})
return shitmarkets
@@ -1388,6 +1428,28 @@ def tickers():
"quoteVolume": 0.0,
"info": {}
},
"ADADOUBLE/USDT": {
"symbol": "ADADOUBLE/USDT",
"timestamp": 1580469388244,
"datetime": "2020-01-31T11:16:28.244Z",
"high": None,
"low": None,
"bid": 0.7305,
"bidVolume": None,
"ask": 0.7342,
"askVolume": None,
"vwap": None,
"open": None,
"close": None,
"last": 0,
"previousClose": None,
"change": None,
"percentage": 2.628,
"average": None,
"baseVolume": 0.0,
"quoteVolume": 0.0,
"info": {}
},
})

View File

@@ -43,7 +43,7 @@ def test_load_trades_from_db(default_conf, fee, mocker):
trades = load_trades_from_db(db_url=default_conf['db_url'])
assert init_mock.call_count == 1
assert len(trades) == 3
assert len(trades) == 4
assert isinstance(trades, DataFrame)
assert "pair" in trades.columns
assert "open_time" in trades.columns

View File

@@ -714,13 +714,13 @@ def test_validate_order_types(default_conf, mocker):
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes')
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
mocker.patch('freqtrade.exchange.Exchange.name', 'Bittrex')
default_conf['order_types'] = {
'buy': 'limit',
'sell': 'limit',
'stoploss': 'market',
'stoploss_on_exchange': False
}
Exchange(default_conf)
type(api_mock).has = PropertyMock(return_value={'createMarketOrder': False})
@@ -730,9 +730,8 @@ def test_validate_order_types(default_conf, mocker):
'buy': 'limit',
'sell': 'limit',
'stoploss': 'market',
'stoploss_on_exchange': 'false'
'stoploss_on_exchange': False
}
with pytest.raises(OperationalException,
match=r'Exchange .* does not support market orders.'):
Exchange(default_conf)
@@ -743,7 +742,6 @@ def test_validate_order_types(default_conf, mocker):
'stoploss': 'limit',
'stoploss_on_exchange': True
}
with pytest.raises(OperationalException,
match=r'On exchange stoploss is not supported for .*'):
Exchange(default_conf)

View File

@@ -235,7 +235,7 @@ def test_VolumePairList_refresh_empty(mocker, markets_empty, whitelist_conf):
([{"method": "VolumePairList", "number_assets": 5, "sort_key": "bidVolume"}],
"BTC", ['HOT/BTC', 'FUEL/BTC', 'XRP/BTC', 'LTC/BTC', 'TKN/BTC']),
([{"method": "VolumePairList", "number_assets": 5, "sort_key": "quoteVolume"}],
"USDT", ['ETH/USDT', 'NANO/USDT', 'ADAHALF/USDT']),
"USDT", ['ETH/USDT', 'NANO/USDT', 'ADAHALF/USDT', 'ADADOUBLE/USDT']),
# No pair for ETH, VolumePairList
([{"method": "VolumePairList", "number_assets": 5, "sort_key": "quoteVolume"}],
"ETH", []),
@@ -303,11 +303,11 @@ def test_VolumePairList_refresh_empty(mocker, markets_empty, whitelist_conf):
# ShuffleFilter
([{"method": "VolumePairList", "number_assets": 5, "sort_key": "quoteVolume"},
{"method": "ShuffleFilter", "seed": 77}],
"USDT", ['ETH/USDT', 'ADAHALF/USDT', 'NANO/USDT']),
"USDT", ['ADADOUBLE/USDT', 'ETH/USDT', 'NANO/USDT', 'ADAHALF/USDT']),
# ShuffleFilter, other seed
([{"method": "VolumePairList", "number_assets": 5, "sort_key": "quoteVolume"},
{"method": "ShuffleFilter", "seed": 42}],
"USDT", ['NANO/USDT', 'ETH/USDT', 'ADAHALF/USDT']),
"USDT", ['ADAHALF/USDT', 'NANO/USDT', 'ADADOUBLE/USDT', 'ETH/USDT']),
# ShuffleFilter, no seed
([{"method": "VolumePairList", "number_assets": 5, "sort_key": "quoteVolume"},
{"method": "ShuffleFilter"}],
@@ -347,6 +347,9 @@ def test_VolumePairList_refresh_empty(mocker, markets_empty, whitelist_conf):
([{"method": "VolumePairList", "number_assets": 5, "sort_key": "bidVolume"},
{"method": "StaticPairList"}],
"BTC", 'static_in_the_middle'),
([{"method": "VolumePairList", "number_assets": 20, "sort_key": "quoteVolume"},
{"method": "PriceFilter", "low_price_ratio": 0.02}],
"USDT", ['ETH/USDT', 'NANO/USDT']),
])
def test_VolumePairList_whitelist_gen(mocker, whitelist_conf, shitcoinmarkets, tickers,
ohlcv_history_list, pairlists, base_currency,

View File

@@ -284,12 +284,11 @@ 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_trade_statistics(default_conf, ticker, ticker_sell_up, fee,

View File

@@ -368,12 +368,12 @@ 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_edge_disabled(botclient, mocker, ticker, fee, markets):

View File

@@ -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_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_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,36 @@ 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_help_handle(default_conf, update, mocker) -> None:
msg_mock = MagicMock()
mocker.patch.multiple(

View File

@@ -871,6 +871,14 @@ def test_load_config_default_exchange_name(all_conf) -> None:
validate_config_schema(all_conf)
def test_load_config_stoploss_exchange_limit_ratio(all_conf) -> None:
all_conf['order_types']['stoploss_on_exchange_limit_ratio'] = 1.15
with pytest.raises(ValidationError,
match=r"1.15 is greater than the maximum"):
validate_config_schema(all_conf)
@pytest.mark.parametrize("keys", [("exchange", "sandbox", False),
("exchange", "key", ""),
("exchange", "secret", ""),

View File

@@ -1726,6 +1726,7 @@ def test_update_trade_state_withorderdict(default_conf, trades_for_order, limit_
amount=amount,
exchange='binance',
open_rate=0.245441,
open_date=arrow.utcnow().datetime,
fee_open=fee.return_value,
fee_close=fee.return_value,
open_order_id="123456",
@@ -1816,6 +1817,7 @@ def test_update_trade_state_sell(default_conf, trades_for_order, limit_sell_orde
open_rate=0.245441,
fee_open=0.0025,
fee_close=0.0025,
open_date=arrow.utcnow().datetime,
open_order_id="123456",
is_open=True,
)
@@ -2572,6 +2574,7 @@ def test_execute_sell_up(default_conf, ticker, fee, ticker_sell_up, mocker) -> N
assert rpc_mock.call_count == 1
last_msg = rpc_mock.call_args_list[-1][0][0]
assert {
'trade_id': 1,
'type': RPCMessageType.SELL_NOTIFICATION,
'exchange': 'Bittrex',
'pair': 'ETH/BTC',
@@ -2622,6 +2625,7 @@ def test_execute_sell_down(default_conf, ticker, fee, ticker_sell_down, mocker)
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',
@@ -2678,6 +2682,7 @@ def test_execute_sell_down_stoploss_on_exchange_dry_run(default_conf, ticker, fe
assert {
'type': RPCMessageType.SELL_NOTIFICATION,
'trade_id': 1,
'exchange': 'Bittrex',
'pair': 'ETH/BTC',
'gain': 'loss',
@@ -2883,6 +2888,7 @@ def test_execute_sell_market_order(default_conf, 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',
@@ -4090,7 +4096,7 @@ def test_cancel_all_open_orders(mocker, default_conf, fee, limit_buy_order, limi
freqtrade = get_patched_freqtradebot(mocker, default_conf)
create_mock_trades(fee)
trades = Trade.query.all()
assert len(trades) == 3
assert len(trades) == 4
freqtrade.cancel_all_open_orders()
assert buy_mock.call_count == 1
assert sell_mock.call_count == 1

View File

@@ -989,7 +989,7 @@ def test_get_overall_performance(fee):
create_mock_trades(fee)
res = Trade.get_overall_performance()
assert len(res) == 1
assert len(res) == 2
assert 'pair' in res[0]
assert 'profit' in res[0]
assert 'count' in res[0]
@@ -1004,5 +1004,5 @@ def test_get_best_pair(fee):
create_mock_trades(fee)
res = Trade.get_best_pair()
assert len(res) == 2
assert res[0] == 'ETC/BTC'
assert res[1] == 0.005
assert res[0] == 'XRP/BTC'
assert res[1] == 0.01

View File

@@ -21,7 +21,7 @@ from freqtrade.plot.plotting import (add_indicators, add_profit,
load_and_plot_trades, plot_profit,
plot_trades, store_plot_file)
from freqtrade.resolvers import StrategyResolver
from tests.conftest import get_args, log_has, log_has_re
from tests.conftest import get_args, log_has, log_has_re, patch_exchange
def fig_generating_mock(fig, *args, **kwargs):
@@ -316,6 +316,8 @@ def test_start_plot_dataframe(mocker):
def test_load_and_plot_trades(default_conf, mocker, caplog, testdatadir):
patch_exchange(mocker)
default_conf['trade_source'] = 'file'
default_conf["datadir"] = testdatadir
default_conf['exportfilename'] = testdatadir / "backtest-result_test.json"