merged with feat/short

This commit is contained in:
Sam Germain
2021-09-14 18:32:08 -06:00
57 changed files with 343 additions and 1805 deletions

View File

@@ -10,10 +10,10 @@ import pytest
from freqtrade.commands import (start_convert_data, start_create_userdir, start_download_data,
start_hyperopt_list, start_hyperopt_show, start_install_ui,
start_list_data, start_list_exchanges, start_list_hyperopts,
start_list_markets, start_list_strategies, start_list_timeframes,
start_new_hyperopt, start_new_strategy, start_show_trades,
start_test_pairlist, start_trading, start_webserver)
start_list_data, start_list_exchanges, start_list_markets,
start_list_strategies, start_list_timeframes, start_new_strategy,
start_show_trades, start_test_pairlist, start_trading,
start_webserver)
from freqtrade.commands.deploy_commands import (clean_ui_subdir, download_and_install_ui,
get_ui_download_url, read_ui_version)
from freqtrade.configuration import setup_utils_configuration
@@ -32,8 +32,6 @@ def test_setup_utils_configuration():
config = setup_utils_configuration(get_args(args), RunMode.OTHER)
assert "exchange" in config
assert config['dry_run'] is True
assert config['exchange']['key'] == ''
assert config['exchange']['secret'] == ''
def test_start_trading_fail(mocker, caplog):
@@ -519,37 +517,6 @@ def test_start_new_strategy_no_arg(mocker, caplog):
start_new_strategy(get_args(args))
def test_start_new_hyperopt(mocker, caplog):
wt_mock = mocker.patch.object(Path, "write_text", MagicMock())
mocker.patch.object(Path, "exists", MagicMock(return_value=False))
args = [
"new-hyperopt",
"--hyperopt",
"CoolNewhyperopt"
]
start_new_hyperopt(get_args(args))
assert wt_mock.call_count == 1
assert "CoolNewhyperopt" in wt_mock.call_args_list[0][0][0]
assert log_has_re("Writing hyperopt to .*", caplog)
mocker.patch('freqtrade.commands.deploy_commands.setup_utils_configuration')
mocker.patch.object(Path, "exists", MagicMock(return_value=True))
with pytest.raises(OperationalException,
match=r".* already exists. Please choose another Hyperopt Name\."):
start_new_hyperopt(get_args(args))
def test_start_new_hyperopt_no_arg(mocker):
args = [
"new-hyperopt",
]
with pytest.raises(OperationalException,
match="`new-hyperopt` requires --hyperopt to be set."):
start_new_hyperopt(get_args(args))
def test_start_install_ui(mocker):
clean_mock = mocker.patch('freqtrade.commands.deploy_commands.clean_ui_subdir')
get_url_mock = mocker.patch('freqtrade.commands.deploy_commands.get_ui_download_url',
@@ -824,37 +791,20 @@ def test_start_list_strategies(mocker, caplog, capsys):
assert "legacy_strategy_v1.py" in captured.out
assert "StrategyTestV2" in captured.out
def test_start_list_hyperopts(mocker, caplog, capsys):
# Test color output
args = [
"list-hyperopts",
"--hyperopt-path",
str(Path(__file__).parent.parent / "optimize" / "hyperopts"),
"-1"
"list-strategies",
"--strategy-path",
str(Path(__file__).parent.parent / "strategy" / "strats"),
]
pargs = get_args(args)
# pargs['config'] = None
start_list_hyperopts(pargs)
start_list_strategies(pargs)
captured = capsys.readouterr()
assert "TestHyperoptLegacy" not in captured.out
assert "legacy_hyperopt.py" not in captured.out
assert "HyperoptTestSepFile" in captured.out
assert "test_hyperopt.py" not in captured.out
# Test regular output
args = [
"list-hyperopts",
"--hyperopt-path",
str(Path(__file__).parent.parent / "optimize" / "hyperopts"),
]
pargs = get_args(args)
# pargs['config'] = None
start_list_hyperopts(pargs)
captured = capsys.readouterr()
assert "TestHyperoptLegacy" not in captured.out
assert "legacy_hyperopt.py" not in captured.out
assert "HyperoptTestSepFile" in captured.out
assert "TestStrategyLegacyV1" in captured.out
assert "legacy_strategy_v1.py" in captured.out
assert "StrategyTestV2" in captured.out
assert "LOAD FAILED" in captured.out
def test_start_test_pairlist(mocker, caplog, tickers, default_conf, capsys):

View File

@@ -1,3 +1,4 @@
from datetime import datetime, timezone
from random import randint
from unittest.mock import MagicMock, PropertyMock
@@ -6,7 +7,7 @@ import pytest
from freqtrade.enums import TradingMode
from freqtrade.exceptions import DependencyException, InvalidOrderException, OperationalException
from tests.conftest import get_patched_exchange
from tests.conftest import get_mock_coro, get_patched_exchange, log_has_re
from tests.exchange.test_exchange import ccxt_exceptionhandlers
@@ -255,3 +256,35 @@ def test__set_leverage_binance(mocker, default_conf):
leverage=5.0,
trading_mode=TradingMode.FUTURES
)
@pytest.mark.asyncio
async def test__async_get_historic_ohlcv_binance(default_conf, mocker, caplog):
ohlcv = [
[
int((datetime.now(timezone.utc).timestamp() - 1000) * 1000),
1, # open
2, # high
3, # low
4, # close
5, # volume (in quote currency)
]
]
exchange = get_patched_exchange(mocker, default_conf, id='binance')
# Monkey-patch async function
exchange._api_async.fetch_ohlcv = get_mock_coro(ohlcv)
pair = 'ETH/BTC'
res = await exchange._async_get_historic_ohlcv(pair, "5m",
1500000000000, is_new_pair=False)
# Call with very old timestamp - causes tons of requests
assert exchange._api_async.fetch_ohlcv.call_count > 400
# assert res == ohlcv
exchange._api_async.fetch_ohlcv.reset_mock()
res = await exchange._async_get_historic_ohlcv(pair, "5m", 1500000000000, is_new_pair=True)
# Called twice - one "init" call - and one to get the actual data.
assert exchange._api_async.fetch_ohlcv.call_count == 2
assert res == ohlcv
assert log_has_re(r"Candle-data for ETH/BTC available starting with .*", caplog)

View File

@@ -54,6 +54,8 @@ EXCHANGES = {
def exchange_conf():
config = get_default_conf((Path(__file__).parent / "testdata").resolve())
config['exchange']['pair_whitelist'] = []
config['exchange']['key'] = ''
config['exchange']['secret'] = ''
config['dry_run'] = False
return config

View File

@@ -1,5 +1,6 @@
import copy
import logging
from copy import deepcopy
from datetime import datetime, timedelta, timezone
from math import isclose
from random import randint
@@ -15,7 +16,7 @@ from freqtrade.exceptions import (DDosProtection, DependencyException, InvalidOr
OperationalException, PricingError, TemporaryError)
from freqtrade.exchange import Binance, Bittrex, Exchange, Kraken
from freqtrade.exchange.common import (API_FETCH_ORDER_RETRY_COUNT, API_RETRY_COUNT,
calculate_backoff)
calculate_backoff, remove_credentials)
from freqtrade.exchange.exchange import (market_is_active, timeframe_to_minutes, timeframe_to_msecs,
timeframe_to_next_date, timeframe_to_prev_date,
timeframe_to_seconds)
@@ -79,6 +80,22 @@ def test_init(default_conf, mocker, caplog):
assert log_has('Instance is running with dry_run enabled', caplog)
def test_remove_credentials(default_conf, caplog) -> None:
conf = deepcopy(default_conf)
conf['dry_run'] = False
remove_credentials(conf)
assert conf['exchange']['key'] != ''
assert conf['exchange']['secret'] != ''
conf['dry_run'] = True
remove_credentials(conf)
assert conf['exchange']['key'] == ''
assert conf['exchange']['secret'] == ''
assert conf['exchange']['password'] == ''
assert conf['exchange']['uid'] == ''
def test_init_ccxt_kwargs(default_conf, mocker, caplog):
mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={}))
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
@@ -188,7 +205,7 @@ def test_exchange_resolver(default_conf, mocker, caplog):
def test_validate_order_time_in_force(default_conf, mocker, caplog):
caplog.set_level(logging.INFO)
# explicitly test bittrex, exchanges implementing other policies need seperate tests
# explicitly test bittrex, exchanges implementing other policies need separate tests
ex = get_patched_exchange(mocker, default_conf, id="bittrex")
tif = {
"buy": "gtc",
@@ -1585,6 +1602,32 @@ def test_get_historic_ohlcv_as_df(default_conf, mocker, exchange_name):
assert 'high' in ret.columns
@pytest.mark.asyncio
@pytest.mark.parametrize("exchange_name", EXCHANGES)
async def test__async_get_historic_ohlcv(default_conf, mocker, caplog, exchange_name):
ohlcv = [
[
int((datetime.now(timezone.utc).timestamp() - 1000) * 1000),
1, # open
2, # high
3, # low
4, # close
5, # volume (in quote currency)
]
]
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
# Monkey-patch async function
exchange._api_async.fetch_ohlcv = get_mock_coro(ohlcv)
pair = 'ETH/USDT'
res = await exchange._async_get_historic_ohlcv(pair, "5m",
1500000000000, is_new_pair=False)
# Call with very old timestamp - causes tons of requests
assert exchange._api_async.fetch_ohlcv.call_count > 200
assert res[0] == ohlcv[0]
assert log_has_re(r'Downloaded data for .* with length .*\.', caplog)
def test_refresh_latest_ohlcv(mocker, default_conf, caplog) -> None:
ohlcv = [
[
@@ -2472,7 +2515,7 @@ def test_fetch_order(default_conf, mocker, exchange_name, caplog):
@pytest.mark.parametrize("exchange_name", EXCHANGES)
def test_fetch_stoploss_order(default_conf, mocker, exchange_name):
# Don't test FTX here - that needs a seperate test
# Don't test FTX here - that needs a separate test
if exchange_name == 'ftx':
return
default_conf['dry_run'] = True

View File

@@ -16,7 +16,7 @@ def hyperopt_conf(default_conf):
hyperconf.update({
'datadir': Path(default_conf['datadir']),
'runmode': RunMode.HYPEROPT,
'hyperopt': 'HyperoptTestSepFile',
'strategy': 'HyperoptableStrategy',
'hyperopt_loss': 'ShortTradeDurHyperOptLoss',
'hyperopt_path': str(Path(__file__).parent / 'hyperopts'),
'epochs': 1,

View File

@@ -1,207 +0,0 @@
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
from functools import reduce
from typing import Any, Callable, Dict, List
import talib.abstract as ta
from pandas import DataFrame
from skopt.space import Categorical, Dimension, Integer
import freqtrade.vendor.qtpylib.indicators as qtpylib
from freqtrade.optimize.hyperopt_interface import IHyperOpt
class HyperoptTestSepFile(IHyperOpt):
"""
Default hyperopt provided by the Freqtrade bot.
You can override it with your own Hyperopt
"""
@staticmethod
def populate_indicators(dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Add several indicators needed for buy and sell strategies defined below.
"""
# ADX
dataframe['adx'] = ta.ADX(dataframe)
# MACD
macd = ta.MACD(dataframe)
dataframe['macd'] = macd['macd']
dataframe['macdsignal'] = macd['macdsignal']
# MFI
dataframe['mfi'] = ta.MFI(dataframe)
# RSI
dataframe['rsi'] = ta.RSI(dataframe)
# Stochastic Fast
stoch_fast = ta.STOCHF(dataframe)
dataframe['fastd'] = stoch_fast['fastd']
# Minus-DI
dataframe['minus_di'] = ta.MINUS_DI(dataframe)
# Bollinger bands
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
dataframe['bb_lowerband'] = bollinger['lower']
dataframe['bb_upperband'] = bollinger['upper']
# SAR
dataframe['sar'] = ta.SAR(dataframe)
return dataframe
@staticmethod
def buy_strategy_generator(params: Dict[str, Any]) -> Callable:
"""
Define the buy strategy parameters to be used by Hyperopt.
"""
def populate_buy_trend(dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Buy strategy Hyperopt will build and use.
"""
conditions = []
# GUARDS AND TRENDS
if 'mfi-enabled' in params and params['mfi-enabled']:
conditions.append(dataframe['mfi'] < params['mfi-value'])
if 'fastd-enabled' in params and params['fastd-enabled']:
conditions.append(dataframe['fastd'] < params['fastd-value'])
if 'adx-enabled' in params and params['adx-enabled']:
conditions.append(dataframe['adx'] > params['adx-value'])
if 'rsi-enabled' in params and params['rsi-enabled']:
conditions.append(dataframe['rsi'] < params['rsi-value'])
# TRIGGERS
if 'trigger' in params:
if params['trigger'] == 'boll':
conditions.append(dataframe['close'] < dataframe['bb_lowerband'])
if params['trigger'] == 'macd_cross_signal':
conditions.append(qtpylib.crossed_above(
dataframe['macd'],
dataframe['macdsignal']
))
if params['trigger'] == 'sar_reversal':
conditions.append(qtpylib.crossed_above(
dataframe['close'],
dataframe['sar']
))
if conditions:
dataframe.loc[
reduce(lambda x, y: x & y, conditions),
'buy'] = 1
return dataframe
return populate_buy_trend
@staticmethod
def indicator_space() -> List[Dimension]:
"""
Define your Hyperopt space for searching buy strategy parameters.
"""
return [
Integer(10, 25, name='mfi-value'),
Integer(15, 45, name='fastd-value'),
Integer(20, 50, name='adx-value'),
Integer(20, 40, name='rsi-value'),
Categorical([True, False], name='mfi-enabled'),
Categorical([True, False], name='fastd-enabled'),
Categorical([True, False], name='adx-enabled'),
Categorical([True, False], name='rsi-enabled'),
Categorical(['boll', 'macd_cross_signal', 'sar_reversal'], name='trigger')
]
@staticmethod
def sell_strategy_generator(params: Dict[str, Any]) -> Callable:
"""
Define the sell strategy parameters to be used by Hyperopt.
"""
def populate_sell_trend(dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Sell strategy Hyperopt will build and use.
"""
conditions = []
# GUARDS AND TRENDS
if 'sell-mfi-enabled' in params and params['sell-mfi-enabled']:
conditions.append(dataframe['mfi'] > params['sell-mfi-value'])
if 'sell-fastd-enabled' in params and params['sell-fastd-enabled']:
conditions.append(dataframe['fastd'] > params['sell-fastd-value'])
if 'sell-adx-enabled' in params and params['sell-adx-enabled']:
conditions.append(dataframe['adx'] < params['sell-adx-value'])
if 'sell-rsi-enabled' in params and params['sell-rsi-enabled']:
conditions.append(dataframe['rsi'] > params['sell-rsi-value'])
# TRIGGERS
if 'sell-trigger' in params:
if params['sell-trigger'] == 'sell-boll':
conditions.append(dataframe['close'] > dataframe['bb_upperband'])
if params['sell-trigger'] == 'sell-macd_cross_signal':
conditions.append(qtpylib.crossed_above(
dataframe['macdsignal'],
dataframe['macd']
))
if params['sell-trigger'] == 'sell-sar_reversal':
conditions.append(qtpylib.crossed_above(
dataframe['sar'],
dataframe['close']
))
if conditions:
dataframe.loc[
reduce(lambda x, y: x & y, conditions),
'sell'] = 1
return dataframe
return populate_sell_trend
@staticmethod
def sell_indicator_space() -> List[Dimension]:
"""
Define your Hyperopt space for searching sell strategy parameters.
"""
return [
Integer(75, 100, name='sell-mfi-value'),
Integer(50, 100, name='sell-fastd-value'),
Integer(50, 100, name='sell-adx-value'),
Integer(60, 100, name='sell-rsi-value'),
Categorical([True, False], name='sell-mfi-enabled'),
Categorical([True, False], name='sell-fastd-enabled'),
Categorical([True, False], name='sell-adx-enabled'),
Categorical([True, False], name='sell-rsi-enabled'),
Categorical(['sell-boll',
'sell-macd_cross_signal',
'sell-sar_reversal'],
name='sell-trigger')
]
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Based on TA indicators. Should be a copy of same method from strategy.
Must align to populate_indicators in this file.
Only used when --spaces does not include buy space.
"""
dataframe.loc[
(
(dataframe['close'] < dataframe['bb_lowerband']) &
(dataframe['mfi'] < 16) &
(dataframe['adx'] > 25) &
(dataframe['rsi'] < 21)
),
'buy'] = 1
return dataframe
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Based on TA indicators. Should be a copy of same method from strategy.
Must align to populate_indicators in this file.
Only used when --spaces does not include sell space.
"""
dataframe.loc[
(
(qtpylib.crossed_above(
dataframe['macdsignal'], dataframe['macd']
)) &
(dataframe['fastd'] > 54)
),
'sell'] = 1
return dataframe

View File

@@ -17,13 +17,10 @@ from freqtrade.optimize.hyperopt_auto import HyperOptAuto
from freqtrade.optimize.hyperopt_tools import HyperoptTools
from freqtrade.optimize.optimize_reports import generate_strategy_stats
from freqtrade.optimize.space import SKDecimal
from freqtrade.resolvers.hyperopt_resolver import HyperOptResolver
from freqtrade.strategy.hyper import IntParameter
from tests.conftest import (get_args, log_has, log_has_re, patch_exchange,
patched_configuration_load_config_file)
from .hyperopts.hyperopt_test_sep_file import HyperoptTestSepFile
# TODO-lev: This file
@@ -34,7 +31,7 @@ def test_setup_hyperopt_configuration_without_arguments(mocker, default_conf, ca
args = [
'hyperopt',
'--config', 'config.json',
'--hyperopt', 'HyperoptTestSepFile',
'--strategy', 'HyperoptableStrategy',
]
config = setup_optimize_configuration(get_args(args), RunMode.HYPEROPT)
@@ -66,7 +63,7 @@ def test_setup_hyperopt_configuration_with_arguments(mocker, default_conf, caplo
args = [
'hyperopt',
'--config', 'config.json',
'--hyperopt', 'HyperoptTestSepFile',
'--strategy', 'HyperoptableStrategy',
'--datadir', '/foo/bar',
'--timeframe', '1m',
'--timerange', ':100',
@@ -118,7 +115,7 @@ def test_setup_hyperopt_configuration_stake_amount(mocker, default_conf) -> None
args = [
'hyperopt',
'--config', 'config.json',
'--hyperopt', 'HyperoptTestSepFile',
'--strategy', 'HyperoptableStrategy',
'--stake-amount', '1',
'--starting-balance', '2'
]
@@ -136,47 +133,6 @@ def test_setup_hyperopt_configuration_stake_amount(mocker, default_conf) -> None
setup_optimize_configuration(get_args(args), RunMode.HYPEROPT)
def test_hyperoptresolver(mocker, default_conf, caplog) -> None:
patched_configuration_load_config_file(mocker, default_conf)
hyperopt = HyperoptTestSepFile
delattr(hyperopt, 'populate_indicators')
delattr(hyperopt, 'populate_buy_trend')
delattr(hyperopt, 'populate_sell_trend')
mocker.patch(
'freqtrade.resolvers.hyperopt_resolver.HyperOptResolver.load_object',
MagicMock(return_value=hyperopt(default_conf))
)
default_conf.update({'hyperopt': 'HyperoptTestSepFile'})
x = HyperOptResolver.load_hyperopt(default_conf)
assert not hasattr(x, 'populate_indicators')
assert not hasattr(x, 'populate_buy_trend')
assert not hasattr(x, 'populate_sell_trend')
assert log_has("Hyperopt class does not provide populate_indicators() method. "
"Using populate_indicators from the strategy.", caplog)
assert log_has("Hyperopt class does not provide populate_sell_trend() method. "
"Using populate_sell_trend from the strategy.", caplog)
assert log_has("Hyperopt class does not provide populate_buy_trend() method. "
"Using populate_buy_trend from the strategy.", caplog)
assert hasattr(x, "ticker_interval") # DEPRECATED
assert hasattr(x, "timeframe")
def test_hyperoptresolver_wrongname(default_conf) -> None:
default_conf.update({'hyperopt': "NonExistingHyperoptClass"})
with pytest.raises(OperationalException, match=r'Impossible to load Hyperopt.*'):
HyperOptResolver.load_hyperopt(default_conf)
def test_hyperoptresolver_noname(default_conf):
default_conf['hyperopt'] = ''
with pytest.raises(OperationalException,
match="No Hyperopt set. Please use `--hyperopt` to specify "
"the Hyperopt class to use."):
HyperOptResolver.load_hyperopt(default_conf)
def test_start_not_installed(mocker, default_conf, import_fails) -> None:
start_mock = MagicMock()
patched_configuration_load_config_file(mocker, default_conf)
@@ -187,9 +143,7 @@ def test_start_not_installed(mocker, default_conf, import_fails) -> None:
args = [
'hyperopt',
'--config', 'config.json',
'--hyperopt', 'HyperoptTestSepFile',
'--hyperopt-path',
str(Path(__file__).parent / "hyperopts"),
'--strategy', 'HyperoptableStrategy',
'--epochs', '5',
'--hyperopt-loss', 'SharpeHyperOptLossDaily',
]
@@ -199,7 +153,7 @@ def test_start_not_installed(mocker, default_conf, import_fails) -> None:
start_hyperopt(pargs)
def test_start(mocker, hyperopt_conf, caplog) -> None:
def test_start_no_hyperopt_allowed(mocker, hyperopt_conf, caplog) -> None:
start_mock = MagicMock()
patched_configuration_load_config_file(mocker, hyperopt_conf)
mocker.patch('freqtrade.optimize.hyperopt.Hyperopt.start', start_mock)
@@ -213,10 +167,8 @@ def test_start(mocker, hyperopt_conf, caplog) -> None:
'--epochs', '5'
]
pargs = get_args(args)
start_hyperopt(pargs)
assert log_has('Starting freqtrade in Hyperopt mode', caplog)
assert start_mock.call_count == 1
with pytest.raises(OperationalException, match=r"Using separate Hyperopt files has been.*"):
start_hyperopt(pargs)
def test_start_no_data(mocker, hyperopt_conf) -> None:
@@ -228,11 +180,11 @@ def test_start_no_data(mocker, hyperopt_conf) -> None:
)
patch_exchange(mocker)
# TODO: migrate to strategy-based hyperopt
args = [
'hyperopt',
'--config', 'config.json',
'--hyperopt', 'HyperoptTestSepFile',
'--strategy', 'HyperoptableStrategy',
'--hyperopt-loss', 'SharpeHyperOptLossDaily',
'--epochs', '5'
]
@@ -250,7 +202,7 @@ def test_start_filelock(mocker, hyperopt_conf, caplog) -> None:
args = [
'hyperopt',
'--config', 'config.json',
'--hyperopt', 'HyperoptTestSepFile',
'--strategy', 'HyperoptableStrategy',
'--hyperopt-loss', 'SharpeHyperOptLossDaily',
'--epochs', '5'
]
@@ -430,74 +382,14 @@ def test_hyperopt_format_results(hyperopt):
def test_populate_indicators(hyperopt, testdatadir) -> None:
data = load_data(testdatadir, '1m', ['UNITTEST/BTC'], fill_up_missing=True)
dataframes = hyperopt.backtesting.strategy.advise_all_indicators(data)
dataframe = hyperopt.custom_hyperopt.populate_indicators(dataframes['UNITTEST/BTC'],
{'pair': 'UNITTEST/BTC'})
dataframe = dataframes['UNITTEST/BTC']
# Check if some indicators are generated. We will not test all of them
assert 'adx' in dataframe
assert 'mfi' in dataframe
assert 'macd' in dataframe
assert 'rsi' in dataframe
def test_buy_strategy_generator(hyperopt, testdatadir) -> None:
data = load_data(testdatadir, '1m', ['UNITTEST/BTC'], fill_up_missing=True)
dataframes = hyperopt.backtesting.strategy.advise_all_indicators(data)
dataframe = hyperopt.custom_hyperopt.populate_indicators(dataframes['UNITTEST/BTC'],
{'pair': 'UNITTEST/BTC'})
populate_buy_trend = hyperopt.custom_hyperopt.buy_strategy_generator(
{
'adx-value': 20,
'fastd-value': 20,
'mfi-value': 20,
'rsi-value': 20,
'short-adx-value': 80,
'short-fastd-value': 80,
'short-mfi-value': 80,
'short-rsi-value': 80,
'adx-enabled': True,
'fastd-enabled': True,
'mfi-enabled': True,
'rsi-enabled': True,
'trigger': 'bb_lower'
}
)
result = populate_buy_trend(dataframe, {'pair': 'UNITTEST/BTC'})
# Check if some indicators are generated. We will not test all of them
assert 'buy' in result
assert 1 in result['buy']
def test_sell_strategy_generator(hyperopt, testdatadir) -> None:
data = load_data(testdatadir, '1m', ['UNITTEST/BTC'], fill_up_missing=True)
dataframes = hyperopt.backtesting.strategy.advise_all_indicators(data)
dataframe = hyperopt.custom_hyperopt.populate_indicators(dataframes['UNITTEST/BTC'],
{'pair': 'UNITTEST/BTC'})
populate_sell_trend = hyperopt.custom_hyperopt.sell_strategy_generator(
{
'sell-adx-value': 20,
'sell-fastd-value': 75,
'sell-mfi-value': 80,
'sell-rsi-value': 20,
'exit-short-adx-value': 80,
'exit-short-fastd-value': 25,
'exit-short-mfi-value': 20,
'exit-short-rsi-value': 80,
'sell-adx-enabled': True,
'sell-fastd-enabled': True,
'sell-mfi-enabled': True,
'sell-rsi-enabled': True,
'sell-trigger': 'sell-bb_upper'
}
)
result = populate_sell_trend(dataframe, {'pair': 'UNITTEST/BTC'})
# Check if some indicators are generated. We will not test all of them
print(result)
assert 'sell' in result
assert 1 in result['sell']
def test_generate_optimizer(mocker, hyperopt_conf) -> None:
hyperopt_conf.update({'spaces': 'all',
'hyperopt_min_trades': 1,
@@ -538,24 +430,12 @@ def test_generate_optimizer(mocker, hyperopt_conf) -> None:
mocker.patch('freqtrade.optimize.hyperopt.load', return_value={'XRP/BTC': None})
optimizer_param = {
'adx-value': 0,
'fastd-value': 35,
'mfi-value': 0,
'rsi-value': 0,
'adx-enabled': False,
'fastd-enabled': True,
'mfi-enabled': False,
'rsi-enabled': False,
'trigger': 'macd_cross_signal',
'sell-adx-value': 0,
'sell-fastd-value': 75,
'sell-mfi-value': 0,
'sell-rsi-value': 0,
'sell-adx-enabled': False,
'sell-fastd-enabled': True,
'sell-mfi-enabled': False,
'sell-rsi-enabled': False,
'sell-trigger': 'macd_cross_signal',
'buy_plusdi': 0.02,
'buy_rsi': 35,
'sell_minusdi': 0.02,
'sell_rsi': 75,
'protection_cooldown_lookback': 20,
'protection_enabled': True,
'roi_t1': 60.0,
'roi_t2': 30.0,
'roi_t3': 20.0,
@@ -575,29 +455,19 @@ def test_generate_optimizer(mocker, hyperopt_conf) -> None:
'0.00003100 BTC ( 0.00%). '
'Avg duration 0:50:00 min.'
),
'params_details': {'buy': {'adx-enabled': False,
'adx-value': 0,
'fastd-enabled': True,
'fastd-value': 35,
'mfi-enabled': False,
'mfi-value': 0,
'rsi-enabled': False,
'rsi-value': 0,
'trigger': 'macd_cross_signal'},
'params_details': {'buy': {'buy_plusdi': 0.02,
'buy_rsi': 35,
},
'roi': {"0": 0.12000000000000001,
"20.0": 0.02,
"50.0": 0.01,
"110.0": 0},
'protection': {},
'sell': {'sell-adx-enabled': False,
'sell-adx-value': 0,
'sell-fastd-enabled': True,
'sell-fastd-value': 75,
'sell-mfi-enabled': False,
'sell-mfi-value': 0,
'sell-rsi-enabled': False,
'sell-rsi-value': 0,
'sell-trigger': 'macd_cross_signal'},
'protection': {'protection_cooldown_lookback': 20,
'protection_enabled': True,
},
'sell': {'sell_minusdi': 0.02,
'sell_rsi': 75,
},
'stoploss': {'stoploss': -0.4},
'trailing': {'trailing_only_offset_is_reached': False,
'trailing_stop': True,
@@ -819,11 +689,6 @@ def test_simplified_interface_roi_stoploss(mocker, hyperopt_conf, capsys) -> Non
hyperopt.backtesting.strategy.advise_all_indicators = MagicMock()
hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
del hyperopt.custom_hyperopt.__class__.buy_strategy_generator
del hyperopt.custom_hyperopt.__class__.sell_strategy_generator
del hyperopt.custom_hyperopt.__class__.indicator_space
del hyperopt.custom_hyperopt.__class__.sell_indicator_space
hyperopt.start()
parallel.assert_called_once()
@@ -854,16 +719,14 @@ def test_simplified_interface_all_failed(mocker, hyperopt_conf) -> None:
hyperopt_conf.update({'spaces': 'all', })
mocker.patch('freqtrade.optimize.hyperopt_auto.HyperOptAuto._generate_indicator_space',
return_value=[])
hyperopt = Hyperopt(hyperopt_conf)
hyperopt.backtesting.strategy.advise_all_indicators = MagicMock()
hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
del hyperopt.custom_hyperopt.__class__.buy_strategy_generator
del hyperopt.custom_hyperopt.__class__.sell_strategy_generator
del hyperopt.custom_hyperopt.__class__.indicator_space
del hyperopt.custom_hyperopt.__class__.sell_indicator_space
with pytest.raises(OperationalException, match=r"The 'buy' space is included into *"):
with pytest.raises(OperationalException, match=r"The 'protection' space is included into *"):
hyperopt.start()
@@ -900,11 +763,6 @@ def test_simplified_interface_buy(mocker, hyperopt_conf, capsys) -> None:
hyperopt.backtesting.strategy.advise_all_indicators = MagicMock()
hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
# TODO: sell_strategy_generator() is actually not called because
# run_optimizer_parallel() is mocked
del hyperopt.custom_hyperopt.__class__.sell_strategy_generator
del hyperopt.custom_hyperopt.__class__.sell_indicator_space
hyperopt.start()
parallel.assert_called_once()
@@ -954,11 +812,6 @@ def test_simplified_interface_sell(mocker, hyperopt_conf, capsys) -> None:
hyperopt.backtesting.strategy.advise_all_indicators = MagicMock()
hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
# TODO: buy_strategy_generator() is actually not called because
# run_optimizer_parallel() is mocked
del hyperopt.custom_hyperopt.__class__.buy_strategy_generator
del hyperopt.custom_hyperopt.__class__.indicator_space
hyperopt.start()
parallel.assert_called_once()
@@ -975,13 +828,12 @@ def test_simplified_interface_sell(mocker, hyperopt_conf, capsys) -> None:
assert hasattr(hyperopt, "position_stacking")
@pytest.mark.parametrize("method,space", [
('buy_strategy_generator', 'buy'),
('indicator_space', 'buy'),
('sell_strategy_generator', 'sell'),
('sell_indicator_space', 'sell'),
@pytest.mark.parametrize("space", [
('buy'),
('sell'),
('protection'),
])
def test_simplified_interface_failed(mocker, hyperopt_conf, method, space) -> None:
def test_simplified_interface_failed(mocker, hyperopt_conf, space) -> None:
mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock())
mocker.patch('freqtrade.optimize.hyperopt.file_dump_json')
mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data',
@@ -990,6 +842,8 @@ def test_simplified_interface_failed(mocker, hyperopt_conf, method, space) -> No
'freqtrade.optimize.hyperopt.get_timerange',
MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13)))
)
mocker.patch('freqtrade.optimize.hyperopt_auto.HyperOptAuto._generate_indicator_space',
return_value=[])
patch_exchange(mocker)
@@ -999,8 +853,6 @@ def test_simplified_interface_failed(mocker, hyperopt_conf, method, space) -> No
hyperopt.backtesting.strategy.advise_all_indicators = MagicMock()
hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={})
delattr(hyperopt.custom_hyperopt.__class__, method)
with pytest.raises(OperationalException, match=f"The '{space}' space is included into *"):
hyperopt.start()
@@ -1010,7 +862,6 @@ def test_in_strategy_auto_hyperopt(mocker, hyperopt_conf, tmpdir, fee) -> None:
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
(Path(tmpdir) / 'hyperopt_results').mkdir(parents=True)
# No hyperopt needed
del hyperopt_conf['hyperopt']
hyperopt_conf.update({
'strategy': 'HyperoptableStrategy',
'user_data_dir': Path(tmpdir),

View File

@@ -68,7 +68,7 @@ def test_PairLocks(use_db):
# Global lock
PairLocks.lock_pair('*', lock_time)
assert PairLocks.is_global_lock(lock_time + timedelta(minutes=-50))
# Global lock also locks every pair seperately
# Global lock also locks every pair separately
assert PairLocks.is_pair_locked(pair, lock_time + timedelta(minutes=-50))
assert PairLocks.is_pair_locked('XRP/USDT', lock_time + timedelta(minutes=-50))

View File

@@ -11,8 +11,7 @@ import pytest
from jsonschema import ValidationError
from freqtrade.commands import Arguments
from freqtrade.configuration import (Configuration, check_exchange, remove_credentials,
validate_config_consistency)
from freqtrade.configuration import Configuration, check_exchange, validate_config_consistency
from freqtrade.configuration.config_validation import validate_config_schema
from freqtrade.configuration.deprecated_settings import (check_conflicting_settings,
process_deprecated_setting,
@@ -617,18 +616,6 @@ def test_check_exchange(default_conf, caplog) -> None:
check_exchange(default_conf)
def test_remove_credentials(default_conf, caplog) -> None:
conf = deepcopy(default_conf)
conf['dry_run'] = False
remove_credentials(conf)
assert conf['dry_run'] is True
assert conf['exchange']['key'] == ''
assert conf['exchange']['secret'] == ''
assert conf['exchange']['password'] == ''
assert conf['exchange']['uid'] == ''
def test_cli_verbose_with_params(default_conf, mocker, caplog) -> None:
patched_configuration_load_config_file(mocker, default_conf)

View File

@@ -74,16 +74,12 @@ def test_copy_sample_files(mocker, default_conf, caplog) -> None:
copymock = mocker.patch('shutil.copy', MagicMock())
copy_sample_files(Path('/tmp/bar'))
assert copymock.call_count == 5
assert copymock.call_count == 3
assert copymock.call_args_list[0][0][1] == str(
Path('/tmp/bar') / 'strategies/sample_strategy.py')
assert copymock.call_args_list[1][0][1] == str(
Path('/tmp/bar') / 'hyperopts/sample_hyperopt_advanced.py')
assert copymock.call_args_list[2][0][1] == str(
Path('/tmp/bar') / 'hyperopts/sample_hyperopt_loss.py')
assert copymock.call_args_list[3][0][1] == str(
Path('/tmp/bar') / 'hyperopts/sample_hyperopt.py')
assert copymock.call_args_list[4][0][1] == str(
assert copymock.call_args_list[2][0][1] == str(
Path('/tmp/bar') / 'notebooks/strategy_analysis_example.ipynb')