Merge branch 'develop' into hyperopt-simplified-interface

This commit is contained in:
hroff-1902
2019-09-06 15:11:06 +03:00
committed by GitHub
26 changed files with 502 additions and 300 deletions

View File

@@ -45,7 +45,7 @@ def log_has_re(line, logs):
def get_args(args):
return Arguments(args, '').get_parsed_arg()
return Arguments(args).get_parsed_arg()
def patched_configuration_load_config_file(mocker, config) -> None:

View File

@@ -4,7 +4,8 @@ from unittest.mock import MagicMock
import ccxt
import pytest
from freqtrade import DependencyException, OperationalException, TemporaryError
from freqtrade import (DependencyException, InvalidOrderException,
OperationalException, TemporaryError)
from freqtrade.tests.conftest import get_patched_exchange
@@ -49,8 +50,9 @@ def test_stoploss_limit_order(default_conf, mocker):
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'binance')
exchange.stoploss_limit(pair='ETH/BTC', amount=1, stop_price=220, rate=200)
with pytest.raises(DependencyException):
api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
with pytest.raises(InvalidOrderException):
api_mock.create_order = MagicMock(
side_effect=ccxt.InvalidOrder("binance Order would trigger immediately."))
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'binance')
exchange.stoploss_limit(pair='ETH/BTC', amount=1, stop_price=220, rate=200)

View File

@@ -418,7 +418,8 @@ def test_start_calls_optimizer(mocker, default_conf, caplog, capsys) -> None:
parallel = mocker.patch(
'freqtrade.optimize.hyperopt.Hyperopt.run_optimizer_parallel',
MagicMock(return_value=[{'loss': 1, 'results_explanation': 'foo result', 'params': {}}])
MagicMock(return_value=[{'loss': 1, 'results_explanation': 'foo result',
'params': {'buy': {}, 'sell': {}, 'roi': {}, 'stoploss': 0.0}}])
)
patch_exchange(mocker)

View File

@@ -100,7 +100,7 @@ def test_authorized_only(default_conf, mocker, caplog) -> None:
bot = FreqtradeBot(default_conf)
patch_get_signal(bot, (True, False))
dummy = DummyCls(bot)
dummy.dummy_handler(bot=MagicMock(), update=update)
dummy.dummy_handler(update=update, context=MagicMock())
assert dummy.state['called'] is True
assert log_has('Executing handler: dummy_handler for chat_id: 0', caplog)
assert not log_has('Rejected unauthorized message from: 0', caplog)
@@ -117,7 +117,7 @@ def test_authorized_only_unauthorized(default_conf, mocker, caplog) -> None:
bot = FreqtradeBot(default_conf)
patch_get_signal(bot, (True, False))
dummy = DummyCls(bot)
dummy.dummy_handler(bot=MagicMock(), update=update)
dummy.dummy_handler(update=update, context=MagicMock())
assert dummy.state['called'] is False
assert not log_has('Executing handler: dummy_handler for chat_id: 3735928559', caplog)
assert log_has('Rejected unauthorized message from: 3735928559', caplog)
@@ -136,7 +136,7 @@ def test_authorized_only_exception(default_conf, mocker, caplog) -> None:
patch_get_signal(bot, (True, False))
dummy = DummyCls(bot)
dummy.dummy_exception(bot=MagicMock(), update=update)
dummy.dummy_exception(update=update, context=MagicMock())
assert dummy.state['called'] is False
assert not log_has('Executing handler: dummy_handler for chat_id: 0', caplog)
assert not log_has('Rejected unauthorized message from: 0', caplog)
@@ -194,12 +194,13 @@ def test_status(default_conf, update, mocker, fee, ticker, markets) -> None:
for _ in range(3):
freqtradebot.create_trades()
telegram._status(bot=MagicMock(), update=update)
telegram._status(update=update, context=MagicMock())
assert msg_mock.call_count == 1
update.message.text = MagicMock()
update.message.text.replace = MagicMock(return_value='table 2 3')
telegram._status(bot=MagicMock(), update=update)
context = MagicMock()
# /status table 2 3
context.args = ["table", "2", "3"]
telegram._status(update=update, context=context)
assert status_table.call_count == 1
@@ -228,13 +229,13 @@ def test_status_handle(default_conf, update, ticker, fee, markets, mocker) -> No
freqtradebot.state = State.STOPPED
# Status is also enabled when stopped
telegram._status(bot=MagicMock(), update=update)
telegram._status(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert 'no active trade' in msg_mock.call_args_list[0][0][0]
msg_mock.reset_mock()
freqtradebot.state = State.RUNNING
telegram._status(bot=MagicMock(), update=update)
telegram._status(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert 'no active trade' in msg_mock.call_args_list[0][0][0]
msg_mock.reset_mock()
@@ -242,7 +243,7 @@ def test_status_handle(default_conf, update, ticker, fee, markets, mocker) -> No
# Create some test data
freqtradebot.create_trades()
# Trigger status while we have a fulfilled order for the open trade
telegram._status(bot=MagicMock(), update=update)
telegram._status(update=update, context=MagicMock())
# close_rate should not be included in the message as the trade is not closed
# and no line should be empty
@@ -280,13 +281,13 @@ def test_status_table_handle(default_conf, update, ticker, fee, markets, mocker)
freqtradebot.state = State.STOPPED
# Status table is also enabled when stopped
telegram._status_table(bot=MagicMock(), update=update)
telegram._status_table(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert 'no active order' in msg_mock.call_args_list[0][0][0]
msg_mock.reset_mock()
freqtradebot.state = State.RUNNING
telegram._status_table(bot=MagicMock(), update=update)
telegram._status_table(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert 'no active order' in msg_mock.call_args_list[0][0][0]
msg_mock.reset_mock()
@@ -294,7 +295,7 @@ def test_status_table_handle(default_conf, update, ticker, fee, markets, mocker)
# Create some test data
freqtradebot.create_trades()
telegram._status_table(bot=MagicMock(), update=update)
telegram._status_table(update=update, context=MagicMock())
text = re.sub('</?pre>', '', msg_mock.call_args_list[-1][0][0])
line = text.split("\n")
@@ -346,8 +347,10 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee,
trade.is_open = False
# Try valid data
update.message.text = '/daily 2'
telegram._daily(bot=MagicMock(), update=update)
# /daily 2
context = MagicMock()
context.args = ["2"]
telegram._daily(update=update, context=context)
assert msg_mock.call_count == 1
assert 'Daily' in msg_mock.call_args_list[0][0][0]
assert str(datetime.utcnow().date()) in msg_mock.call_args_list[0][0][0]
@@ -369,9 +372,10 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee,
trade.close_date = datetime.utcnow()
trade.is_open = False
update.message.text = '/daily 1'
telegram._daily(bot=MagicMock(), update=update)
# /daily 1
context = MagicMock()
context.args = ["1"]
telegram._daily(update=update, context=context)
assert str(' 0.00018651 BTC') in msg_mock.call_args_list[0][0][0]
assert str(' 2.798 USD') in msg_mock.call_args_list[0][0][0]
assert str(' 3 trades') in msg_mock.call_args_list[0][0][0]
@@ -398,16 +402,20 @@ def test_daily_wrong_input(default_conf, update, ticker, mocker) -> None:
# Try invalid data
msg_mock.reset_mock()
freqtradebot.state = State.RUNNING
update.message.text = '/daily -2'
telegram._daily(bot=MagicMock(), update=update)
# /daily -2
context = MagicMock()
context.args = ["-2"]
telegram._daily(update=update, context=context)
assert msg_mock.call_count == 1
assert 'must be an integer greater than 0' in msg_mock.call_args_list[0][0][0]
# Try invalid data
msg_mock.reset_mock()
freqtradebot.state = State.RUNNING
update.message.text = '/daily today'
telegram._daily(bot=MagicMock(), update=update)
# /daily today
context = MagicMock()
context.args = ["today"]
telegram._daily(update=update, context=context)
assert str('Daily Profit over the last 7 days') in msg_mock.call_args_list[0][0][0]
@@ -433,7 +441,7 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee,
patch_get_signal(freqtradebot, (True, False))
telegram = Telegram(freqtradebot)
telegram._profit(bot=MagicMock(), update=update)
telegram._profit(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert 'no closed trade' in msg_mock.call_args_list[0][0][0]
msg_mock.reset_mock()
@@ -445,7 +453,7 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee,
# Simulate fulfilled LIMIT_BUY order for trade
trade.update(limit_buy_order)
telegram._profit(bot=MagicMock(), update=update)
telegram._profit(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert 'no closed trade' in msg_mock.call_args_list[-1][0][0]
msg_mock.reset_mock()
@@ -457,7 +465,7 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee,
trade.close_date = datetime.utcnow()
trade.is_open = False
telegram._profit(bot=MagicMock(), update=update)
telegram._profit(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert '*ROI:* Close trades' in msg_mock.call_args_list[-1][0][0]
assert '∙ `0.00006217 BTC (6.20%)`' in msg_mock.call_args_list[-1][0][0]
@@ -507,7 +515,7 @@ def test_telegram_balance_handle(default_conf, update, mocker, rpc_balance) -> N
telegram = Telegram(freqtradebot)
telegram._balance(bot=MagicMock(), update=update)
telegram._balance(update=update, context=MagicMock())
result = msg_mock.call_args_list[0][0][0]
assert msg_mock.call_count == 1
assert '*BTC:*' in result
@@ -536,7 +544,7 @@ def test_balance_handle_empty_response(default_conf, update, mocker) -> None:
telegram = Telegram(freqtradebot)
freqtradebot.config['dry_run'] = False
telegram._balance(bot=MagicMock(), update=update)
telegram._balance(update=update, context=MagicMock())
result = msg_mock.call_args_list[0][0][0]
assert msg_mock.call_count == 1
assert 'All balances are zero.' in result
@@ -557,7 +565,7 @@ def test_balance_handle_empty_response_dry(default_conf, update, mocker) -> None
telegram = Telegram(freqtradebot)
telegram._balance(bot=MagicMock(), update=update)
telegram._balance(update=update, context=MagicMock())
result = msg_mock.call_args_list[0][0][0]
assert msg_mock.call_count == 1
assert "Running in Dry Run, balances are not available." in result
@@ -593,7 +601,7 @@ def test_balance_handle_too_large_response(default_conf, update, mocker) -> None
telegram = Telegram(freqtradebot)
telegram._balance(bot=MagicMock(), update=update)
telegram._balance(update=update, context=MagicMock())
assert msg_mock.call_count > 1
# Test if wrap happens around 4000 -
# and each single currency-output is around 120 characters long so we need
@@ -615,7 +623,7 @@ def test_start_handle(default_conf, update, mocker) -> None:
freqtradebot.state = State.STOPPED
assert freqtradebot.state == State.STOPPED
telegram._start(bot=MagicMock(), update=update)
telegram._start(update=update, context=MagicMock())
assert freqtradebot.state == State.RUNNING
assert msg_mock.call_count == 1
@@ -633,7 +641,7 @@ def test_start_handle_already_running(default_conf, update, mocker) -> None:
freqtradebot.state = State.RUNNING
assert freqtradebot.state == State.RUNNING
telegram._start(bot=MagicMock(), update=update)
telegram._start(update=update, context=MagicMock())
assert freqtradebot.state == State.RUNNING
assert msg_mock.call_count == 1
assert 'already running' in msg_mock.call_args_list[0][0][0]
@@ -652,7 +660,7 @@ def test_stop_handle(default_conf, update, mocker) -> None:
freqtradebot.state = State.RUNNING
assert freqtradebot.state == State.RUNNING
telegram._stop(bot=MagicMock(), update=update)
telegram._stop(update=update, context=MagicMock())
assert freqtradebot.state == State.STOPPED
assert msg_mock.call_count == 1
assert 'stopping trader' in msg_mock.call_args_list[0][0][0]
@@ -671,7 +679,7 @@ def test_stop_handle_already_stopped(default_conf, update, mocker) -> None:
freqtradebot.state = State.STOPPED
assert freqtradebot.state == State.STOPPED
telegram._stop(bot=MagicMock(), update=update)
telegram._stop(update=update, context=MagicMock())
assert freqtradebot.state == State.STOPPED
assert msg_mock.call_count == 1
assert 'already stopped' in msg_mock.call_args_list[0][0][0]
@@ -689,7 +697,7 @@ def test_stopbuy_handle(default_conf, update, mocker) -> None:
telegram = Telegram(freqtradebot)
assert freqtradebot.config['max_open_trades'] != 0
telegram._stopbuy(bot=MagicMock(), update=update)
telegram._stopbuy(update=update, context=MagicMock())
assert freqtradebot.config['max_open_trades'] == 0
assert msg_mock.call_count == 1
assert 'No more buy will occur from now. Run /reload_conf to reset.' \
@@ -709,7 +717,7 @@ def test_reload_conf_handle(default_conf, update, mocker) -> None:
freqtradebot.state = State.RUNNING
assert freqtradebot.state == State.RUNNING
telegram._reload_conf(bot=MagicMock(), update=update)
telegram._reload_conf(update=update, context=MagicMock())
assert freqtradebot.state == State.RELOAD_CONF
assert msg_mock.call_count == 1
assert 'reloading config' in msg_mock.call_args_list[0][0][0]
@@ -742,8 +750,10 @@ def test_forcesell_handle(default_conf, update, ticker, fee,
# Increase the price and sell it
mocker.patch('freqtrade.exchange.Exchange.get_ticker', ticker_sell_up)
update.message.text = '/forcesell 1'
telegram._forcesell(bot=MagicMock(), update=update)
# /forcesell 1
context = MagicMock()
context.args = ["1"]
telegram._forcesell(update=update, context=context)
assert rpc_mock.call_count == 2
last_msg = rpc_mock.call_args_list[-1][0][0]
@@ -796,8 +806,10 @@ def test_forcesell_down_handle(default_conf, update, ticker, fee,
trade = Trade.query.first()
assert trade
update.message.text = '/forcesell 1'
telegram._forcesell(bot=MagicMock(), update=update)
# /forcesell 1
context = MagicMock()
context.args = ["1"]
telegram._forcesell(update=update, context=context)
assert rpc_mock.call_count == 2
@@ -842,8 +854,10 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, markets, mocker
freqtradebot.create_trades()
rpc_mock.reset_mock()
update.message.text = '/forcesell all'
telegram._forcesell(bot=MagicMock(), update=update)
# /forcesell all
context = MagicMock()
context.args = ["all"]
telegram._forcesell(update=update, context=context)
assert rpc_mock.call_count == 4
msg = rpc_mock.call_args_list[0][0][0]
@@ -882,24 +896,29 @@ def test_forcesell_handle_invalid(default_conf, update, mocker) -> None:
# Trader is not running
freqtradebot.state = State.STOPPED
update.message.text = '/forcesell 1'
telegram._forcesell(bot=MagicMock(), update=update)
# /forcesell 1
context = MagicMock()
context.args = ["1"]
telegram._forcesell(update=update, context=context)
assert msg_mock.call_count == 1
assert 'not running' in msg_mock.call_args_list[0][0][0]
# No argument
msg_mock.reset_mock()
freqtradebot.state = State.RUNNING
update.message.text = '/forcesell'
telegram._forcesell(bot=MagicMock(), update=update)
context = MagicMock()
context.args = []
telegram._forcesell(update=update, context=context)
assert msg_mock.call_count == 1
assert 'invalid argument' in msg_mock.call_args_list[0][0][0]
# Invalid argument
msg_mock.reset_mock()
freqtradebot.state = State.RUNNING
update.message.text = '/forcesell 123456'
telegram._forcesell(bot=MagicMock(), update=update)
# /forcesell 123456
context = MagicMock()
context.args = ["123456"]
telegram._forcesell(update=update, context=context)
assert msg_mock.call_count == 1
assert 'invalid argument' in msg_mock.call_args_list[0][0][0]
@@ -921,8 +940,10 @@ def test_forcebuy_handle(default_conf, update, markets, mocker) -> None:
patch_get_signal(freqtradebot, (True, False))
telegram = Telegram(freqtradebot)
update.message.text = '/forcebuy ETH/BTC'
telegram._forcebuy(bot=MagicMock(), update=update)
# /forcebuy ETH/BTC
context = MagicMock()
context.args = ["ETH/BTC"]
telegram._forcebuy(update=update, context=context)
assert fbuy_mock.call_count == 1
assert fbuy_mock.call_args_list[0][0][0] == 'ETH/BTC'
@@ -931,8 +952,10 @@ def test_forcebuy_handle(default_conf, update, markets, mocker) -> None:
# Reset and retry with specified price
fbuy_mock = MagicMock(return_value=None)
mocker.patch('freqtrade.rpc.RPC._rpc_forcebuy', fbuy_mock)
update.message.text = '/forcebuy ETH/BTC 0.055'
telegram._forcebuy(bot=MagicMock(), update=update)
# /forcebuy ETH/BTC 0.055
context = MagicMock()
context.args = ["ETH/BTC", "0.055"]
telegram._forcebuy(update=update, context=context)
assert fbuy_mock.call_count == 1
assert fbuy_mock.call_args_list[0][0][0] == 'ETH/BTC'
@@ -955,7 +978,7 @@ def test_forcebuy_handle_exception(default_conf, update, markets, mocker) -> Non
telegram = Telegram(freqtradebot)
update.message.text = '/forcebuy ETH/Nonepair'
telegram._forcebuy(bot=MagicMock(), update=update)
telegram._forcebuy(update=update, context=MagicMock())
assert rpc_mock.call_count == 1
assert rpc_mock.call_args_list[0][0][0] == 'Forcebuy not enabled.'
@@ -995,7 +1018,7 @@ def test_performance_handle(default_conf, update, ticker, fee,
trade.close_date = datetime.utcnow()
trade.is_open = False
telegram._performance(bot=MagicMock(), update=update)
telegram._performance(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert 'Performance' in msg_mock.call_args_list[0][0][0]
assert '<code>ETH/BTC\t6.20% (1)</code>' in msg_mock.call_args_list[0][0][0]
@@ -1021,7 +1044,7 @@ def test_count_handle(default_conf, update, ticker, fee, markets, mocker) -> Non
telegram = Telegram(freqtradebot)
freqtradebot.state = State.STOPPED
telegram._count(bot=MagicMock(), update=update)
telegram._count(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert 'not running' in msg_mock.call_args_list[0][0][0]
msg_mock.reset_mock()
@@ -1030,7 +1053,7 @@ def test_count_handle(default_conf, update, ticker, fee, markets, mocker) -> Non
# Create some test data
freqtradebot.create_trades()
msg_mock.reset_mock()
telegram._count(bot=MagicMock(), update=update)
telegram._count(update=update, context=MagicMock())
msg = '<pre> current max total stake\n--------- ----- -------------\n' \
' 1 {} {}</pre>'\
@@ -1052,7 +1075,7 @@ def test_whitelist_static(default_conf, update, mocker) -> None:
telegram = Telegram(freqtradebot)
telegram._whitelist(bot=MagicMock(), update=update)
telegram._whitelist(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert ('Using whitelist `StaticPairList` with 4 pairs\n`ETH/BTC, LTC/BTC, XRP/BTC, NEO/BTC`'
in msg_mock.call_args_list[0][0][0])
@@ -1073,7 +1096,7 @@ def test_whitelist_dynamic(default_conf, update, mocker) -> None:
telegram = Telegram(freqtradebot)
telegram._whitelist(bot=MagicMock(), update=update)
telegram._whitelist(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert ('Using whitelist `VolumePairList` with 4 pairs\n`ETH/BTC, LTC/BTC, XRP/BTC, NEO/BTC`'
in msg_mock.call_args_list[0][0][0])
@@ -1090,13 +1113,17 @@ def test_blacklist_static(default_conf, update, mocker) -> None:
telegram = Telegram(freqtradebot)
telegram._blacklist(bot=MagicMock(), update=update, args=[])
telegram._blacklist(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert ("Blacklist contains 2 pairs\n`DOGE/BTC, HOT/BTC`"
in msg_mock.call_args_list[0][0][0])
msg_mock.reset_mock()
telegram._blacklist(bot=MagicMock(), update=update, args=["ETH/BTC"])
# /blacklist ETH/BTC
context = MagicMock()
context.args = ["ETH/BTC"]
telegram._blacklist(update=update, context=context)
assert msg_mock.call_count == 1
assert ("Blacklist contains 3 pairs\n`DOGE/BTC, HOT/BTC, ETH/BTC`"
in msg_mock.call_args_list[0][0][0])
@@ -1115,7 +1142,7 @@ def test_edge_disabled(default_conf, update, mocker) -> None:
telegram = Telegram(freqtradebot)
telegram._edge(bot=MagicMock(), update=update)
telegram._edge(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert "Edge is not enabled." in msg_mock.call_args_list[0][0][0]
@@ -1137,7 +1164,7 @@ def test_edge_enabled(edge_conf, update, mocker) -> None:
telegram = Telegram(freqtradebot)
telegram._edge(bot=MagicMock(), update=update)
telegram._edge(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert '<b>Edge only validated following pairs:</b>\n<pre>' in msg_mock.call_args_list[0][0][0]
assert 'Pair Winrate Expectancy Stoploss' in msg_mock.call_args_list[0][0][0]
@@ -1154,7 +1181,7 @@ def test_help_handle(default_conf, update, mocker) -> None:
telegram = Telegram(freqtradebot)
telegram._help(bot=MagicMock(), update=update)
telegram._help(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert '*/help:* `This help message`' in msg_mock.call_args_list[0][0][0]
@@ -1169,7 +1196,7 @@ def test_version_handle(default_conf, update, mocker) -> None:
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
telegram = Telegram(freqtradebot)
telegram._version(bot=MagicMock(), update=update)
telegram._version(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert '*Version:* `{}`'.format(__version__) in msg_mock.call_args_list[0][0][0]
@@ -1395,9 +1422,11 @@ def test__send_msg(default_conf, mocker) -> None:
bot = MagicMock()
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
telegram = Telegram(freqtradebot)
telegram._updater = MagicMock()
telegram._updater.bot = bot
telegram._config['telegram']['enabled'] = True
telegram._send_msg('test', bot)
telegram._send_msg('test')
assert len(bot.method_calls) == 1
@@ -1407,9 +1436,11 @@ def test__send_msg_network_error(default_conf, mocker, caplog) -> None:
bot.send_message = MagicMock(side_effect=NetworkError('Oh snap'))
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
telegram = Telegram(freqtradebot)
telegram._updater = MagicMock()
telegram._updater.bot = bot
telegram._config['telegram']['enabled'] = True
telegram._send_msg('test', bot)
telegram._send_msg('test')
# Bot should've tried to send it twice
assert len(bot.method_calls) == 2

View File

@@ -9,13 +9,15 @@ from freqtrade.configuration.cli_options import check_int_positive
# Parse common command-line-arguments. Used for all tools
def test_parse_args_none() -> None:
arguments = Arguments([], '')
arguments = Arguments([])
assert isinstance(arguments, Arguments)
x = arguments.get_parsed_arg()
assert isinstance(x, argparse.Namespace)
assert isinstance(arguments.parser, argparse.ArgumentParser)
def test_parse_args_defaults() -> None:
args = Arguments([], '').get_parsed_arg()
args = Arguments([]).get_parsed_arg()
assert args.config == ['config.json']
assert args.strategy_path is None
assert args.datadir is None
@@ -23,33 +25,32 @@ def test_parse_args_defaults() -> None:
def test_parse_args_config() -> None:
args = Arguments(['-c', '/dev/null'], '').get_parsed_arg()
args = Arguments(['-c', '/dev/null']).get_parsed_arg()
assert args.config == ['/dev/null']
args = Arguments(['--config', '/dev/null'], '').get_parsed_arg()
args = Arguments(['--config', '/dev/null']).get_parsed_arg()
assert args.config == ['/dev/null']
args = Arguments(['--config', '/dev/null',
'--config', '/dev/zero'],
'').get_parsed_arg()
'--config', '/dev/zero'],).get_parsed_arg()
assert args.config == ['/dev/null', '/dev/zero']
def test_parse_args_db_url() -> None:
args = Arguments(['--db-url', 'sqlite:///test.sqlite'], '').get_parsed_arg()
args = Arguments(['--db-url', 'sqlite:///test.sqlite']).get_parsed_arg()
assert args.db_url == 'sqlite:///test.sqlite'
def test_parse_args_verbose() -> None:
args = Arguments(['-v'], '').get_parsed_arg()
args = Arguments(['-v']).get_parsed_arg()
assert args.verbosity == 1
args = Arguments(['--verbose'], '').get_parsed_arg()
args = Arguments(['--verbose']).get_parsed_arg()
assert args.verbosity == 1
def test_common_scripts_options() -> None:
args = Arguments(['download-data', '-p', 'ETH/BTC', 'XRP/BTC'], '').get_parsed_arg()
args = Arguments(['download-data', '-p', 'ETH/BTC', 'XRP/BTC']).get_parsed_arg()
assert args.pairs == ['ETH/BTC', 'XRP/BTC']
assert hasattr(args, "func")
@@ -57,40 +58,40 @@ def test_common_scripts_options() -> None:
def test_parse_args_version() -> None:
with pytest.raises(SystemExit, match=r'0'):
Arguments(['--version'], '').get_parsed_arg()
Arguments(['--version']).get_parsed_arg()
def test_parse_args_invalid() -> None:
with pytest.raises(SystemExit, match=r'2'):
Arguments(['-c'], '').get_parsed_arg()
Arguments(['-c']).get_parsed_arg()
def test_parse_args_strategy() -> None:
args = Arguments(['--strategy', 'SomeStrategy'], '').get_parsed_arg()
args = Arguments(['--strategy', 'SomeStrategy']).get_parsed_arg()
assert args.strategy == 'SomeStrategy'
def test_parse_args_strategy_invalid() -> None:
with pytest.raises(SystemExit, match=r'2'):
Arguments(['--strategy'], '').get_parsed_arg()
Arguments(['--strategy']).get_parsed_arg()
def test_parse_args_strategy_path() -> None:
args = Arguments(['--strategy-path', '/some/path'], '').get_parsed_arg()
args = Arguments(['--strategy-path', '/some/path']).get_parsed_arg()
assert args.strategy_path == '/some/path'
def test_parse_args_strategy_path_invalid() -> None:
with pytest.raises(SystemExit, match=r'2'):
Arguments(['--strategy-path'], '').get_parsed_arg()
Arguments(['--strategy-path']).get_parsed_arg()
def test_parse_args_backtesting_invalid() -> None:
with pytest.raises(SystemExit, match=r'2'):
Arguments(['backtesting --ticker-interval'], '').get_parsed_arg()
Arguments(['backtesting --ticker-interval']).get_parsed_arg()
with pytest.raises(SystemExit, match=r'2'):
Arguments(['backtesting --ticker-interval', 'abc'], '').get_parsed_arg()
Arguments(['backtesting --ticker-interval', 'abc']).get_parsed_arg()
def test_parse_args_backtesting_custom() -> None:
@@ -103,7 +104,7 @@ def test_parse_args_backtesting_custom() -> None:
'DefaultStrategy',
'SampleStrategy'
]
call_args = Arguments(args, '').get_parsed_arg()
call_args = Arguments(args).get_parsed_arg()
assert call_args.config == ['test_conf.json']
assert call_args.verbosity == 0
assert call_args.subparser == 'backtesting'
@@ -121,7 +122,7 @@ def test_parse_args_hyperopt_custom() -> None:
'--epochs', '20',
'--spaces', 'buy'
]
call_args = Arguments(args, '').get_parsed_arg()
call_args = Arguments(args).get_parsed_arg()
assert call_args.config == ['test_conf.json']
assert call_args.epochs == 20
assert call_args.verbosity == 0
@@ -138,7 +139,7 @@ def test_download_data_options() -> None:
'--days', '30',
'--exchange', 'binance'
]
args = Arguments(args, '').get_parsed_arg()
args = Arguments(args).get_parsed_arg()
assert args.pairs_file == 'file_with_pairs'
assert args.datadir == 'datadir/directory'
@@ -155,7 +156,7 @@ def test_plot_dataframe_options() -> None:
'--plot-limit', '30',
'-p', 'UNITTEST/BTC',
]
pargs = Arguments(args, '').get_parsed_arg()
pargs = Arguments(args).get_parsed_arg()
assert pargs.indicators1 == ["sma10", "sma100"]
assert pargs.indicators2 == ["macd", "fastd", "fastk"]
@@ -170,7 +171,7 @@ def test_plot_profit_options() -> None:
'--trade-source', 'DB',
"--db-url", "sqlite:///whatever.sqlite",
]
pargs = Arguments(args, '').get_parsed_arg()
pargs = Arguments(args).get_parsed_arg()
assert pargs.trade_source == "DB"
assert pargs.pairs == ["UNITTEST/BTC"]

View File

@@ -66,7 +66,7 @@ def test_load_config_file(default_conf, mocker, caplog) -> None:
def test__args_to_config(caplog):
arg_list = ['--strategy-path', 'TestTest']
args = Arguments(arg_list, '').get_parsed_arg()
args = Arguments(arg_list).get_parsed_arg()
configuration = Configuration(args)
config = {}
with warnings.catch_warnings(record=True) as w:
@@ -93,7 +93,7 @@ def test_load_config_max_open_trades_zero(default_conf, mocker, caplog) -> None:
default_conf['max_open_trades'] = 0
patched_configuration_load_config_file(mocker, default_conf)
args = Arguments([], '').get_parsed_arg()
args = Arguments([]).get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
@@ -119,7 +119,7 @@ def test_load_config_combine_dicts(default_conf, mocker, caplog) -> None:
)
arg_list = ['-c', 'test_conf.json', '--config', 'test2_conf.json', ]
args = Arguments(arg_list, '').get_parsed_arg()
args = Arguments(arg_list).get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
@@ -167,7 +167,7 @@ def test_load_config_max_open_trades_minus_one(default_conf, mocker, caplog) ->
default_conf['max_open_trades'] = -1
patched_configuration_load_config_file(mocker, default_conf)
args = Arguments([], '').get_parsed_arg()
args = Arguments([]).get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
@@ -191,7 +191,7 @@ def test_load_config_file_exception(mocker) -> None:
def test_load_config(default_conf, mocker) -> None:
patched_configuration_load_config_file(mocker, default_conf)
args = Arguments([], '').get_parsed_arg()
args = Arguments([]).get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
@@ -208,7 +208,7 @@ def test_load_config_with_params(default_conf, mocker) -> None:
'--strategy-path', '/some/path',
'--db-url', 'sqlite:///someurl',
]
args = Arguments(arglist, '').get_parsed_arg()
args = Arguments(arglist).get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
@@ -226,7 +226,7 @@ def test_load_config_with_params(default_conf, mocker) -> None:
'--strategy', 'TestStrategy',
'--strategy-path', '/some/path'
]
args = Arguments(arglist, '').get_parsed_arg()
args = Arguments(arglist).get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
@@ -242,7 +242,7 @@ def test_load_config_with_params(default_conf, mocker) -> None:
'--strategy', 'TestStrategy',
'--strategy-path', '/some/path'
]
args = Arguments(arglist, '').get_parsed_arg()
args = Arguments(arglist).get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
@@ -258,7 +258,7 @@ def test_load_config_with_params(default_conf, mocker) -> None:
'--strategy', 'TestStrategy',
'--strategy-path', '/some/path'
]
args = Arguments(arglist, '').get_parsed_arg()
args = Arguments(arglist).get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
@@ -276,7 +276,7 @@ def test_load_config_with_params(default_conf, mocker) -> None:
'--strategy', 'TestStrategy',
'--strategy-path', '/some/path'
]
args = Arguments(arglist, '').get_parsed_arg()
args = Arguments(arglist).get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
@@ -290,7 +290,7 @@ def test_load_custom_strategy(default_conf, mocker) -> None:
})
patched_configuration_load_config_file(mocker, default_conf)
args = Arguments([], '').get_parsed_arg()
args = Arguments([]).get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
@@ -305,7 +305,7 @@ def test_show_info(default_conf, mocker, caplog) -> None:
'--strategy', 'TestStrategy',
'--db-url', 'sqlite:///tmp/testdb',
]
args = Arguments(arglist, '').get_parsed_arg()
args = Arguments(arglist).get_parsed_arg()
configuration = Configuration(args)
configuration.get_config()
@@ -323,7 +323,7 @@ def test_setup_configuration_without_arguments(mocker, default_conf, caplog) ->
'backtesting'
]
args = Arguments(arglist, '').get_parsed_arg()
args = Arguments(arglist).get_parsed_arg()
configuration = Configuration(args)
config = configuration.get_config()
@@ -373,7 +373,7 @@ def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> Non
'--export', '/bar/foo'
]
args = Arguments(arglist, '').get_parsed_arg()
args = Arguments(arglist).get_parsed_arg()
configuration = Configuration(args)
config = configuration.get_config()
@@ -423,7 +423,7 @@ def test_setup_configuration_with_stratlist(mocker, default_conf, caplog) -> Non
'TestStrategy'
]
args = Arguments(arglist, '').get_parsed_arg()
args = Arguments(arglist).get_parsed_arg()
configuration = Configuration(args, RunMode.BACKTEST)
config = configuration.get_config()
@@ -460,7 +460,7 @@ def test_hyperopt_with_arguments(mocker, default_conf, caplog) -> None:
'--epochs', '10',
'--spaces', 'all',
]
args = Arguments(arglist, '').get_parsed_arg()
args = Arguments(arglist).get_parsed_arg()
configuration = Configuration(args, RunMode.HYPEROPT)
config = configuration.get_config()
@@ -536,7 +536,7 @@ def test_cli_verbose_with_params(default_conf, mocker, caplog) -> None:
# Prevent setting loggers
mocker.patch('freqtrade.loggers._set_loggers', MagicMock)
arglist = ['-vvv']
args = Arguments(arglist, '').get_parsed_arg()
args = Arguments(arglist).get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
@@ -589,7 +589,7 @@ def test_set_logfile(default_conf, mocker):
arglist = [
'--logfile', 'test_file.log',
]
args = Arguments(arglist, '').get_parsed_arg()
args = Arguments(arglist).get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
@@ -603,7 +603,7 @@ def test_load_config_warn_forcebuy(default_conf, mocker, caplog) -> None:
default_conf['forcebuy_enable'] = True
patched_configuration_load_config_file(mocker, default_conf)
args = Arguments([], '').get_parsed_arg()
args = Arguments([]).get_parsed_arg()
configuration = Configuration(args)
validated_conf = configuration.load_config()
@@ -778,7 +778,7 @@ def test_pairlist_resolving():
'--exchange', 'binance'
]
args = Arguments(arglist, '').get_parsed_arg()
args = Arguments(arglist).get_parsed_arg()
configuration = Configuration(args)
config = configuration.get_config()
@@ -794,7 +794,7 @@ def test_pairlist_resolving_with_config(mocker, default_conf):
'download-data',
]
args = Arguments(arglist, '').get_parsed_arg()
args = Arguments(arglist).get_parsed_arg()
configuration = Configuration(args)
config = configuration.get_config()
@@ -809,7 +809,7 @@ def test_pairlist_resolving_with_config(mocker, default_conf):
'--pairs', 'ETH/BTC', 'XRP/BTC',
]
args = Arguments(arglist, '').get_parsed_arg()
args = Arguments(arglist).get_parsed_arg()
configuration = Configuration(args)
config = configuration.get_config()
@@ -831,7 +831,7 @@ def test_pairlist_resolving_with_config_pl(mocker, default_conf):
'--pairs-file', 'pairs.json',
]
args = Arguments(arglist, '').get_parsed_arg()
args = Arguments(arglist).get_parsed_arg()
configuration = Configuration(args)
config = configuration.get_config()
@@ -853,7 +853,7 @@ def test_pairlist_resolving_with_config_pl_not_exists(mocker, default_conf):
'--pairs-file', 'pairs.json',
]
args = Arguments(arglist, '').get_parsed_arg()
args = Arguments(arglist).get_parsed_arg()
with pytest.raises(OperationalException, match=r"No pairs file found with path.*"):
configuration = Configuration(args)
@@ -870,7 +870,9 @@ def test_pairlist_resolving_fallback(mocker):
'--exchange', 'binance'
]
args = Arguments(arglist, '').get_parsed_arg()
args = Arguments(arglist).get_parsed_arg()
# Fix flaky tests if config.json exists
args.config = None
configuration = Configuration(args)
config = configuration.get_config()

View File

@@ -1152,7 +1152,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf, fee, caplog,
side_effect=DependencyException()
)
freqtrade.handle_stoploss_on_exchange(trade)
assert log_has('Unable to place a stoploss order on exchange: ', caplog)
assert log_has('Unable to place a stoploss order on exchange.', caplog)
assert trade.stoploss_order_id is None
# Fifth case: get_order returns InvalidOrder
@@ -1200,6 +1200,50 @@ def test_handle_sle_cancel_cant_recreate(mocker, default_conf, fee, caplog,
assert trade.is_open is True
def test_create_stoploss_order_invalid_order(mocker, default_conf, caplog, fee,
markets, limit_buy_order, limit_sell_order):
rpc_mock = patch_RPCManager(mocker)
patch_exchange(mocker)
sell_mock = MagicMock(return_value={'id': limit_sell_order['id']})
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_ticker=MagicMock(return_value={
'bid': 0.00001172,
'ask': 0.00001173,
'last': 0.00001172
}),
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
sell=sell_mock,
get_fee=fee,
markets=PropertyMock(return_value=markets),
get_order=MagicMock(return_value={'status': 'canceled'}),
stoploss_limit=MagicMock(side_effect=InvalidOrderException()),
)
freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade)
freqtrade.strategy.order_types['stoploss_on_exchange'] = True
freqtrade.create_trades()
trade = Trade.query.first()
caplog.clear()
freqtrade.create_stoploss_order(trade, 200, 199)
assert trade.stoploss_order_id is None
assert trade.sell_reason == SellType.EMERGENCY_SELL.value
assert log_has("Unable to place a stoploss order on exchange. ", caplog)
assert log_has("Selling the trade forcefully", caplog)
# Should call a market sell
assert sell_mock.call_count == 1
assert sell_mock.call_args[1]['ordertype'] == 'market'
assert sell_mock.call_args[1]['pair'] == trade.pair
assert sell_mock.call_args[1]['amount'] == trade.amount
# Rpc is sending first buy, then sell
assert rpc_mock.call_count == 2
assert rpc_mock.call_args_list[1][0][0]['sell_reason'] == SellType.EMERGENCY_SELL.value
assert rpc_mock.call_args_list[1][0][0]['order_type'] == 'market'
def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee, caplog,
markets, limit_buy_order, limit_sell_order) -> None:
# When trailing stoploss is set

View File

@@ -117,7 +117,7 @@ def test_main_reload_conf(mocker, default_conf, caplog) -> None:
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock())
args = Arguments(['-c', 'config.json.example'], '').get_parsed_arg()
args = Arguments(['-c', 'config.json.example']).get_parsed_arg()
worker = Worker(args=args, config=default_conf)
with pytest.raises(SystemExit):
main(['-c', 'config.json.example'])
@@ -139,7 +139,7 @@ def test_reconfigure(mocker, default_conf) -> None:
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock())
args = Arguments(['-c', 'config.json.example'], '').get_parsed_arg()
args = Arguments(['-c', 'config.json.example']).get_parsed_arg()
worker = Worker(args=args, config=default_conf)
freqtrade = worker.freqtrade

View File

@@ -4,8 +4,10 @@ from pathlib import Path
from unittest.mock import MagicMock
import plotly.graph_objects as go
import pytest
from plotly.subplots import make_subplots
from freqtrade import OperationalException
from freqtrade.configuration import TimeRange
from freqtrade.data import history
from freqtrade.data.btanalysis import create_cum_profit, load_backtest_data
@@ -335,6 +337,15 @@ def test_start_plot_profit(mocker):
assert called_config['pairs'] == ["ETH/BTC"]
def test_start_plot_profit_error(mocker):
args = [
"plot-profit",
"--pairs", "ETH/BTC"
]
with pytest.raises(OperationalException):
start_plot_profit(get_args(args))
def test_plot_profit(default_conf, mocker, caplog):
default_conf['trade_source'] = 'file'
default_conf["datadir"] = history.make_testdata_path(None)