Update config to use single quotes
This commit is contained in:
parent
d1fe3c1a3d
commit
309ea1246a
@ -35,8 +35,8 @@ def start_download_data(args: Dict[str, Any]) -> None:
|
|||||||
"Downloading data requires a list of pairs. "
|
"Downloading data requires a list of pairs. "
|
||||||
"Please check the documentation on how to configure this.")
|
"Please check the documentation on how to configure this.")
|
||||||
|
|
||||||
logger.info(f'About to download pairs: {config["pairs"]}, '
|
logger.info(f"About to download pairs: {config['pairs']}, "
|
||||||
f'intervals: {config["timeframes"]} to {config["datadir"]}')
|
f"intervals: {config['timeframes']} to {config['datadir']}")
|
||||||
|
|
||||||
pairs_not_available: List[str] = []
|
pairs_not_available: List[str] = []
|
||||||
|
|
||||||
@ -51,21 +51,21 @@ def start_download_data(args: Dict[str, Any]) -> None:
|
|||||||
|
|
||||||
if config.get('download_trades'):
|
if config.get('download_trades'):
|
||||||
pairs_not_available = refresh_backtest_trades_data(
|
pairs_not_available = refresh_backtest_trades_data(
|
||||||
exchange, pairs=config["pairs"], datadir=config['datadir'],
|
exchange, pairs=config['pairs'], datadir=config['datadir'],
|
||||||
timerange=timerange, erase=bool(config.get("erase")),
|
timerange=timerange, erase=bool(config.get('erase')),
|
||||||
data_format=config['dataformat_trades'])
|
data_format=config['dataformat_trades'])
|
||||||
|
|
||||||
# Convert downloaded trade data to different timeframes
|
# Convert downloaded trade data to different timeframes
|
||||||
convert_trades_to_ohlcv(
|
convert_trades_to_ohlcv(
|
||||||
pairs=config["pairs"], timeframes=config["timeframes"],
|
pairs=config['pairs'], timeframes=config['timeframes'],
|
||||||
datadir=config['datadir'], timerange=timerange, erase=bool(config.get("erase")),
|
datadir=config['datadir'], timerange=timerange, erase=bool(config.get('erase')),
|
||||||
data_format_ohlcv=config['dataformat_ohlcv'],
|
data_format_ohlcv=config['dataformat_ohlcv'],
|
||||||
data_format_trades=config['dataformat_trades'],
|
data_format_trades=config['dataformat_trades'],
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
pairs_not_available = refresh_backtest_ohlcv_data(
|
pairs_not_available = refresh_backtest_ohlcv_data(
|
||||||
exchange, pairs=config["pairs"], timeframes=config["timeframes"],
|
exchange, pairs=config['pairs'], timeframes=config['timeframes'],
|
||||||
datadir=config['datadir'], timerange=timerange, erase=bool(config.get("erase")),
|
datadir=config['datadir'], timerange=timerange, erase=bool(config.get('erase')),
|
||||||
data_format=config['dataformat_ohlcv'])
|
data_format=config['dataformat_ohlcv'])
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
@ -75,7 +75,7 @@ def start_new_strategy(args: Dict[str, Any]) -> None:
|
|||||||
if args["strategy"] == "DefaultStrategy":
|
if args["strategy"] == "DefaultStrategy":
|
||||||
raise OperationalException("DefaultStrategy is not allowed as name.")
|
raise OperationalException("DefaultStrategy is not allowed as name.")
|
||||||
|
|
||||||
new_path = config['user_data_dir'] / USERPATH_STRATEGIES / (args["strategy"] + ".py")
|
new_path = config['user_data_dir'] / USERPATH_STRATEGIES / (args['strategy'] + '.py')
|
||||||
|
|
||||||
if new_path.exists():
|
if new_path.exists():
|
||||||
raise OperationalException(f"`{new_path}` already exists. "
|
raise OperationalException(f"`{new_path}` already exists. "
|
||||||
@ -125,11 +125,11 @@ def start_new_hyperopt(args: Dict[str, Any]) -> None:
|
|||||||
|
|
||||||
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
|
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
|
||||||
|
|
||||||
if "hyperopt" in args and args["hyperopt"]:
|
if 'hyperopt' in args and args['hyperopt']:
|
||||||
if args["hyperopt"] == "DefaultHyperopt":
|
if args['hyperopt'] == 'DefaultHyperopt':
|
||||||
raise OperationalException("DefaultHyperopt is not allowed as name.")
|
raise OperationalException("DefaultHyperopt is not allowed as name.")
|
||||||
|
|
||||||
new_path = config['user_data_dir'] / USERPATH_HYPEROPTS / (args["hyperopt"] + ".py")
|
new_path = config['user_data_dir'] / USERPATH_HYPEROPTS / (args['hyperopt'] + '.py')
|
||||||
|
|
||||||
if new_path.exists():
|
if new_path.exists():
|
||||||
raise OperationalException(f"`{new_path}` already exists. "
|
raise OperationalException(f"`{new_path}` already exists. "
|
||||||
|
@ -54,7 +54,7 @@ class Configuration:
|
|||||||
:param files: List of file paths
|
:param files: List of file paths
|
||||||
:return: configuration dictionary
|
:return: configuration dictionary
|
||||||
"""
|
"""
|
||||||
c = Configuration({"config": files}, RunMode.OTHER)
|
c = Configuration({'config': files}, RunMode.OTHER)
|
||||||
return c.get_config()
|
return c.get_config()
|
||||||
|
|
||||||
def load_from_files(self, files: List[str]) -> Dict[str, Any]:
|
def load_from_files(self, files: List[str]) -> Dict[str, Any]:
|
||||||
@ -123,10 +123,10 @@ class Configuration:
|
|||||||
the -v/--verbose, --logfile options
|
the -v/--verbose, --logfile options
|
||||||
"""
|
"""
|
||||||
# Log level
|
# Log level
|
||||||
config.update({'verbosity': self.args.get("verbosity", 0)})
|
config.update({'verbosity': self.args.get('verbosity', 0)})
|
||||||
|
|
||||||
if 'logfile' in self.args and self.args["logfile"]:
|
if 'logfile' in self.args and self.args['logfile']:
|
||||||
config.update({'logfile': self.args["logfile"]})
|
config.update({'logfile': self.args['logfile']})
|
||||||
|
|
||||||
setup_logging(config)
|
setup_logging(config)
|
||||||
|
|
||||||
@ -149,22 +149,22 @@ class Configuration:
|
|||||||
def _process_common_options(self, config: Dict[str, Any]) -> None:
|
def _process_common_options(self, config: Dict[str, Any]) -> None:
|
||||||
|
|
||||||
# Set strategy if not specified in config and or if it's non default
|
# Set strategy if not specified in config and or if it's non default
|
||||||
if self.args.get("strategy") or not config.get('strategy'):
|
if self.args.get('strategy') or not config.get('strategy'):
|
||||||
config.update({'strategy': self.args.get("strategy")})
|
config.update({'strategy': self.args.get('strategy')})
|
||||||
|
|
||||||
self._args_to_config(config, argname='strategy_path',
|
self._args_to_config(config, argname='strategy_path',
|
||||||
logstring='Using additional Strategy lookup path: {}')
|
logstring='Using additional Strategy lookup path: {}')
|
||||||
|
|
||||||
if ('db_url' in self.args and self.args["db_url"] and
|
if ('db_url' in self.args and self.args['db_url'] and
|
||||||
self.args["db_url"] != constants.DEFAULT_DB_PROD_URL):
|
self.args['db_url'] != constants.DEFAULT_DB_PROD_URL):
|
||||||
config.update({'db_url': self.args["db_url"]})
|
config.update({'db_url': self.args['db_url']})
|
||||||
logger.info('Parameter --db-url detected ...')
|
logger.info('Parameter --db-url detected ...')
|
||||||
|
|
||||||
if config.get('forcebuy_enable', False):
|
if config.get('forcebuy_enable', False):
|
||||||
logger.warning('`forcebuy` RPC message enabled.')
|
logger.warning('`forcebuy` RPC message enabled.')
|
||||||
|
|
||||||
# Support for sd_notify
|
# Support for sd_notify
|
||||||
if 'sd_notify' in self.args and self.args["sd_notify"]:
|
if 'sd_notify' in self.args and self.args['sd_notify']:
|
||||||
config['internals'].update({'sd_notify': True})
|
config['internals'].update({'sd_notify': True})
|
||||||
|
|
||||||
def _process_datadir_options(self, config: Dict[str, Any]) -> None:
|
def _process_datadir_options(self, config: Dict[str, Any]) -> None:
|
||||||
@ -173,24 +173,24 @@ class Configuration:
|
|||||||
--user-data, --datadir
|
--user-data, --datadir
|
||||||
"""
|
"""
|
||||||
# Check exchange parameter here - otherwise `datadir` might be wrong.
|
# Check exchange parameter here - otherwise `datadir` might be wrong.
|
||||||
if "exchange" in self.args and self.args["exchange"]:
|
if 'exchange' in self.args and self.args['exchange']:
|
||||||
config['exchange']['name'] = self.args["exchange"]
|
config['exchange']['name'] = self.args['exchange']
|
||||||
logger.info(f"Using exchange {config['exchange']['name']}")
|
logger.info(f"Using exchange {config['exchange']['name']}")
|
||||||
|
|
||||||
if 'pair_whitelist' not in config['exchange']:
|
if 'pair_whitelist' not in config['exchange']:
|
||||||
config['exchange']['pair_whitelist'] = []
|
config['exchange']['pair_whitelist'] = []
|
||||||
|
|
||||||
if 'user_data_dir' in self.args and self.args["user_data_dir"]:
|
if 'user_data_dir' in self.args and self.args['user_data_dir']:
|
||||||
config.update({'user_data_dir': self.args["user_data_dir"]})
|
config.update({'user_data_dir': self.args['user_data_dir']})
|
||||||
elif 'user_data_dir' not in config:
|
elif 'user_data_dir' not in config:
|
||||||
# Default to cwd/user_data (legacy option ...)
|
# Default to cwd/user_data (legacy option ...)
|
||||||
config.update({'user_data_dir': str(Path.cwd() / "user_data")})
|
config.update({'user_data_dir': str(Path.cwd() / 'user_data')})
|
||||||
|
|
||||||
# reset to user_data_dir so this contains the absolute path.
|
# reset to user_data_dir so this contains the absolute path.
|
||||||
config['user_data_dir'] = create_userdata_dir(config['user_data_dir'], create_dir=False)
|
config['user_data_dir'] = create_userdata_dir(config['user_data_dir'], create_dir=False)
|
||||||
logger.info('Using user-data directory: %s ...', config['user_data_dir'])
|
logger.info('Using user-data directory: %s ...', config['user_data_dir'])
|
||||||
|
|
||||||
config.update({'datadir': create_datadir(config, self.args.get("datadir", None))})
|
config.update({'datadir': create_datadir(config, self.args.get('datadir', None))})
|
||||||
logger.info('Using data directory: %s ...', config.get('datadir'))
|
logger.info('Using data directory: %s ...', config.get('datadir'))
|
||||||
|
|
||||||
if self.args.get('exportfilename'):
|
if self.args.get('exportfilename'):
|
||||||
@ -219,8 +219,8 @@ class Configuration:
|
|||||||
config.update({'use_max_market_positions': False})
|
config.update({'use_max_market_positions': False})
|
||||||
logger.info('Parameter --disable-max-market-positions detected ...')
|
logger.info('Parameter --disable-max-market-positions detected ...')
|
||||||
logger.info('max_open_trades set to unlimited ...')
|
logger.info('max_open_trades set to unlimited ...')
|
||||||
elif 'max_open_trades' in self.args and self.args["max_open_trades"]:
|
elif 'max_open_trades' in self.args and self.args['max_open_trades']:
|
||||||
config.update({'max_open_trades': self.args["max_open_trades"]})
|
config.update({'max_open_trades': self.args['max_open_trades']})
|
||||||
logger.info('Parameter --max-open-trades detected, '
|
logger.info('Parameter --max-open-trades detected, '
|
||||||
'overriding max_open_trades to: %s ...', config.get('max_open_trades'))
|
'overriding max_open_trades to: %s ...', config.get('max_open_trades'))
|
||||||
elif config['runmode'] in NON_UTIL_MODES:
|
elif config['runmode'] in NON_UTIL_MODES:
|
||||||
@ -447,12 +447,12 @@ class Configuration:
|
|||||||
config['pairs'].sort()
|
config['pairs'].sort()
|
||||||
return
|
return
|
||||||
|
|
||||||
if "config" in self.args and self.args["config"]:
|
if 'config' in self.args and self.args['config']:
|
||||||
logger.info("Using pairlist from configuration.")
|
logger.info("Using pairlist from configuration.")
|
||||||
config['pairs'] = config.get('exchange', {}).get('pair_whitelist')
|
config['pairs'] = config.get('exchange', {}).get('pair_whitelist')
|
||||||
else:
|
else:
|
||||||
# Fall back to /dl_path/pairs.json
|
# Fall back to /dl_path/pairs.json
|
||||||
pairs_file = config['datadir'] / "pairs.json"
|
pairs_file = config['datadir'] / 'pairs.json'
|
||||||
if pairs_file.exists():
|
if pairs_file.exists():
|
||||||
with pairs_file.open('r') as f:
|
with pairs_file.open('r') as f:
|
||||||
config['pairs'] = json_load(f)
|
config['pairs'] = json_load(f)
|
||||||
|
@ -208,7 +208,7 @@ def load_trades_from_db(db_url: str, strategy: Optional[str] = None) -> pd.DataF
|
|||||||
def load_trades(source: str, db_url: str, exportfilename: Path,
|
def load_trades(source: str, db_url: str, exportfilename: Path,
|
||||||
no_trades: bool = False, strategy: Optional[str] = None) -> pd.DataFrame:
|
no_trades: bool = False, strategy: Optional[str] = None) -> pd.DataFrame:
|
||||||
"""
|
"""
|
||||||
Based on configuration option "trade_source":
|
Based on configuration option 'trade_source':
|
||||||
* loads data from DB (using `db_url`)
|
* loads data from DB (using `db_url`)
|
||||||
* loads data from backtestfile (using `exportfilename`)
|
* loads data from backtestfile (using `exportfilename`)
|
||||||
:param source: "DB" or "file" - specify source to load from
|
:param source: "DB" or "file" - specify source to load from
|
||||||
|
@ -85,8 +85,8 @@ class Exchange:
|
|||||||
|
|
||||||
# Deep merge ft_has with default ft_has options
|
# Deep merge ft_has with default ft_has options
|
||||||
self._ft_has = deep_merge_dicts(self._ft_has, deepcopy(self._ft_has_default))
|
self._ft_has = deep_merge_dicts(self._ft_has, deepcopy(self._ft_has_default))
|
||||||
if exchange_config.get("_ft_has_params"):
|
if exchange_config.get('_ft_has_params'):
|
||||||
self._ft_has = deep_merge_dicts(exchange_config.get("_ft_has_params"),
|
self._ft_has = deep_merge_dicts(exchange_config.get('_ft_has_params'),
|
||||||
self._ft_has)
|
self._ft_has)
|
||||||
logger.info("Overriding exchange._ft_has with config params, result: %s", self._ft_has)
|
logger.info("Overriding exchange._ft_has with config params, result: %s", self._ft_has)
|
||||||
|
|
||||||
|
@ -38,15 +38,15 @@ def init_plotscript(config):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if "pairs" in config:
|
if "pairs" in config:
|
||||||
pairs = config["pairs"]
|
pairs = config['pairs']
|
||||||
else:
|
else:
|
||||||
pairs = config["exchange"]["pair_whitelist"]
|
pairs = config['exchange']['pair_whitelist']
|
||||||
|
|
||||||
# Set timerange to use
|
# Set timerange to use
|
||||||
timerange = TimeRange.parse_timerange(config.get("timerange"))
|
timerange = TimeRange.parse_timerange(config.get('timerange'))
|
||||||
|
|
||||||
data = load_data(
|
data = load_data(
|
||||||
datadir=config.get("datadir"),
|
datadir=config.get('datadir'),
|
||||||
pairs=pairs,
|
pairs=pairs,
|
||||||
timeframe=config.get('timeframe', '5m'),
|
timeframe=config.get('timeframe', '5m'),
|
||||||
timerange=timerange,
|
timerange=timerange,
|
||||||
@ -67,7 +67,7 @@ def init_plotscript(config):
|
|||||||
db_url=config.get('db_url'),
|
db_url=config.get('db_url'),
|
||||||
exportfilename=filename,
|
exportfilename=filename,
|
||||||
no_trades=no_trades,
|
no_trades=no_trades,
|
||||||
strategy=config.get("strategy"),
|
strategy=config.get('strategy'),
|
||||||
)
|
)
|
||||||
trades = trim_dataframe(trades, timerange, 'open_date')
|
trades = trim_dataframe(trades, timerange, 'open_date')
|
||||||
|
|
||||||
@ -491,13 +491,13 @@ def load_and_plot_trades(config: Dict[str, Any]):
|
|||||||
pair=pair,
|
pair=pair,
|
||||||
data=df_analyzed,
|
data=df_analyzed,
|
||||||
trades=trades_pair,
|
trades=trades_pair,
|
||||||
indicators1=config.get("indicators1", []),
|
indicators1=config.get('indicators1', []),
|
||||||
indicators2=config.get("indicators2", []),
|
indicators2=config.get('indicators2', []),
|
||||||
plot_config=strategy.plot_config if hasattr(strategy, 'plot_config') else {}
|
plot_config=strategy.plot_config if hasattr(strategy, 'plot_config') else {}
|
||||||
)
|
)
|
||||||
|
|
||||||
store_plot_file(fig, filename=generate_plot_filename(pair, config['timeframe']),
|
store_plot_file(fig, filename=generate_plot_filename(pair, config['timeframe']),
|
||||||
directory=config['user_data_dir'] / "plot")
|
directory=config['user_data_dir'] / 'plot')
|
||||||
|
|
||||||
logger.info('End of plotting process. %s plots generated', pair_counter)
|
logger.info('End of plotting process. %s plots generated', pair_counter)
|
||||||
|
|
||||||
@ -514,7 +514,7 @@ def plot_profit(config: Dict[str, Any]) -> None:
|
|||||||
# Filter trades to relevant pairs
|
# Filter trades to relevant pairs
|
||||||
# Remove open pairs - we don't know the profit yet so can't calculate profit for these.
|
# Remove open pairs - we don't know the profit yet so can't calculate profit for these.
|
||||||
# Also, If only one open pair is left, then the profit-generation would fail.
|
# Also, If only one open pair is left, then the profit-generation would fail.
|
||||||
trades = trades[(trades['pair'].isin(plot_elements["pairs"]))
|
trades = trades[(trades['pair'].isin(plot_elements['pairs']))
|
||||||
& (~trades['close_date'].isnull())
|
& (~trades['close_date'].isnull())
|
||||||
]
|
]
|
||||||
if len(trades) == 0:
|
if len(trades) == 0:
|
||||||
@ -523,7 +523,7 @@ def plot_profit(config: Dict[str, Any]) -> None:
|
|||||||
|
|
||||||
# Create an average close price of all the pairs that were involved.
|
# Create an average close price of all the pairs that were involved.
|
||||||
# this could be useful to gauge the overall market trend
|
# this could be useful to gauge the overall market trend
|
||||||
fig = generate_profit_graph(plot_elements["pairs"], plot_elements["ohlcv"],
|
fig = generate_profit_graph(plot_elements['pairs'], plot_elements['ohlcv'],
|
||||||
trades, config.get('timeframe', '5m'))
|
trades, config.get('timeframe', '5m'))
|
||||||
store_plot_file(fig, filename='freqtrade-profit-plot.html',
|
store_plot_file(fig, filename='freqtrade-profit-plot.html',
|
||||||
directory=config['user_data_dir'] / "plot", auto_open=True)
|
directory=config['user_data_dir'] / 'plot', auto_open=True)
|
||||||
|
@ -276,11 +276,11 @@ def main(args):
|
|||||||
print_commands()
|
print_commands()
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
config = load_config(args["config"])
|
config = load_config(args['config'])
|
||||||
url = config.get("api_server", {}).get("server_url", "127.0.0.1")
|
url = config.get('api_server', {}).get('server_url', '127.0.0.1')
|
||||||
port = config.get("api_server", {}).get("listen_port", "8080")
|
port = config.get('api_server', {}).get('listen_port', '8080')
|
||||||
username = config.get("api_server", {}).get("username")
|
username = config.get('api_server', {}).get('username')
|
||||||
password = config.get("api_server", {}).get("password")
|
password = config.get('api_server', {}).get('password')
|
||||||
|
|
||||||
server_url = f"http://{url}:{port}"
|
server_url = f"http://{url}:{port}"
|
||||||
client = FtRestClient(server_url, username, password)
|
client = FtRestClient(server_url, username, password)
|
||||||
|
@ -78,7 +78,7 @@ def patch_exchange(mocker, api_mock=None, id='bittrex', mock_markets=True) -> No
|
|||||||
def get_patched_exchange(mocker, config, api_mock=None, id='bittrex',
|
def get_patched_exchange(mocker, config, api_mock=None, id='bittrex',
|
||||||
mock_markets=True) -> Exchange:
|
mock_markets=True) -> Exchange:
|
||||||
patch_exchange(mocker, api_mock, id, mock_markets)
|
patch_exchange(mocker, api_mock, id, mock_markets)
|
||||||
config["exchange"]["name"] = id
|
config['exchange']['name'] = id
|
||||||
try:
|
try:
|
||||||
exchange = ExchangeResolver.load_exchange(id, config)
|
exchange = ExchangeResolver.load_exchange(id, config)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -87,20 +87,20 @@ def test_api_unauthorized(botclient):
|
|||||||
assert rc.json == {'error': 'Unauthorized'}
|
assert rc.json == {'error': 'Unauthorized'}
|
||||||
|
|
||||||
# Change only username
|
# Change only username
|
||||||
ftbot.config['api_server']['username'] = "Ftrader"
|
ftbot.config['api_server']['username'] = 'Ftrader'
|
||||||
rc = client_get(client, f"{BASE_URI}/version")
|
rc = client_get(client, f"{BASE_URI}/version")
|
||||||
assert_response(rc, 401)
|
assert_response(rc, 401)
|
||||||
assert rc.json == {'error': 'Unauthorized'}
|
assert rc.json == {'error': 'Unauthorized'}
|
||||||
|
|
||||||
# Change only password
|
# Change only password
|
||||||
ftbot.config['api_server']['username'] = _TEST_USER
|
ftbot.config['api_server']['username'] = _TEST_USER
|
||||||
ftbot.config['api_server']['password'] = "WrongPassword"
|
ftbot.config['api_server']['password'] = 'WrongPassword'
|
||||||
rc = client_get(client, f"{BASE_URI}/version")
|
rc = client_get(client, f"{BASE_URI}/version")
|
||||||
assert_response(rc, 401)
|
assert_response(rc, 401)
|
||||||
assert rc.json == {'error': 'Unauthorized'}
|
assert rc.json == {'error': 'Unauthorized'}
|
||||||
|
|
||||||
ftbot.config['api_server']['username'] = "Ftrader"
|
ftbot.config['api_server']['username'] = 'Ftrader'
|
||||||
ftbot.config['api_server']['password'] = "WrongPassword"
|
ftbot.config['api_server']['password'] = 'WrongPassword'
|
||||||
|
|
||||||
rc = client_get(client, f"{BASE_URI}/version")
|
rc = client_get(client, f"{BASE_URI}/version")
|
||||||
assert_response(rc, 401)
|
assert_response(rc, 401)
|
||||||
@ -677,7 +677,7 @@ def test_api_forcebuy(botclient, mocker, fee):
|
|||||||
assert rc.json == {"error": "Error querying _forcebuy: Forcebuy not enabled."}
|
assert rc.json == {"error": "Error querying _forcebuy: Forcebuy not enabled."}
|
||||||
|
|
||||||
# enable forcebuy
|
# enable forcebuy
|
||||||
ftbot.config["forcebuy_enable"] = True
|
ftbot.config['forcebuy_enable'] = True
|
||||||
|
|
||||||
fbuy_mock = MagicMock(return_value=None)
|
fbuy_mock = MagicMock(return_value=None)
|
||||||
mocker.patch("freqtrade.rpc.RPC._rpc_forcebuy", fbuy_mock)
|
mocker.patch("freqtrade.rpc.RPC._rpc_forcebuy", fbuy_mock)
|
||||||
|
@ -19,64 +19,64 @@ def test_parse_args_none() -> None:
|
|||||||
|
|
||||||
|
|
||||||
def test_parse_args_defaults(mocker) -> None:
|
def test_parse_args_defaults(mocker) -> None:
|
||||||
mocker.patch.object(Path, "is_file", MagicMock(side_effect=[False, True]))
|
mocker.patch.object(Path, 'is_file', MagicMock(side_effect=[False, True]))
|
||||||
args = Arguments(['trade']).get_parsed_arg()
|
args = Arguments(['trade']).get_parsed_arg()
|
||||||
assert args["config"] == ['config.json']
|
assert args['config'] == ['config.json']
|
||||||
assert args["strategy_path"] is None
|
assert args['strategy_path'] is None
|
||||||
assert args["datadir"] is None
|
assert args['datadir'] is None
|
||||||
assert args["verbosity"] == 0
|
assert args['verbosity'] == 0
|
||||||
|
|
||||||
|
|
||||||
def test_parse_args_default_userdatadir(mocker) -> None:
|
def test_parse_args_default_userdatadir(mocker) -> None:
|
||||||
mocker.patch.object(Path, "is_file", MagicMock(return_value=True))
|
mocker.patch.object(Path, 'is_file', MagicMock(return_value=True))
|
||||||
args = Arguments(['trade']).get_parsed_arg()
|
args = Arguments(['trade']).get_parsed_arg()
|
||||||
# configuration defaults to user_data if that is available.
|
# configuration defaults to user_data if that is available.
|
||||||
assert args["config"] == [str(Path('user_data/config.json'))]
|
assert args['config'] == [str(Path('user_data/config.json'))]
|
||||||
assert args["strategy_path"] is None
|
assert args['strategy_path'] is None
|
||||||
assert args["datadir"] is None
|
assert args['datadir'] is None
|
||||||
assert args["verbosity"] == 0
|
assert args['verbosity'] == 0
|
||||||
|
|
||||||
|
|
||||||
def test_parse_args_userdatadir(mocker) -> None:
|
def test_parse_args_userdatadir(mocker) -> None:
|
||||||
mocker.patch.object(Path, "is_file", MagicMock(return_value=True))
|
mocker.patch.object(Path, 'is_file', MagicMock(return_value=True))
|
||||||
args = Arguments(['trade', '--user-data-dir', 'user_data']).get_parsed_arg()
|
args = Arguments(['trade', '--user-data-dir', 'user_data']).get_parsed_arg()
|
||||||
# configuration defaults to user_data if that is available.
|
# configuration defaults to user_data if that is available.
|
||||||
assert args["config"] == [str(Path('user_data/config.json'))]
|
assert args['config'] == [str(Path('user_data/config.json'))]
|
||||||
assert args["strategy_path"] is None
|
assert args['strategy_path'] is None
|
||||||
assert args["datadir"] is None
|
assert args['datadir'] is None
|
||||||
assert args["verbosity"] == 0
|
assert args['verbosity'] == 0
|
||||||
|
|
||||||
|
|
||||||
def test_parse_args_config() -> None:
|
def test_parse_args_config() -> None:
|
||||||
args = Arguments(['trade', '-c', '/dev/null']).get_parsed_arg()
|
args = Arguments(['trade', '-c', '/dev/null']).get_parsed_arg()
|
||||||
assert args["config"] == ['/dev/null']
|
assert args['config'] == ['/dev/null']
|
||||||
|
|
||||||
args = Arguments(['trade', '--config', '/dev/null']).get_parsed_arg()
|
args = Arguments(['trade', '--config', '/dev/null']).get_parsed_arg()
|
||||||
assert args["config"] == ['/dev/null']
|
assert args['config'] == ['/dev/null']
|
||||||
|
|
||||||
args = Arguments(['trade', '--config', '/dev/null',
|
args = Arguments(['trade', '--config', '/dev/null',
|
||||||
'--config', '/dev/zero'],).get_parsed_arg()
|
'--config', '/dev/zero'],).get_parsed_arg()
|
||||||
assert args["config"] == ['/dev/null', '/dev/zero']
|
assert args['config'] == ['/dev/null', '/dev/zero']
|
||||||
|
|
||||||
|
|
||||||
def test_parse_args_db_url() -> None:
|
def test_parse_args_db_url() -> None:
|
||||||
args = Arguments(['trade', '--db-url', 'sqlite:///test.sqlite']).get_parsed_arg()
|
args = Arguments(['trade', '--db-url', 'sqlite:///test.sqlite']).get_parsed_arg()
|
||||||
assert args["db_url"] == 'sqlite:///test.sqlite'
|
assert args['db_url'] == 'sqlite:///test.sqlite'
|
||||||
|
|
||||||
|
|
||||||
def test_parse_args_verbose() -> None:
|
def test_parse_args_verbose() -> None:
|
||||||
args = Arguments(['trade', '-v']).get_parsed_arg()
|
args = Arguments(['trade', '-v']).get_parsed_arg()
|
||||||
assert args["verbosity"] == 1
|
assert args['verbosity'] == 1
|
||||||
|
|
||||||
args = Arguments(['trade', '--verbose']).get_parsed_arg()
|
args = Arguments(['trade', '--verbose']).get_parsed_arg()
|
||||||
assert args["verbosity"] == 1
|
assert args['verbosity'] == 1
|
||||||
|
|
||||||
|
|
||||||
def test_common_scripts_options() -> None:
|
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 args['pairs'] == ['ETH/BTC', 'XRP/BTC']
|
||||||
assert "func" in args
|
assert 'func' in args
|
||||||
|
|
||||||
|
|
||||||
def test_parse_args_version() -> None:
|
def test_parse_args_version() -> None:
|
||||||
@ -91,7 +91,7 @@ def test_parse_args_invalid() -> None:
|
|||||||
|
|
||||||
def test_parse_args_strategy() -> None:
|
def test_parse_args_strategy() -> None:
|
||||||
args = Arguments(['trade', '--strategy', 'SomeStrategy']).get_parsed_arg()
|
args = Arguments(['trade', '--strategy', 'SomeStrategy']).get_parsed_arg()
|
||||||
assert args["strategy"] == 'SomeStrategy'
|
assert args['strategy'] == 'SomeStrategy'
|
||||||
|
|
||||||
|
|
||||||
def test_parse_args_strategy_invalid() -> None:
|
def test_parse_args_strategy_invalid() -> None:
|
||||||
@ -101,7 +101,7 @@ def test_parse_args_strategy_invalid() -> None:
|
|||||||
|
|
||||||
def test_parse_args_strategy_path() -> None:
|
def test_parse_args_strategy_path() -> None:
|
||||||
args = Arguments(['trade', '--strategy-path', '/some/path']).get_parsed_arg()
|
args = Arguments(['trade', '--strategy-path', '/some/path']).get_parsed_arg()
|
||||||
assert args["strategy_path"] == '/some/path'
|
assert args['strategy_path'] == '/some/path'
|
||||||
|
|
||||||
|
|
||||||
def test_parse_args_strategy_path_invalid() -> None:
|
def test_parse_args_strategy_path_invalid() -> None:
|
||||||
@ -127,13 +127,13 @@ def test_parse_args_backtesting_custom() -> None:
|
|||||||
'SampleStrategy'
|
'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['config'] == ['test_conf.json']
|
||||||
assert call_args["verbosity"] == 0
|
assert call_args['verbosity'] == 0
|
||||||
assert call_args["command"] == 'backtesting'
|
assert call_args['command'] == 'backtesting'
|
||||||
assert call_args["func"] is not None
|
assert call_args['func'] is not None
|
||||||
assert call_args["timeframe"] == '1m'
|
assert call_args['timeframe'] == '1m'
|
||||||
assert type(call_args["strategy_list"]) is list
|
assert type(call_args['strategy_list']) is list
|
||||||
assert len(call_args["strategy_list"]) == 2
|
assert len(call_args['strategy_list']) == 2
|
||||||
|
|
||||||
|
|
||||||
def test_parse_args_hyperopt_custom() -> None:
|
def test_parse_args_hyperopt_custom() -> None:
|
||||||
@ -144,13 +144,13 @@ def test_parse_args_hyperopt_custom() -> None:
|
|||||||
'--spaces', 'buy'
|
'--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['config'] == ['test_conf.json']
|
||||||
assert call_args["epochs"] == 20
|
assert call_args['epochs'] == 20
|
||||||
assert call_args["verbosity"] == 0
|
assert call_args['verbosity'] == 0
|
||||||
assert call_args["command"] == 'hyperopt'
|
assert call_args['command'] == 'hyperopt'
|
||||||
assert call_args["spaces"] == ['buy']
|
assert call_args['spaces'] == ['buy']
|
||||||
assert call_args["func"] is not None
|
assert call_args['func'] is not None
|
||||||
assert callable(call_args["func"])
|
assert callable(call_args['func'])
|
||||||
|
|
||||||
|
|
||||||
def test_download_data_options() -> None:
|
def test_download_data_options() -> None:
|
||||||
@ -163,10 +163,10 @@ def test_download_data_options() -> None:
|
|||||||
]
|
]
|
||||||
pargs = Arguments(args).get_parsed_arg()
|
pargs = Arguments(args).get_parsed_arg()
|
||||||
|
|
||||||
assert pargs["pairs_file"] == 'file_with_pairs'
|
assert pargs['pairs_file'] == 'file_with_pairs'
|
||||||
assert pargs["datadir"] == 'datadir/directory'
|
assert pargs['datadir'] == 'datadir/directory'
|
||||||
assert pargs["days"] == 30
|
assert pargs['days'] == 30
|
||||||
assert pargs["exchange"] == 'binance'
|
assert pargs['exchange'] == 'binance'
|
||||||
|
|
||||||
|
|
||||||
def test_plot_dataframe_options() -> None:
|
def test_plot_dataframe_options() -> None:
|
||||||
@ -180,10 +180,10 @@ def test_plot_dataframe_options() -> None:
|
|||||||
]
|
]
|
||||||
pargs = Arguments(args).get_parsed_arg()
|
pargs = Arguments(args).get_parsed_arg()
|
||||||
|
|
||||||
assert pargs["indicators1"] == ["sma10", "sma100"]
|
assert pargs['indicators1'] == ['sma10', 'sma100']
|
||||||
assert pargs["indicators2"] == ["macd", "fastd", "fastk"]
|
assert pargs['indicators2'] == ['macd', 'fastd', 'fastk']
|
||||||
assert pargs["plot_limit"] == 30
|
assert pargs['plot_limit'] == 30
|
||||||
assert pargs["pairs"] == ["UNITTEST/BTC"]
|
assert pargs['pairs'] == ['UNITTEST/BTC']
|
||||||
|
|
||||||
|
|
||||||
def test_plot_profit_options() -> None:
|
def test_plot_profit_options() -> None:
|
||||||
@ -191,66 +191,66 @@ def test_plot_profit_options() -> None:
|
|||||||
'plot-profit',
|
'plot-profit',
|
||||||
'-p', 'UNITTEST/BTC',
|
'-p', 'UNITTEST/BTC',
|
||||||
'--trade-source', 'DB',
|
'--trade-source', 'DB',
|
||||||
"--db-url", "sqlite:///whatever.sqlite",
|
'--db-url', 'sqlite:///whatever.sqlite',
|
||||||
]
|
]
|
||||||
pargs = Arguments(args).get_parsed_arg()
|
pargs = Arguments(args).get_parsed_arg()
|
||||||
|
|
||||||
assert pargs["trade_source"] == "DB"
|
assert pargs['trade_source'] == 'DB'
|
||||||
assert pargs["pairs"] == ["UNITTEST/BTC"]
|
assert pargs['pairs'] == ['UNITTEST/BTC']
|
||||||
assert pargs["db_url"] == "sqlite:///whatever.sqlite"
|
assert pargs['db_url'] == 'sqlite:///whatever.sqlite'
|
||||||
|
|
||||||
|
|
||||||
def test_config_notallowed(mocker) -> None:
|
def test_config_notallowed(mocker) -> None:
|
||||||
mocker.patch.object(Path, "is_file", MagicMock(return_value=False))
|
mocker.patch.object(Path, 'is_file', MagicMock(return_value=False))
|
||||||
args = [
|
args = [
|
||||||
'create-userdir',
|
'create-userdir',
|
||||||
]
|
]
|
||||||
pargs = Arguments(args).get_parsed_arg()
|
pargs = Arguments(args).get_parsed_arg()
|
||||||
|
|
||||||
assert "config" not in pargs
|
assert 'config' not in pargs
|
||||||
|
|
||||||
# When file exists:
|
# When file exists:
|
||||||
mocker.patch.object(Path, "is_file", MagicMock(return_value=True))
|
mocker.patch.object(Path, 'is_file', MagicMock(return_value=True))
|
||||||
args = [
|
args = [
|
||||||
'create-userdir',
|
'create-userdir',
|
||||||
]
|
]
|
||||||
pargs = Arguments(args).get_parsed_arg()
|
pargs = Arguments(args).get_parsed_arg()
|
||||||
# config is not added even if it exists, since create-userdir is in the notallowed list
|
# config is not added even if it exists, since create-userdir is in the notallowed list
|
||||||
assert "config" not in pargs
|
assert 'config' not in pargs
|
||||||
|
|
||||||
|
|
||||||
def test_config_notrequired(mocker) -> None:
|
def test_config_notrequired(mocker) -> None:
|
||||||
mocker.patch.object(Path, "is_file", MagicMock(return_value=False))
|
mocker.patch.object(Path, 'is_file', MagicMock(return_value=False))
|
||||||
args = [
|
args = [
|
||||||
'download-data',
|
'download-data',
|
||||||
]
|
]
|
||||||
pargs = Arguments(args).get_parsed_arg()
|
pargs = Arguments(args).get_parsed_arg()
|
||||||
|
|
||||||
assert pargs["config"] is None
|
assert pargs['config'] is None
|
||||||
|
|
||||||
# When file exists:
|
# When file exists:
|
||||||
mocker.patch.object(Path, "is_file", MagicMock(side_effect=[False, True]))
|
mocker.patch.object(Path, 'is_file', MagicMock(side_effect=[False, True]))
|
||||||
args = [
|
args = [
|
||||||
'download-data',
|
'download-data',
|
||||||
]
|
]
|
||||||
pargs = Arguments(args).get_parsed_arg()
|
pargs = Arguments(args).get_parsed_arg()
|
||||||
# config is added if it exists
|
# config is added if it exists
|
||||||
assert pargs["config"] == ['config.json']
|
assert pargs['config'] == ['config.json']
|
||||||
|
|
||||||
|
|
||||||
def test_check_int_positive() -> None:
|
def test_check_int_positive() -> None:
|
||||||
assert check_int_positive("3") == 3
|
assert check_int_positive('3') == 3
|
||||||
assert check_int_positive("1") == 1
|
assert check_int_positive('1') == 1
|
||||||
assert check_int_positive("100") == 100
|
assert check_int_positive('100') == 100
|
||||||
|
|
||||||
with pytest.raises(argparse.ArgumentTypeError):
|
with pytest.raises(argparse.ArgumentTypeError):
|
||||||
check_int_positive("-2")
|
check_int_positive('-2')
|
||||||
|
|
||||||
with pytest.raises(argparse.ArgumentTypeError):
|
with pytest.raises(argparse.ArgumentTypeError):
|
||||||
check_int_positive("0")
|
check_int_positive('0')
|
||||||
|
|
||||||
with pytest.raises(argparse.ArgumentTypeError):
|
with pytest.raises(argparse.ArgumentTypeError):
|
||||||
check_int_positive("3.5")
|
check_int_positive('3.5')
|
||||||
|
|
||||||
with pytest.raises(argparse.ArgumentTypeError):
|
with pytest.raises(argparse.ArgumentTypeError):
|
||||||
check_int_positive("DeadBeef")
|
check_int_positive('DeadBeef')
|
||||||
|
@ -1005,7 +1005,7 @@ def test_pairlist_resolving_fallback(mocker):
|
|||||||
|
|
||||||
args = Arguments(arglist).get_parsed_arg()
|
args = Arguments(arglist).get_parsed_arg()
|
||||||
# Fix flaky tests if config.json exists
|
# Fix flaky tests if config.json exists
|
||||||
args["config"] = None
|
args['config'] = None
|
||||||
|
|
||||||
configuration = Configuration(args, RunMode.OTHER)
|
configuration = Configuration(args, RunMode.OTHER)
|
||||||
config = configuration.get_config()
|
config = configuration.get_config()
|
||||||
|
@ -44,19 +44,19 @@ def test_parse_args_backtesting(mocker) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def test_main_start_hyperopt(mocker) -> None:
|
def test_main_start_hyperopt(mocker) -> None:
|
||||||
mocker.patch.object(Path, "is_file", MagicMock(side_effect=[False, True]))
|
mocker.patch.object(Path, 'is_file', MagicMock(side_effect=[False, True]))
|
||||||
hyperopt_mock = mocker.patch('freqtrade.commands.start_hyperopt', MagicMock())
|
hyperopt_mock = mocker.patch('freqtrade.commands.start_hyperopt', MagicMock())
|
||||||
hyperopt_mock.__name__ = PropertyMock("start_hyperopt")
|
hyperopt_mock.__name__ = PropertyMock('start_hyperopt')
|
||||||
# it's sys.exit(0) at the end of hyperopt
|
# it's sys.exit(0) at the end of hyperopt
|
||||||
with pytest.raises(SystemExit):
|
with pytest.raises(SystemExit):
|
||||||
main(['hyperopt'])
|
main(['hyperopt'])
|
||||||
assert hyperopt_mock.call_count == 1
|
assert hyperopt_mock.call_count == 1
|
||||||
call_args = hyperopt_mock.call_args[0][0]
|
call_args = hyperopt_mock.call_args[0][0]
|
||||||
assert call_args["config"] == ['config.json']
|
assert call_args['config'] == ['config.json']
|
||||||
assert call_args["verbosity"] == 0
|
assert call_args['verbosity'] == 0
|
||||||
assert call_args["command"] == 'hyperopt'
|
assert call_args['command'] == 'hyperopt'
|
||||||
assert call_args["func"] is not None
|
assert call_args['func'] is not None
|
||||||
assert callable(call_args["func"])
|
assert callable(call_args['func'])
|
||||||
|
|
||||||
|
|
||||||
def test_main_fatal_exception(mocker, default_conf, caplog) -> None:
|
def test_main_fatal_exception(mocker, default_conf, caplog) -> None:
|
||||||
|
@ -362,22 +362,22 @@ def test_start_plot_profit(mocker):
|
|||||||
def test_start_plot_profit_error(mocker):
|
def test_start_plot_profit_error(mocker):
|
||||||
|
|
||||||
args = [
|
args = [
|
||||||
"plot-profit",
|
'plot-profit',
|
||||||
"--pairs", "ETH/BTC"
|
'--pairs', 'ETH/BTC'
|
||||||
]
|
]
|
||||||
argsp = get_args(args)
|
argsp = get_args(args)
|
||||||
# Make sure we use no config. Details: #2241
|
# Make sure we use no config. Details: #2241
|
||||||
# not resetting config causes random failures if config.json exists
|
# not resetting config causes random failures if config.json exists
|
||||||
argsp["config"] = []
|
argsp['config'] = []
|
||||||
with pytest.raises(OperationalException):
|
with pytest.raises(OperationalException):
|
||||||
start_plot_profit(argsp)
|
start_plot_profit(argsp)
|
||||||
|
|
||||||
|
|
||||||
def test_plot_profit(default_conf, mocker, testdatadir, caplog):
|
def test_plot_profit(default_conf, mocker, testdatadir, caplog):
|
||||||
default_conf['trade_source'] = 'file'
|
default_conf['trade_source'] = 'file'
|
||||||
default_conf["datadir"] = testdatadir
|
default_conf['datadir'] = testdatadir
|
||||||
default_conf['exportfilename'] = testdatadir / "backtest-result_test_nofile.json"
|
default_conf['exportfilename'] = testdatadir / 'backtest-result_test_nofile.json'
|
||||||
default_conf['pairs'] = ["ETH/BTC", "LTC/BTC"]
|
default_conf['pairs'] = ['ETH/BTC', 'LTC/BTC']
|
||||||
|
|
||||||
profit_mock = MagicMock()
|
profit_mock = MagicMock()
|
||||||
store_mock = MagicMock()
|
store_mock = MagicMock()
|
||||||
|
Loading…
Reference in New Issue
Block a user