Merge branch 'develop' into data_handler
This commit is contained in:
116
tests/commands/test_build_config.py
Normal file
116
tests/commands/test_build_config.py
Normal file
@@ -0,0 +1,116 @@
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
import rapidjson
|
||||
|
||||
from freqtrade.commands.build_config_commands import (ask_user_config,
|
||||
ask_user_overwrite,
|
||||
start_new_config,
|
||||
validate_is_float,
|
||||
validate_is_int)
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from tests.conftest import get_args, log_has_re
|
||||
|
||||
|
||||
def test_validate_is_float():
|
||||
assert validate_is_float('2.0')
|
||||
assert validate_is_float('2.1')
|
||||
assert validate_is_float('0.1')
|
||||
assert validate_is_float('-0.5')
|
||||
assert not validate_is_float('-0.5e')
|
||||
|
||||
|
||||
def test_validate_is_int():
|
||||
assert validate_is_int('2')
|
||||
assert validate_is_int('6')
|
||||
assert validate_is_int('-1')
|
||||
assert validate_is_int('500')
|
||||
assert not validate_is_int('2.0')
|
||||
assert not validate_is_int('2.1')
|
||||
assert not validate_is_int('-2.1')
|
||||
assert not validate_is_int('-ee')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('exchange', ['bittrex', 'binance', 'kraken', 'ftx'])
|
||||
def test_start_new_config(mocker, caplog, exchange):
|
||||
wt_mock = mocker.patch.object(Path, "write_text", MagicMock())
|
||||
mocker.patch.object(Path, "exists", MagicMock(return_value=True))
|
||||
unlink_mock = mocker.patch.object(Path, "unlink", MagicMock())
|
||||
mocker.patch('freqtrade.commands.build_config_commands.ask_user_overwrite', return_value=True)
|
||||
|
||||
sample_selections = {
|
||||
'max_open_trades': 3,
|
||||
'stake_currency': 'USDT',
|
||||
'stake_amount': 100,
|
||||
'fiat_display_currency': 'EUR',
|
||||
'ticker_interval': '15m',
|
||||
'dry_run': True,
|
||||
'exchange_name': exchange,
|
||||
'exchange_key': 'sampleKey',
|
||||
'exchange_secret': 'Samplesecret',
|
||||
'telegram': False,
|
||||
'telegram_token': 'asdf1244',
|
||||
'telegram_chat_id': '1144444',
|
||||
}
|
||||
mocker.patch('freqtrade.commands.build_config_commands.ask_user_config',
|
||||
return_value=sample_selections)
|
||||
args = [
|
||||
"new-config",
|
||||
"--config",
|
||||
"coolconfig.json"
|
||||
]
|
||||
start_new_config(get_args(args))
|
||||
|
||||
assert log_has_re("Writing config to .*", caplog)
|
||||
assert wt_mock.call_count == 1
|
||||
assert unlink_mock.call_count == 1
|
||||
result = rapidjson.loads(wt_mock.call_args_list[0][0][0],
|
||||
parse_mode=rapidjson.PM_COMMENTS | rapidjson.PM_TRAILING_COMMAS)
|
||||
assert result['exchange']['name'] == exchange
|
||||
assert result['ticker_interval'] == '15m'
|
||||
|
||||
|
||||
def test_start_new_config_exists(mocker, caplog):
|
||||
mocker.patch.object(Path, "exists", MagicMock(return_value=True))
|
||||
mocker.patch('freqtrade.commands.build_config_commands.ask_user_overwrite', return_value=False)
|
||||
args = [
|
||||
"new-config",
|
||||
"--config",
|
||||
"coolconfig.json"
|
||||
]
|
||||
with pytest.raises(OperationalException, match=r"Configuration .* already exists\."):
|
||||
start_new_config(get_args(args))
|
||||
|
||||
|
||||
def test_ask_user_overwrite(mocker):
|
||||
"""
|
||||
Once https://github.com/tmbo/questionary/issues/35 is implemented, improve this test.
|
||||
"""
|
||||
prompt_mock = mocker.patch('freqtrade.commands.build_config_commands.prompt',
|
||||
return_value={'overwrite': False})
|
||||
assert not ask_user_overwrite(Path('test.json'))
|
||||
assert prompt_mock.call_count == 1
|
||||
|
||||
prompt_mock.reset_mock()
|
||||
prompt_mock = mocker.patch('freqtrade.commands.build_config_commands.prompt',
|
||||
return_value={'overwrite': True})
|
||||
assert ask_user_overwrite(Path('test.json'))
|
||||
assert prompt_mock.call_count == 1
|
||||
|
||||
|
||||
def test_ask_user_config(mocker):
|
||||
"""
|
||||
Once https://github.com/tmbo/questionary/issues/35 is implemented, improve this test.
|
||||
"""
|
||||
prompt_mock = mocker.patch('freqtrade.commands.build_config_commands.prompt',
|
||||
return_value={'overwrite': False})
|
||||
answers = ask_user_config()
|
||||
assert isinstance(answers, dict)
|
||||
assert prompt_mock.call_count == 1
|
||||
|
||||
prompt_mock = mocker.patch('freqtrade.commands.build_config_commands.prompt',
|
||||
return_value={})
|
||||
|
||||
with pytest.raises(OperationalException, match=r"User interrupted interactive questions\."):
|
||||
ask_user_config()
|
@@ -778,6 +778,121 @@ def test_hyperopt_list(mocker, capsys, hyperopt_results):
|
||||
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",
|
||||
"--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"])
|
||||
|
||||
|
||||
def test_hyperopt_show(mocker, capsys, hyperopt_results):
|
||||
|
@@ -24,7 +24,7 @@ from freqtrade.data.history.jsondatahandler import (JsonDataHandler,
|
||||
JsonGzDataHandler)
|
||||
from freqtrade.exchange import timeframe_to_minutes
|
||||
from freqtrade.misc import file_dump_json
|
||||
from freqtrade.strategy.default_strategy import DefaultStrategy
|
||||
from freqtrade.resolvers import StrategyResolver
|
||||
from tests.conftest import (get_patched_exchange, log_has, log_has_re,
|
||||
patch_exchange)
|
||||
|
||||
@@ -352,7 +352,7 @@ def test_load_partial_missing(testdatadir, caplog) -> None:
|
||||
|
||||
def test_init(default_conf, mocker) -> None:
|
||||
assert {} == load_data(
|
||||
datadir='',
|
||||
datadir=Path(''),
|
||||
pairs=[],
|
||||
timeframe=default_conf['ticker_interval']
|
||||
)
|
||||
@@ -361,13 +361,13 @@ def test_init(default_conf, mocker) -> None:
|
||||
def test_init_with_refresh(default_conf, mocker) -> None:
|
||||
exchange = get_patched_exchange(mocker, default_conf)
|
||||
refresh_data(
|
||||
datadir='',
|
||||
datadir=Path(''),
|
||||
pairs=[],
|
||||
timeframe=default_conf['ticker_interval'],
|
||||
exchange=exchange
|
||||
)
|
||||
assert {} == load_data(
|
||||
datadir='',
|
||||
datadir=Path(''),
|
||||
pairs=[],
|
||||
timeframe=default_conf['ticker_interval']
|
||||
)
|
||||
@@ -399,7 +399,9 @@ def test_file_dump_json_tofile(testdatadir) -> None:
|
||||
|
||||
def test_get_timerange(default_conf, mocker, testdatadir) -> None:
|
||||
patch_exchange(mocker)
|
||||
strategy = DefaultStrategy(default_conf)
|
||||
|
||||
default_conf.update({'strategy': 'DefaultStrategy'})
|
||||
strategy = StrategyResolver.load_strategy(default_conf)
|
||||
|
||||
data = strategy.tickerdata_to_dataframe(
|
||||
load_data(
|
||||
@@ -415,7 +417,9 @@ def test_get_timerange(default_conf, mocker, testdatadir) -> None:
|
||||
|
||||
def test_validate_backtest_data_warn(default_conf, mocker, caplog, testdatadir) -> None:
|
||||
patch_exchange(mocker)
|
||||
strategy = DefaultStrategy(default_conf)
|
||||
|
||||
default_conf.update({'strategy': 'DefaultStrategy'})
|
||||
strategy = StrategyResolver.load_strategy(default_conf)
|
||||
|
||||
data = strategy.tickerdata_to_dataframe(
|
||||
load_data(
|
||||
@@ -437,7 +441,9 @@ def test_validate_backtest_data_warn(default_conf, mocker, caplog, testdatadir)
|
||||
|
||||
def test_validate_backtest_data(default_conf, mocker, caplog, testdatadir) -> None:
|
||||
patch_exchange(mocker)
|
||||
strategy = DefaultStrategy(default_conf)
|
||||
|
||||
default_conf.update({'strategy': 'DefaultStrategy'})
|
||||
strategy = StrategyResolver.load_strategy(default_conf)
|
||||
|
||||
timerange = TimeRange('index', 'index', 200, 250)
|
||||
data = strategy.tickerdata_to_dataframe(
|
||||
|
@@ -1,4 +1,4 @@
|
||||
from typing import Dict, List, NamedTuple
|
||||
from typing import Dict, List, NamedTuple, Optional
|
||||
|
||||
import arrow
|
||||
from pandas import DataFrame
|
||||
@@ -23,14 +23,14 @@ class BTContainer(NamedTuple):
|
||||
"""
|
||||
Minimal BacktestContainer defining Backtest inputs and results.
|
||||
"""
|
||||
data: List[float]
|
||||
data: List[List[float]]
|
||||
stop_loss: float
|
||||
roi: Dict[str, float]
|
||||
trades: List[BTrade]
|
||||
profit_perc: float
|
||||
trailing_stop: bool = False
|
||||
trailing_only_offset_is_reached: bool = False
|
||||
trailing_stop_positive: float = None
|
||||
trailing_stop_positive: Optional[float] = None
|
||||
trailing_stop_positive_offset: float = 0.0
|
||||
use_sell_signal: bool = False
|
||||
|
||||
|
@@ -364,7 +364,7 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data) -> None:
|
||||
default_conf["trailing_stop"] = data.trailing_stop
|
||||
default_conf["trailing_only_offset_is_reached"] = data.trailing_only_offset_is_reached
|
||||
# Only add this to configuration If it's necessary
|
||||
if data.trailing_stop_positive:
|
||||
if data.trailing_stop_positive is not None:
|
||||
default_conf["trailing_stop_positive"] = data.trailing_stop_positive
|
||||
default_conf["trailing_stop_positive_offset"] = data.trailing_stop_positive_offset
|
||||
default_conf["ask_strategy"] = {"use_sell_signal": data.use_sell_signal}
|
||||
|
@@ -19,8 +19,8 @@ from freqtrade.data.dataprovider import DataProvider
|
||||
from freqtrade.data.history import get_timerange
|
||||
from freqtrade.exceptions import DependencyException, OperationalException
|
||||
from freqtrade.optimize.backtesting import Backtesting
|
||||
from freqtrade.resolvers import StrategyResolver
|
||||
from freqtrade.state import RunMode
|
||||
from freqtrade.strategy.default_strategy import DefaultStrategy
|
||||
from freqtrade.strategy.interface import SellType
|
||||
from tests.conftest import (get_args, log_has, log_has_re, patch_exchange,
|
||||
patched_configuration_load_config_file)
|
||||
@@ -257,8 +257,8 @@ def test_start(mocker, fee, default_conf, caplog) -> None:
|
||||
'--config', 'config.json',
|
||||
'--strategy', 'DefaultStrategy',
|
||||
]
|
||||
args = get_args(args)
|
||||
start_backtesting(args)
|
||||
pargs = get_args(args)
|
||||
start_backtesting(pargs)
|
||||
assert log_has('Starting freqtrade in Backtesting mode', caplog)
|
||||
assert start_mock.call_count == 1
|
||||
|
||||
@@ -317,7 +317,9 @@ def test_tickerdata_to_dataframe_bt(default_conf, mocker, testdatadir) -> None:
|
||||
assert len(data['UNITTEST/BTC']) == 102
|
||||
|
||||
# Load strategy to compare the result between Backtesting function and strategy are the same
|
||||
strategy = DefaultStrategy(default_conf)
|
||||
default_conf.update({'strategy': 'DefaultStrategy'})
|
||||
strategy = StrategyResolver.load_strategy(default_conf)
|
||||
|
||||
data2 = strategy.tickerdata_to_dataframe(tickerlist)
|
||||
assert data['UNITTEST/BTC'].equals(data2['UNITTEST/BTC'])
|
||||
|
||||
|
@@ -82,8 +82,8 @@ def test_start(mocker, fee, edge_conf, caplog) -> None:
|
||||
'--config', 'config.json',
|
||||
'--strategy', 'DefaultStrategy',
|
||||
]
|
||||
args = get_args(args)
|
||||
start_edge(args)
|
||||
pargs = get_args(args)
|
||||
start_edge(pargs)
|
||||
assert log_has('Starting freqtrade in Edge mode', caplog)
|
||||
assert start_mock.call_count == 1
|
||||
|
||||
|
@@ -2,6 +2,7 @@
|
||||
import locale
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Dict, List
|
||||
from unittest.mock import MagicMock, PropertyMock
|
||||
|
||||
import pandas as pd
|
||||
@@ -54,7 +55,7 @@ def hyperopt_results():
|
||||
|
||||
|
||||
# Functions for recurrent object patching
|
||||
def create_trials(mocker, hyperopt, testdatadir) -> None:
|
||||
def create_trials(mocker, hyperopt, testdatadir) -> List[Dict]:
|
||||
"""
|
||||
When creating trials, mock the hyperopt Trials so that *by default*
|
||||
- we don't create any pickle'd files in the filesystem
|
||||
@@ -228,10 +229,10 @@ def test_start_not_installed(mocker, default_conf, caplog, import_fails) -> None
|
||||
'--hyperopt', 'DefaultHyperOpt',
|
||||
'--epochs', '5'
|
||||
]
|
||||
args = get_args(args)
|
||||
pargs = get_args(args)
|
||||
|
||||
with pytest.raises(OperationalException, match=r"Please ensure that the hyperopt dependencies"):
|
||||
start_hyperopt(args)
|
||||
start_hyperopt(pargs)
|
||||
|
||||
|
||||
def test_start(mocker, default_conf, caplog) -> None:
|
||||
@@ -246,8 +247,8 @@ def test_start(mocker, default_conf, caplog) -> None:
|
||||
'--hyperopt', 'DefaultHyperOpt',
|
||||
'--epochs', '5'
|
||||
]
|
||||
args = get_args(args)
|
||||
start_hyperopt(args)
|
||||
pargs = get_args(args)
|
||||
start_hyperopt(pargs)
|
||||
|
||||
assert log_has('Starting freqtrade in Hyperopt mode', caplog)
|
||||
assert start_mock.call_count == 1
|
||||
@@ -269,9 +270,9 @@ def test_start_no_data(mocker, default_conf, caplog) -> None:
|
||||
'--hyperopt', 'DefaultHyperOpt',
|
||||
'--epochs', '5'
|
||||
]
|
||||
args = get_args(args)
|
||||
pargs = get_args(args)
|
||||
with pytest.raises(OperationalException, match='No data found. Terminating.'):
|
||||
start_hyperopt(args)
|
||||
start_hyperopt(pargs)
|
||||
|
||||
|
||||
def test_start_filelock(mocker, default_conf, caplog) -> None:
|
||||
@@ -286,16 +287,19 @@ def test_start_filelock(mocker, default_conf, caplog) -> None:
|
||||
'--hyperopt', 'DefaultHyperOpt',
|
||||
'--epochs', '5'
|
||||
]
|
||||
args = get_args(args)
|
||||
start_hyperopt(args)
|
||||
pargs = get_args(args)
|
||||
start_hyperopt(pargs)
|
||||
assert log_has("Another running instance of freqtrade Hyperopt detected.", caplog)
|
||||
|
||||
|
||||
def test_loss_calculation_prefer_correct_trade_count(default_conf, hyperopt_results) -> None:
|
||||
hl = HyperOptLossResolver.load_hyperoptloss(default_conf)
|
||||
correct = hl.hyperopt_loss_function(hyperopt_results, 600)
|
||||
over = hl.hyperopt_loss_function(hyperopt_results, 600 + 100)
|
||||
under = hl.hyperopt_loss_function(hyperopt_results, 600 - 100)
|
||||
correct = hl.hyperopt_loss_function(hyperopt_results, 600,
|
||||
datetime(2019, 1, 1), datetime(2019, 5, 1))
|
||||
over = hl.hyperopt_loss_function(hyperopt_results, 600 + 100,
|
||||
datetime(2019, 1, 1), datetime(2019, 5, 1))
|
||||
under = hl.hyperopt_loss_function(hyperopt_results, 600 - 100,
|
||||
datetime(2019, 1, 1), datetime(2019, 5, 1))
|
||||
assert over > correct
|
||||
assert under > correct
|
||||
|
||||
@@ -305,8 +309,10 @@ def test_loss_calculation_prefer_shorter_trades(default_conf, hyperopt_results)
|
||||
resultsb.loc[1, 'trade_duration'] = 20
|
||||
|
||||
hl = HyperOptLossResolver.load_hyperoptloss(default_conf)
|
||||
longer = hl.hyperopt_loss_function(hyperopt_results, 100)
|
||||
shorter = hl.hyperopt_loss_function(resultsb, 100)
|
||||
longer = hl.hyperopt_loss_function(hyperopt_results, 100,
|
||||
datetime(2019, 1, 1), datetime(2019, 5, 1))
|
||||
shorter = hl.hyperopt_loss_function(resultsb, 100,
|
||||
datetime(2019, 1, 1), datetime(2019, 5, 1))
|
||||
assert shorter < longer
|
||||
|
||||
|
||||
@@ -317,9 +323,12 @@ def test_loss_calculation_has_limited_profit(default_conf, hyperopt_results) ->
|
||||
results_under['profit_percent'] = hyperopt_results['profit_percent'] / 2
|
||||
|
||||
hl = HyperOptLossResolver.load_hyperoptloss(default_conf)
|
||||
correct = hl.hyperopt_loss_function(hyperopt_results, 600)
|
||||
over = hl.hyperopt_loss_function(results_over, 600)
|
||||
under = hl.hyperopt_loss_function(results_under, 600)
|
||||
correct = hl.hyperopt_loss_function(hyperopt_results, 600,
|
||||
datetime(2019, 1, 1), datetime(2019, 5, 1))
|
||||
over = hl.hyperopt_loss_function(results_over, 600,
|
||||
datetime(2019, 1, 1), datetime(2019, 5, 1))
|
||||
under = hl.hyperopt_loss_function(results_under, 600,
|
||||
datetime(2019, 1, 1), datetime(2019, 5, 1))
|
||||
assert over < correct
|
||||
assert under > correct
|
||||
|
||||
|
@@ -122,7 +122,7 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None:
|
||||
assert "Since" in headers
|
||||
assert "Pair" in headers
|
||||
assert 'instantly' == result[0][2]
|
||||
assert 'ETH/BTC' == result[0][1]
|
||||
assert 'ETH/BTC' in result[0][1]
|
||||
assert '-0.59%' == result[0][3]
|
||||
# Test with fiatconvert
|
||||
|
||||
@@ -131,7 +131,7 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None:
|
||||
assert "Since" in headers
|
||||
assert "Pair" in headers
|
||||
assert 'instantly' == result[0][2]
|
||||
assert 'ETH/BTC' == result[0][1]
|
||||
assert 'ETH/BTC' in result[0][1]
|
||||
assert '-0.59% (-0.09)' == result[0][3]
|
||||
|
||||
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker',
|
||||
@@ -140,7 +140,7 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None:
|
||||
rpc._freqtrade.exchange._cached_ticker = {}
|
||||
result, headers = rpc._rpc_status_table(default_conf['stake_currency'], 'USD')
|
||||
assert 'instantly' == result[0][2]
|
||||
assert 'ETH/BTC' == result[0][1]
|
||||
assert 'ETH/BTC' in result[0][1]
|
||||
assert 'nan%' == result[0][3]
|
||||
|
||||
|
||||
|
@@ -284,7 +284,7 @@ def test_status_table_handle(default_conf, update, ticker, fee, mocker) -> None:
|
||||
fields = re.sub('[ ]+', ' ', line[2].strip()).split(' ')
|
||||
|
||||
assert int(fields[0]) == 1
|
||||
assert fields[1] == 'ETH/BTC'
|
||||
assert 'ETH/BTC' in fields[1]
|
||||
assert msg_mock.call_count == 1
|
||||
|
||||
|
||||
@@ -1200,12 +1200,35 @@ def test_send_msg_buy_notification(default_conf, mocker) -> None:
|
||||
'stake_amount': 0.001,
|
||||
'stake_amount_fiat': 0.0,
|
||||
'stake_currency': 'BTC',
|
||||
'fiat_currency': 'USD'
|
||||
'fiat_currency': 'USD',
|
||||
'current_rate': 1.099e-05,
|
||||
'amount': 1333.3333333333335,
|
||||
'open_date': arrow.utcnow().shift(hours=-1)
|
||||
})
|
||||
assert msg_mock.call_args[0][0] \
|
||||
== '*Bittrex:* Buying ETH/BTC\n' \
|
||||
'at rate `0.00001099\n' \
|
||||
'(0.001000 BTC,0.000 USD)`'
|
||||
'*Amount:* `1333.33333333`\n' \
|
||||
'*Open Rate:* `0.00001099`\n' \
|
||||
'*Current Rate:* `0.00001099`\n' \
|
||||
'*Total:* `(0.001000 BTC, 0.000 USD)`'
|
||||
|
||||
|
||||
def test_send_msg_buy_cancel_notification(default_conf, mocker) -> None:
|
||||
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)
|
||||
telegram.send_msg({
|
||||
'type': RPCMessageType.BUY_CANCEL_NOTIFICATION,
|
||||
'exchange': 'Bittrex',
|
||||
'pair': 'ETH/BTC',
|
||||
})
|
||||
assert msg_mock.call_args[0][0] \
|
||||
== ('*Bittrex:* Cancelling Open Buy Order for ETH/BTC')
|
||||
|
||||
|
||||
def test_send_msg_sell_notification(default_conf, mocker) -> None:
|
||||
@@ -1239,13 +1262,13 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None:
|
||||
})
|
||||
assert msg_mock.call_args[0][0] \
|
||||
== ('*Binance:* Selling KEY/ETH\n'
|
||||
'*Rate:* `0.00003201`\n'
|
||||
'*Amount:* `1333.33333333`\n'
|
||||
'*Open Rate:* `0.00007500`\n'
|
||||
'*Current Rate:* `0.00003201`\n'
|
||||
'*Close Rate:* `0.00003201`\n'
|
||||
'*Sell Reason:* `stop_loss`\n'
|
||||
'*Duration:* `1:00:00 (60.0 min)`\n'
|
||||
'*Profit:* `-57.41%`` (loss: -0.05746268 ETH`` / -24.812 USD)`')
|
||||
'*Profit:* `-57.41%` `(loss: -0.05746268 ETH / -24.812 USD)`')
|
||||
|
||||
msg_mock.reset_mock()
|
||||
telegram.send_msg({
|
||||
@@ -1267,10 +1290,10 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None:
|
||||
})
|
||||
assert msg_mock.call_args[0][0] \
|
||||
== ('*Binance:* Selling KEY/ETH\n'
|
||||
'*Rate:* `0.00003201`\n'
|
||||
'*Amount:* `1333.33333333`\n'
|
||||
'*Open Rate:* `0.00007500`\n'
|
||||
'*Current Rate:* `0.00003201`\n'
|
||||
'*Close Rate:* `0.00003201`\n'
|
||||
'*Sell Reason:* `stop_loss`\n'
|
||||
'*Duration:* `1 day, 2:30:00 (1590.0 min)`\n'
|
||||
'*Profit:* `-57.41%`')
|
||||
@@ -1278,6 +1301,37 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None:
|
||||
telegram._fiat_converter.convert_amount = old_convamount
|
||||
|
||||
|
||||
def test_send_msg_sell_cancel_notification(default_conf, mocker) -> None:
|
||||
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)
|
||||
old_convamount = telegram._fiat_converter.convert_amount
|
||||
telegram._fiat_converter.convert_amount = lambda a, b, c: -24.812
|
||||
telegram.send_msg({
|
||||
'type': RPCMessageType.SELL_CANCEL_NOTIFICATION,
|
||||
'exchange': 'Binance',
|
||||
'pair': 'KEY/ETH',
|
||||
})
|
||||
assert msg_mock.call_args[0][0] \
|
||||
== ('*Binance:* Cancelling Open Sell Order for KEY/ETH')
|
||||
|
||||
msg_mock.reset_mock()
|
||||
telegram.send_msg({
|
||||
'type': RPCMessageType.SELL_CANCEL_NOTIFICATION,
|
||||
'exchange': 'Binance',
|
||||
'pair': 'KEY/ETH',
|
||||
})
|
||||
assert msg_mock.call_args[0][0] \
|
||||
== ('*Binance:* Cancelling Open Sell Order for KEY/ETH')
|
||||
# Reset singleton function to avoid random breaks
|
||||
telegram._fiat_converter.convert_amount = old_convamount
|
||||
|
||||
|
||||
def test_send_msg_status_notification(default_conf, mocker) -> None:
|
||||
msg_mock = MagicMock()
|
||||
mocker.patch.multiple(
|
||||
@@ -1360,12 +1414,17 @@ def test_send_msg_buy_notification_no_fiat(default_conf, mocker) -> None:
|
||||
'stake_amount': 0.001,
|
||||
'stake_amount_fiat': 0.0,
|
||||
'stake_currency': 'BTC',
|
||||
'fiat_currency': None
|
||||
'fiat_currency': None,
|
||||
'current_rate': 1.099e-05,
|
||||
'amount': 1333.3333333333335,
|
||||
'open_date': arrow.utcnow().shift(hours=-1)
|
||||
})
|
||||
assert msg_mock.call_args[0][0] \
|
||||
== '*Bittrex:* Buying ETH/BTC\n' \
|
||||
'at rate `0.00001099\n' \
|
||||
'(0.001000 BTC)`'
|
||||
'*Amount:* `1333.33333333`\n' \
|
||||
'*Open Rate:* `0.00001099`\n' \
|
||||
'*Current Rate:* `0.00001099`\n' \
|
||||
'*Total:* `(0.001000 BTC)`'
|
||||
|
||||
|
||||
def test_send_msg_sell_notification_no_fiat(default_conf, mocker) -> None:
|
||||
@@ -1398,10 +1457,10 @@ def test_send_msg_sell_notification_no_fiat(default_conf, mocker) -> None:
|
||||
})
|
||||
assert msg_mock.call_args[0][0] \
|
||||
== '*Binance:* Selling KEY/ETH\n' \
|
||||
'*Rate:* `0.00003201`\n' \
|
||||
'*Amount:* `1333.33333333`\n' \
|
||||
'*Open Rate:* `0.00007500`\n' \
|
||||
'*Current Rate:* `0.00003201`\n' \
|
||||
'*Close Rate:* `0.00003201`\n' \
|
||||
'*Sell Reason:* `stop_loss`\n' \
|
||||
'*Duration:* `2:35:03 (155.1 min)`\n' \
|
||||
'*Profit:* `-57.41%`'
|
||||
|
@@ -13,24 +13,34 @@ from tests.conftest import get_patched_freqtradebot, log_has
|
||||
|
||||
def get_webhook_dict() -> dict:
|
||||
return {
|
||||
"enabled": True,
|
||||
"url": "https://maker.ifttt.com/trigger/freqtrade_test/with/key/c764udvJ5jfSlswVRukZZ2/",
|
||||
"webhookbuy": {
|
||||
"value1": "Buying {pair}",
|
||||
"value2": "limit {limit:8f}",
|
||||
"value3": "{stake_amount:8f} {stake_currency}"
|
||||
},
|
||||
"webhooksell": {
|
||||
"value1": "Selling {pair}",
|
||||
"value2": "limit {limit:8f}",
|
||||
"value3": "profit: {profit_amount:8f} {stake_currency}"
|
||||
},
|
||||
"webhookstatus": {
|
||||
"value1": "Status: {status}",
|
||||
"value2": "",
|
||||
"value3": ""
|
||||
}
|
||||
}
|
||||
"enabled": True,
|
||||
"url": "https://maker.ifttt.com/trigger/freqtrade_test/with/key/c764udvJ5jfSlswVRukZZ2/",
|
||||
"webhookbuy": {
|
||||
"value1": "Buying {pair}",
|
||||
"value2": "limit {limit:8f}",
|
||||
"value3": "{stake_amount:8f} {stake_currency}"
|
||||
},
|
||||
"webhookbuycancel": {
|
||||
"value1": "Cancelling Open Buy Order for {pair}",
|
||||
"value2": "limit {limit:8f}",
|
||||
"value3": "{stake_amount:8f} {stake_currency}"
|
||||
},
|
||||
"webhooksell": {
|
||||
"value1": "Selling {pair}",
|
||||
"value2": "limit {limit:8f}",
|
||||
"value3": "profit: {profit_amount:8f} {stake_currency}"
|
||||
},
|
||||
"webhooksellcancel": {
|
||||
"value1": "Cancelling Open Sell Order for {pair}",
|
||||
"value2": "limit {limit:8f}",
|
||||
"value3": "profit: {profit_amount:8f} {stake_currency}"
|
||||
},
|
||||
"webhookstatus": {
|
||||
"value1": "Status: {status}",
|
||||
"value2": "",
|
||||
"value3": ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def test__init__(mocker, default_conf):
|
||||
@@ -44,6 +54,9 @@ def test_send_msg(default_conf, mocker):
|
||||
msg_mock = MagicMock()
|
||||
mocker.patch("freqtrade.rpc.webhook.Webhook._send_msg", msg_mock)
|
||||
webhook = Webhook(get_patched_freqtradebot(mocker, default_conf))
|
||||
# Test buy
|
||||
msg_mock = MagicMock()
|
||||
mocker.patch("freqtrade.rpc.webhook.Webhook._send_msg", msg_mock)
|
||||
msg = {
|
||||
'type': RPCMessageType.BUY_NOTIFICATION,
|
||||
'exchange': 'Bittrex',
|
||||
@@ -54,8 +67,6 @@ def test_send_msg(default_conf, mocker):
|
||||
'stake_currency': 'BTC',
|
||||
'fiat_currency': 'EUR'
|
||||
}
|
||||
msg_mock = MagicMock()
|
||||
mocker.patch("freqtrade.rpc.webhook.Webhook._send_msg", msg_mock)
|
||||
webhook.send_msg(msg=msg)
|
||||
assert msg_mock.call_count == 1
|
||||
assert (msg_mock.call_args[0][0]["value1"] ==
|
||||
@@ -64,6 +75,27 @@ def test_send_msg(default_conf, mocker):
|
||||
default_conf["webhook"]["webhookbuy"]["value2"].format(**msg))
|
||||
assert (msg_mock.call_args[0][0]["value3"] ==
|
||||
default_conf["webhook"]["webhookbuy"]["value3"].format(**msg))
|
||||
# Test buy cancel
|
||||
msg_mock = MagicMock()
|
||||
mocker.patch("freqtrade.rpc.webhook.Webhook._send_msg", msg_mock)
|
||||
msg = {
|
||||
'type': RPCMessageType.BUY_CANCEL_NOTIFICATION,
|
||||
'exchange': 'Bittrex',
|
||||
'pair': 'ETH/BTC',
|
||||
'limit': 0.005,
|
||||
'stake_amount': 0.8,
|
||||
'stake_amount_fiat': 500,
|
||||
'stake_currency': 'BTC',
|
||||
'fiat_currency': 'EUR'
|
||||
}
|
||||
webhook.send_msg(msg=msg)
|
||||
assert msg_mock.call_count == 1
|
||||
assert (msg_mock.call_args[0][0]["value1"] ==
|
||||
default_conf["webhook"]["webhookbuycancel"]["value1"].format(**msg))
|
||||
assert (msg_mock.call_args[0][0]["value2"] ==
|
||||
default_conf["webhook"]["webhookbuycancel"]["value2"].format(**msg))
|
||||
assert (msg_mock.call_args[0][0]["value3"] ==
|
||||
default_conf["webhook"]["webhookbuycancel"]["value3"].format(**msg))
|
||||
# Test sell
|
||||
msg_mock = MagicMock()
|
||||
mocker.patch("freqtrade.rpc.webhook.Webhook._send_msg", msg_mock)
|
||||
@@ -90,7 +122,32 @@ def test_send_msg(default_conf, mocker):
|
||||
default_conf["webhook"]["webhooksell"]["value2"].format(**msg))
|
||||
assert (msg_mock.call_args[0][0]["value3"] ==
|
||||
default_conf["webhook"]["webhooksell"]["value3"].format(**msg))
|
||||
|
||||
# Test sell cancel
|
||||
msg_mock = MagicMock()
|
||||
mocker.patch("freqtrade.rpc.webhook.Webhook._send_msg", msg_mock)
|
||||
msg = {
|
||||
'type': RPCMessageType.SELL_CANCEL_NOTIFICATION,
|
||||
'exchange': 'Bittrex',
|
||||
'pair': 'ETH/BTC',
|
||||
'gain': "profit",
|
||||
'limit': 0.005,
|
||||
'amount': 0.8,
|
||||
'order_type': 'limit',
|
||||
'open_rate': 0.004,
|
||||
'current_rate': 0.005,
|
||||
'profit_amount': 0.001,
|
||||
'profit_percent': 0.20,
|
||||
'stake_currency': 'BTC',
|
||||
'sell_reason': SellType.STOP_LOSS.value
|
||||
}
|
||||
webhook.send_msg(msg=msg)
|
||||
assert msg_mock.call_count == 1
|
||||
assert (msg_mock.call_args[0][0]["value1"] ==
|
||||
default_conf["webhook"]["webhooksellcancel"]["value1"].format(**msg))
|
||||
assert (msg_mock.call_args[0][0]["value2"] ==
|
||||
default_conf["webhook"]["webhooksellcancel"]["value2"].format(**msg))
|
||||
assert (msg_mock.call_args[0][0]["value3"] ==
|
||||
default_conf["webhook"]["webhooksellcancel"]["value3"].format(**msg))
|
||||
for msgtype in [RPCMessageType.STATUS_NOTIFICATION,
|
||||
RPCMessageType.WARNING_NOTIFICATION,
|
||||
RPCMessageType.CUSTOM_NOTIFICATION]:
|
||||
|
9
tests/strategy/failing_strategy.py
Normal file
9
tests/strategy/failing_strategy.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# The strategy which fails to load due to non-existent dependency
|
||||
|
||||
import nonexiting_module # noqa
|
||||
|
||||
from freqtrade.strategy.interface import IStrategy
|
||||
|
||||
|
||||
class TestStrategyLegacy(IStrategy):
|
||||
pass
|
@@ -9,8 +9,9 @@ from pandas import DataFrame
|
||||
from freqtrade.configuration import TimeRange
|
||||
from freqtrade.data.history import load_data
|
||||
from freqtrade.persistence import Trade
|
||||
from tests.conftest import get_patched_exchange, log_has
|
||||
from freqtrade.resolvers import StrategyResolver
|
||||
from freqtrade.strategy.default_strategy import DefaultStrategy
|
||||
from tests.conftest import get_patched_exchange, log_has
|
||||
|
||||
# Avoid to reinit the same object again and again
|
||||
_STRATEGY = DefaultStrategy(config={})
|
||||
@@ -103,7 +104,8 @@ def test_get_signal_handles_exceptions(mocker, default_conf):
|
||||
|
||||
|
||||
def test_tickerdata_to_dataframe(default_conf, testdatadir) -> None:
|
||||
strategy = DefaultStrategy(default_conf)
|
||||
default_conf.update({'strategy': 'DefaultStrategy'})
|
||||
strategy = StrategyResolver.load_strategy(default_conf)
|
||||
|
||||
timerange = TimeRange.parse_timerange('1510694220-1510700340')
|
||||
tickerlist = load_data(testdatadir, '1m', ['UNITTEST/BTC'], timerange=timerange,
|
||||
@@ -118,7 +120,8 @@ def test_min_roi_reached(default_conf, fee) -> None:
|
||||
min_roi_list = [{20: 0.05, 55: 0.01, 0: 0.1},
|
||||
{0: 0.1, 20: 0.05, 55: 0.01}]
|
||||
for roi in min_roi_list:
|
||||
strategy = DefaultStrategy(default_conf)
|
||||
default_conf.update({'strategy': 'DefaultStrategy'})
|
||||
strategy = StrategyResolver.load_strategy(default_conf)
|
||||
strategy.minimal_roi = roi
|
||||
trade = Trade(
|
||||
pair='ETH/BTC',
|
||||
@@ -156,7 +159,8 @@ def test_min_roi_reached2(default_conf, fee) -> None:
|
||||
},
|
||||
]
|
||||
for roi in min_roi_list:
|
||||
strategy = DefaultStrategy(default_conf)
|
||||
default_conf.update({'strategy': 'DefaultStrategy'})
|
||||
strategy = StrategyResolver.load_strategy(default_conf)
|
||||
strategy.minimal_roi = roi
|
||||
trade = Trade(
|
||||
pair='ETH/BTC',
|
||||
@@ -190,7 +194,8 @@ def test_min_roi_reached3(default_conf, fee) -> None:
|
||||
30: 0.05,
|
||||
55: 0.30,
|
||||
}
|
||||
strategy = DefaultStrategy(default_conf)
|
||||
default_conf.update({'strategy': 'DefaultStrategy'})
|
||||
strategy = StrategyResolver.load_strategy(default_conf)
|
||||
strategy.minimal_roi = min_roi
|
||||
trade = Trade(
|
||||
pair='ETH/BTC',
|
||||
@@ -290,7 +295,8 @@ def test__analyze_ticker_internal_skip_analyze(ticker_history, mocker, caplog) -
|
||||
|
||||
|
||||
def test_is_pair_locked(default_conf):
|
||||
strategy = DefaultStrategy(default_conf)
|
||||
default_conf.update({'strategy': 'DefaultStrategy'})
|
||||
strategy = StrategyResolver.load_strategy(default_conf)
|
||||
# dict should be empty
|
||||
assert not strategy._pair_locked_until
|
||||
|
||||
|
@@ -30,14 +30,25 @@ def test_search_strategy():
|
||||
assert s is None
|
||||
|
||||
|
||||
def test_search_all_strategies():
|
||||
def test_search_all_strategies_no_failed():
|
||||
directory = Path(__file__).parent
|
||||
strategies = StrategyResolver.search_all_objects(directory)
|
||||
strategies = StrategyResolver.search_all_objects(directory, enum_failed=False)
|
||||
assert isinstance(strategies, list)
|
||||
assert len(strategies) == 3
|
||||
assert isinstance(strategies[0], dict)
|
||||
|
||||
|
||||
def test_search_all_strategies_with_failed():
|
||||
directory = Path(__file__).parent
|
||||
strategies = StrategyResolver.search_all_objects(directory, enum_failed=True)
|
||||
assert isinstance(strategies, list)
|
||||
assert len(strategies) == 4
|
||||
# with enum_failed=True search_all_objects() shall find 3 good strategies
|
||||
# and 1 which fails to load
|
||||
assert len([x for x in strategies if x['class'] is not None]) == 3
|
||||
assert len([x for x in strategies if x['class'] is None]) == 1
|
||||
|
||||
|
||||
def test_load_strategy(default_conf, result):
|
||||
default_conf.update({'strategy': 'SampleStrategy',
|
||||
'strategy_path': str(Path(__file__).parents[2] / 'freqtrade/templates')
|
||||
|
@@ -18,7 +18,8 @@ def test_parse_args_none() -> None:
|
||||
assert isinstance(arguments.parser, argparse.ArgumentParser)
|
||||
|
||||
|
||||
def test_parse_args_defaults() -> None:
|
||||
def test_parse_args_defaults(mocker) -> None:
|
||||
mocker.patch.object(Path, "is_file", MagicMock(side_effect=[False, True]))
|
||||
args = Arguments(['trade']).get_parsed_arg()
|
||||
assert args["config"] == ['config.json']
|
||||
assert args["strategy_path"] is None
|
||||
@@ -26,6 +27,26 @@ def test_parse_args_defaults() -> None:
|
||||
assert args["verbosity"] == 0
|
||||
|
||||
|
||||
def test_parse_args_default_userdatadir(mocker) -> None:
|
||||
mocker.patch.object(Path, "is_file", MagicMock(return_value=True))
|
||||
args = Arguments(['trade']).get_parsed_arg()
|
||||
# configuration defaults to user_data if that is available.
|
||||
assert args["config"] == [str(Path('user_data/config.json'))]
|
||||
assert args["strategy_path"] is None
|
||||
assert args["datadir"] is None
|
||||
assert args["verbosity"] == 0
|
||||
|
||||
|
||||
def test_parse_args_userdatadir(mocker) -> None:
|
||||
mocker.patch.object(Path, "is_file", MagicMock(return_value=True))
|
||||
args = Arguments(['trade', '--user-data-dir', 'user_data']).get_parsed_arg()
|
||||
# configuration defaults to user_data if that is available.
|
||||
assert args["config"] == [str(Path('user_data/config.json'))]
|
||||
assert args["strategy_path"] is None
|
||||
assert args["datadir"] is None
|
||||
assert args["verbosity"] == 0
|
||||
|
||||
|
||||
def test_parse_args_config() -> None:
|
||||
args = Arguments(['trade', '-c', '/dev/null']).get_parsed_arg()
|
||||
assert args["config"] == ['/dev/null']
|
||||
@@ -208,7 +229,7 @@ def test_config_notrequired(mocker) -> None:
|
||||
assert pargs["config"] is None
|
||||
|
||||
# When file exists:
|
||||
mocker.patch.object(Path, "is_file", MagicMock(return_value=True))
|
||||
mocker.patch.object(Path, "is_file", MagicMock(side_effect=[False, True]))
|
||||
args = [
|
||||
'download-data',
|
||||
]
|
||||
|
@@ -300,7 +300,7 @@ def test_edge_overrides_stoploss(limit_buy_order, fee, caplog, mocker, edge_conf
|
||||
|
||||
# stoploss shoud be hit
|
||||
assert freqtrade.handle_trade(trade) is True
|
||||
assert log_has('executed sell, reason: SellType.STOP_LOSS', caplog)
|
||||
assert log_has('Executing Sell for NEO/BTC. Reason: SellType.STOP_LOSS', caplog)
|
||||
assert trade.sell_reason == SellType.STOP_LOSS.value
|
||||
|
||||
|
||||
@@ -921,7 +921,7 @@ def test_get_buy_rate(mocker, default_conf, ask, last, last_ab, expected) -> Non
|
||||
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker',
|
||||
MagicMock(return_value={'ask': ask, 'last': last}))
|
||||
|
||||
assert freqtrade.get_buy_rate('ETH/BTC') == expected
|
||||
assert freqtrade.get_buy_rate('ETH/BTC', True) == expected
|
||||
|
||||
|
||||
def test_execute_buy(mocker, default_conf, fee, limit_buy_order) -> None:
|
||||
@@ -1964,7 +1964,7 @@ def test_check_handle_cancelled_buy(default_conf, ticker, limit_buy_order_old, o
|
||||
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
|
||||
nb_trades = len(trades)
|
||||
assert nb_trades == 0
|
||||
assert log_has_re("Buy order canceled on Exchange for Trade.*", caplog)
|
||||
assert log_has_re("Buy order cancelled on exchange for Trade.*", caplog)
|
||||
|
||||
|
||||
def test_check_handle_timedout_buy_exception(default_conf, ticker, limit_buy_order_old, open_trade,
|
||||
@@ -2045,7 +2045,7 @@ def test_check_handle_cancelled_sell(default_conf, ticker, limit_sell_order_old,
|
||||
assert cancel_order_mock.call_count == 0
|
||||
assert rpc_mock.call_count == 1
|
||||
assert open_trade.is_open is True
|
||||
assert log_has_re("Sell order canceled on exchange for Trade.*", caplog)
|
||||
assert log_has_re("Sell order cancelled on exchange for Trade.*", caplog)
|
||||
|
||||
|
||||
def test_check_handle_timedout_partial(default_conf, ticker, limit_buy_order_old_partial,
|
||||
@@ -2067,7 +2067,7 @@ def test_check_handle_timedout_partial(default_conf, ticker, limit_buy_order_old
|
||||
# note this is for a partially-complete buy order
|
||||
freqtrade.check_handle_timedout()
|
||||
assert cancel_order_mock.call_count == 1
|
||||
assert rpc_mock.call_count == 1
|
||||
assert rpc_mock.call_count == 2
|
||||
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
|
||||
assert len(trades) == 1
|
||||
assert trades[0].amount == 23.0
|
||||
@@ -2101,7 +2101,7 @@ def test_check_handle_timedout_partial_fee(default_conf, ticker, open_trade, cap
|
||||
assert log_has_re(r"Applying fee on amount for Trade.* Order", caplog)
|
||||
|
||||
assert cancel_order_mock.call_count == 1
|
||||
assert rpc_mock.call_count == 1
|
||||
assert rpc_mock.call_count == 2
|
||||
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
|
||||
assert len(trades) == 1
|
||||
# Verify that tradehas been updated
|
||||
@@ -2140,7 +2140,7 @@ def test_check_handle_timedout_partial_except(default_conf, ticker, open_trade,
|
||||
assert log_has_re(r"Could not update trade amount: .*", caplog)
|
||||
|
||||
assert cancel_order_mock.call_count == 1
|
||||
assert rpc_mock.call_count == 1
|
||||
assert rpc_mock.call_count == 2
|
||||
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
|
||||
assert len(trades) == 1
|
||||
# Verify that tradehas been updated
|
||||
@@ -3524,7 +3524,7 @@ def test_order_book_bid_strategy1(mocker, default_conf, order_book_l2) -> None:
|
||||
default_conf['telegram']['enabled'] = False
|
||||
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
assert freqtrade.get_buy_rate('ETH/BTC') == 0.043935
|
||||
assert freqtrade.get_buy_rate('ETH/BTC', True) == 0.043935
|
||||
assert ticker_mock.call_count == 0
|
||||
|
||||
|
||||
@@ -3549,7 +3549,7 @@ def test_order_book_bid_strategy2(mocker, default_conf, order_book_l2) -> None:
|
||||
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
# orderbook shall be used even if tickers would be lower.
|
||||
assert freqtrade.get_buy_rate('ETH/BTC') != 0.042
|
||||
assert freqtrade.get_buy_rate('ETH/BTC', True) != 0.042
|
||||
assert ticker_mock.call_count == 0
|
||||
|
||||
|
||||
|
@@ -5,8 +5,9 @@ from unittest.mock import MagicMock, PropertyMock
|
||||
|
||||
import pytest
|
||||
|
||||
from pathlib import Path
|
||||
from freqtrade.commands import Arguments
|
||||
from freqtrade.exceptions import OperationalException, FreqtradeException
|
||||
from freqtrade.exceptions import FreqtradeException, OperationalException
|
||||
from freqtrade.freqtradebot import FreqtradeBot
|
||||
from freqtrade.main import main
|
||||
from freqtrade.state import State
|
||||
@@ -26,6 +27,7 @@ def test_parse_args_backtesting(mocker) -> None:
|
||||
Test that main() can start backtesting and also ensure we can pass some specific arguments
|
||||
further argument parsing is done in test_arguments.py
|
||||
"""
|
||||
mocker.patch.object(Path, "is_file", MagicMock(side_effect=[False, True]))
|
||||
backtesting_mock = mocker.patch('freqtrade.commands.start_backtesting')
|
||||
backtesting_mock.__name__ = PropertyMock("start_backtesting")
|
||||
# it's sys.exit(0) at the end of backtesting
|
||||
@@ -42,6 +44,7 @@ def test_parse_args_backtesting(mocker) -> None:
|
||||
|
||||
|
||||
def test_main_start_hyperopt(mocker) -> None:
|
||||
mocker.patch.object(Path, "is_file", MagicMock(side_effect=[False, True]))
|
||||
hyperopt_mock = mocker.patch('freqtrade.commands.start_hyperopt', MagicMock())
|
||||
hyperopt_mock.__name__ = PropertyMock("start_hyperopt")
|
||||
# it's sys.exit(0) at the end of hyperopt
|
||||
|
@@ -19,7 +19,7 @@ from freqtrade.plot.plotting import (add_indicators, add_profit,
|
||||
generate_profit_graph, init_plotscript,
|
||||
load_and_plot_trades, plot_profit,
|
||||
plot_trades, store_plot_file)
|
||||
from freqtrade.strategy.default_strategy import DefaultStrategy
|
||||
from freqtrade.resolvers import StrategyResolver
|
||||
from tests.conftest import get_args, log_has, log_has_re
|
||||
|
||||
|
||||
@@ -70,9 +70,11 @@ def test_add_indicators(default_conf, testdatadir, caplog):
|
||||
indicators1 = {"ema10": {}}
|
||||
indicators2 = {"macd": {"color": "red"}}
|
||||
|
||||
default_conf.update({'strategy': 'DefaultStrategy'})
|
||||
strategy = StrategyResolver.load_strategy(default_conf)
|
||||
|
||||
# Generate buy/sell signals and indicators
|
||||
strat = DefaultStrategy(default_conf)
|
||||
data = strat.analyze_ticker(data, {'pair': pair})
|
||||
data = strategy.analyze_ticker(data, {'pair': pair})
|
||||
fig = generate_empty_figure()
|
||||
|
||||
# Row 1
|
||||
@@ -181,9 +183,11 @@ def test_generate_candlestick_graph_no_trades(default_conf, mocker, testdatadir)
|
||||
data = history.load_pair_history(pair=pair, timeframe='1m',
|
||||
datadir=testdatadir, timerange=timerange)
|
||||
|
||||
default_conf.update({'strategy': 'DefaultStrategy'})
|
||||
strategy = StrategyResolver.load_strategy(default_conf)
|
||||
|
||||
# Generate buy/sell signals and indicators
|
||||
strat = DefaultStrategy(default_conf)
|
||||
data = strat.analyze_ticker(data, {'pair': pair})
|
||||
data = strategy.analyze_ticker(data, {'pair': pair})
|
||||
|
||||
indicators1 = []
|
||||
indicators2 = []
|
||||
|
Reference in New Issue
Block a user