prototype of custom hyperopt tool finished
This commit is contained in:
parent
1eaff121bc
commit
18e6cd9c9b
@ -13,7 +13,6 @@ from freqtrade.commands.data_commands import (start_convert_data, start_download
|
|||||||
from freqtrade.commands.deploy_commands import (start_create_userdir, start_install_ui,
|
from freqtrade.commands.deploy_commands import (start_create_userdir, start_install_ui,
|
||||||
start_new_hyperopt, start_new_strategy)
|
start_new_hyperopt, start_new_strategy)
|
||||||
from freqtrade.commands.automation_commands import start_build_hyperopt
|
from freqtrade.commands.automation_commands import start_build_hyperopt
|
||||||
|
|
||||||
from freqtrade.commands.hyperopt_commands import start_hyperopt_list, start_hyperopt_show
|
from freqtrade.commands.hyperopt_commands import start_hyperopt_list, start_hyperopt_show
|
||||||
from freqtrade.commands.list_commands import (start_list_exchanges, start_list_hyperopts,
|
from freqtrade.commands.list_commands import (start_list_exchanges, start_list_hyperopts,
|
||||||
start_list_markets, start_list_strategies,
|
start_list_markets, start_list_strategies,
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import ast
|
||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
from typing import Any, Dict
|
||||||
@ -6,40 +7,141 @@ from freqtrade.constants import USERPATH_HYPEROPTS
|
|||||||
from freqtrade.exceptions import OperationalException
|
from freqtrade.exceptions import OperationalException
|
||||||
from freqtrade.state import RunMode
|
from freqtrade.state import RunMode
|
||||||
from freqtrade.configuration import setup_utils_configuration
|
from freqtrade.configuration import setup_utils_configuration
|
||||||
from freqtrade.misc import render_template, render_template_with_fallback
|
from freqtrade.misc import render_template
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
'''
|
||||||
|
TODO
|
||||||
|
-make the code below more dynamic with a large list of indicators and aims
|
||||||
|
-buy_space integer values variation based on aim(later deep learning)
|
||||||
|
-add --mode , see notes
|
||||||
|
-when making the strategy reading tool, make sure that the populate indicators gets copied to here
|
||||||
|
'''
|
||||||
|
|
||||||
def deploy_custom_hyperopt(hyperopt_name: str, hyperopt_path: Path, buy_indicators: str, sell_indicators: str) -> None:
|
POSSIBLE_GUARDS = ["rsi", "mfi", "fastd"]
|
||||||
|
POSSIBLE_TRIGGERS = ["bb_lowerband", "bb_upperband"]
|
||||||
|
POSSIBLE_VALUES = {"above": ">", "below": "<"}
|
||||||
|
|
||||||
|
|
||||||
|
def build_hyperopt_buyelements(buy_indicators: Dict[str, str]):
|
||||||
|
"""
|
||||||
|
Build the arguments with the placefillers for the buygenerator
|
||||||
|
"""
|
||||||
|
buy_guards = ""
|
||||||
|
buy_triggers = ""
|
||||||
|
buy_space = ""
|
||||||
|
|
||||||
|
for indicator in buy_indicators:
|
||||||
|
# Error handling
|
||||||
|
if not indicator in POSSIBLE_GUARDS and not indicator in POSSIBLE_TRIGGERS:
|
||||||
|
raise OperationalException(
|
||||||
|
f"`{indicator}` is not part of the available indicators. The current options are {POSSIBLE_GUARDS + POSSIBLE_TRIGGERS}.")
|
||||||
|
elif not buy_indicators[indicator] in POSSIBLE_VALUES:
|
||||||
|
raise OperationalException(
|
||||||
|
f"`{buy_indicators[indicator]}` is not part of the available indicator options. The current options are {POSSIBLE_VALUES}.")
|
||||||
|
# If the indicator is a guard
|
||||||
|
elif indicator in POSSIBLE_GUARDS:
|
||||||
|
# get the symbol corrosponding to the value
|
||||||
|
aim = POSSIBLE_VALUES[buy_indicators[indicator]]
|
||||||
|
|
||||||
|
# add the guard to its argument
|
||||||
|
buy_guards += f"if '{indicator}-enabled' in params and params['{indicator}-enabled']: conditions.append(dataframe['{indicator}'] {aim} params['{indicator}-value'])"
|
||||||
|
|
||||||
|
# add the space to its argument
|
||||||
|
buy_space += f"Integer(10, 90, name='{indicator}-value'), Categorical([True, False], name='{indicator}-enabled'),"
|
||||||
|
# If the indicator is a trigger
|
||||||
|
elif indicator in POSSIBLE_TRIGGERS:
|
||||||
|
# get the symbol corrosponding to the value
|
||||||
|
aim = POSSIBLE_VALUES[buy_indicators[indicator]]
|
||||||
|
|
||||||
|
# add the trigger to its argument
|
||||||
|
buy_triggers += f"if params['trigger'] == '{indicator}': conditions.append(dataframe['{indicator}'] {aim} dataframe['close'])"
|
||||||
|
|
||||||
|
# Final line of indicator space makes all triggers
|
||||||
|
|
||||||
|
buy_space += "Categorical(["
|
||||||
|
|
||||||
|
# adding all triggers to the list
|
||||||
|
for indicator in buy_indicators:
|
||||||
|
if indicator in POSSIBLE_TRIGGERS:
|
||||||
|
buy_space += f"'{indicator}', "
|
||||||
|
|
||||||
|
# Deleting the last ", "
|
||||||
|
buy_space = buy_space[:-2]
|
||||||
|
buy_space += "], name='trigger')"
|
||||||
|
|
||||||
|
return {"buy_guards": buy_guards, "buy_triggers": buy_triggers, "buy_space": buy_space}
|
||||||
|
|
||||||
|
|
||||||
|
def build_hyperopt_sellelements(sell_indicators: Dict[str, str]):
|
||||||
|
"""
|
||||||
|
Build the arguments with the placefillers for the sellgenerator
|
||||||
|
"""
|
||||||
|
sell_guards = ""
|
||||||
|
sell_triggers = ""
|
||||||
|
sell_space = ""
|
||||||
|
|
||||||
|
for indicator in sell_indicators:
|
||||||
|
# Error handling
|
||||||
|
if not indicator in POSSIBLE_GUARDS and not indicator in POSSIBLE_TRIGGERS:
|
||||||
|
raise OperationalException(
|
||||||
|
f"`{indicator}` is not part of the available indicators. The current options are {POSSIBLE_GUARDS + POSSIBLE_TRIGGERS}.")
|
||||||
|
elif not sell_indicators[indicator] in POSSIBLE_VALUES:
|
||||||
|
raise OperationalException(
|
||||||
|
f"`{sell_indicators[indicator]}` is not part of the available indicator options. The current options are {POSSIBLE_VALUES}.")
|
||||||
|
# If indicator is a guard
|
||||||
|
elif indicator in POSSIBLE_GUARDS:
|
||||||
|
# get the symbol corrosponding to the value
|
||||||
|
aim = POSSIBLE_VALUES[sell_indicators[indicator]]
|
||||||
|
|
||||||
|
# add the guard to its argument
|
||||||
|
sell_guards += f"if '{indicator}-enabled' in params and params['sell-{indicator}-enabled']: conditions.append(dataframe['{indicator}'] {aim} params['sell-{indicator}-value'])"
|
||||||
|
|
||||||
|
# add the space to its argument
|
||||||
|
sell_space += f"Integer(10, 90, name='sell-{indicator}-value'), Categorical([True, False], name='sell-{indicator}-enabled'),"
|
||||||
|
# If the indicator is a trigger
|
||||||
|
elif indicator in POSSIBLE_TRIGGERS:
|
||||||
|
# get the symbol corrosponding to the value
|
||||||
|
aim = POSSIBLE_VALUES[sell_indicators[indicator]]
|
||||||
|
|
||||||
|
# add the trigger to its argument
|
||||||
|
sell_triggers += f"if params['sell-trigger'] == 'sell-{indicator}': conditions.append(dataframe['{indicator}'] {aim} dataframe['close'])"
|
||||||
|
|
||||||
|
# Final line of indicator space makes all triggers
|
||||||
|
|
||||||
|
sell_space += "Categorical(["
|
||||||
|
|
||||||
|
# Adding all triggers to the list
|
||||||
|
for indicator in sell_indicators:
|
||||||
|
if indicator in POSSIBLE_TRIGGERS:
|
||||||
|
sell_space += f"'sell-{indicator}', "
|
||||||
|
|
||||||
|
# Deleting the last ", "
|
||||||
|
sell_space = sell_space[:-2]
|
||||||
|
sell_space += "], name='trigger')"
|
||||||
|
|
||||||
|
return {"sell_guards": sell_guards, "sell_triggers": sell_triggers, "sell_space": sell_space}
|
||||||
|
|
||||||
|
|
||||||
|
def deploy_custom_hyperopt(hyperopt_name: str, hyperopt_path: Path, buy_indicators: Dict[str, str], sell_indicators: Dict[str, str]) -> None:
|
||||||
"""
|
"""
|
||||||
Deploys a custom hyperopt template to hyperopt_path
|
Deploys a custom hyperopt template to hyperopt_path
|
||||||
TODO make the code below more dynamic with a large list of indicators instead of a few templates
|
|
||||||
"""
|
"""
|
||||||
fallback = 'full'
|
|
||||||
buy_guards = render_template_with_fallback(
|
|
||||||
templatefile=f"subtemplates/hyperopt_buy_guards_{subtemplate}.j2",
|
|
||||||
templatefallbackfile=f"subtemplates/hyperopt_buy_guards_{fallback}.j2",
|
|
||||||
)
|
|
||||||
sell_guards = render_template_with_fallback(
|
|
||||||
templatefile=f"subtemplates/hyperopt_sell_guards_{subtemplate}.j2",
|
|
||||||
templatefallbackfile=f"subtemplates/hyperopt_sell_guards_{fallback}.j2",
|
|
||||||
)
|
|
||||||
buy_space = render_template_with_fallback(
|
|
||||||
templatefile=f"subtemplates/hyperopt_buy_space_{subtemplate}.j2",
|
|
||||||
templatefallbackfile=f"subtemplates/hyperopt_buy_space_{fallback}.j2",
|
|
||||||
)
|
|
||||||
sell_space = render_template_with_fallback(
|
|
||||||
templatefile=f"subtemplates/hyperopt_sell_space_{subtemplate}.j2",
|
|
||||||
templatefallbackfile=f"subtemplates/hyperopt_sell_space_{fallback}.j2",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
# Build the arguments for the buy and sell generators
|
||||||
|
buy_args = build_hyperopt_buyelements(buy_indicators)
|
||||||
|
sell_args = build_hyperopt_sellelements(sell_indicators)
|
||||||
|
|
||||||
|
# Build the final template
|
||||||
strategy_text = render_template(templatefile='base_hyperopt.py.j2',
|
strategy_text = render_template(templatefile='base_hyperopt.py.j2',
|
||||||
arguments={"hyperopt": hyperopt_name,
|
arguments={"hyperopt": hyperopt_name,
|
||||||
"buy_guards": buy_guards,
|
"buy_guards": buy_args["buy_guards"],
|
||||||
"sell_guards": sell_guards,
|
"buy_triggers": buy_args["buy_triggers"],
|
||||||
"buy_space": buy_space,
|
"buy_space": buy_args["buy_space"],
|
||||||
"sell_space": sell_space,
|
"sell_guards": sell_args["sell_guards"],
|
||||||
|
"sell_triggers": sell_args["sell_triggers"],
|
||||||
|
"sell_space": sell_args["sell_space"],
|
||||||
})
|
})
|
||||||
|
|
||||||
logger.info(f"Writing custom hyperopt to `{hyperopt_path}`.")
|
logger.info(f"Writing custom hyperopt to `{hyperopt_path}`.")
|
||||||
@ -67,5 +169,9 @@ def start_build_hyperopt(args: Dict[str, Any]) -> None:
|
|||||||
if new_path.exists():
|
if new_path.exists():
|
||||||
raise OperationalException(f"`{new_path}` already exists. "
|
raise OperationalException(f"`{new_path}` already exists. "
|
||||||
"Please choose another Hyperopt Name.")
|
"Please choose another Hyperopt Name.")
|
||||||
|
|
||||||
|
buy_indicators = ast.literal_eval(args['buy_indicators'])
|
||||||
|
sell_indicators = ast.literal_eval(args['sell_indicators'])
|
||||||
|
|
||||||
deploy_custom_hyperopt(args['hyperopt'], new_path,
|
deploy_custom_hyperopt(args['hyperopt'], new_path,
|
||||||
args['buy_indicators'], args['sell_indicators'])
|
buy_indicators, sell_indicators)
|
||||||
|
@ -275,6 +275,19 @@ AVAILABLE_CLI_OPTIONS = {
|
|||||||
'Example: `--hyperopt-filename=hyperopt_results_2020-09-27_16-20-48.pickle`',
|
'Example: `--hyperopt-filename=hyperopt_results_2020-09-27_16-20-48.pickle`',
|
||||||
metavar='FILENAME',
|
metavar='FILENAME',
|
||||||
),
|
),
|
||||||
|
# Automation
|
||||||
|
"buy_indicators": Arg(
|
||||||
|
'-b', '--buy-indicators',
|
||||||
|
help='Specify the buy indicators the hyperopt should build. '
|
||||||
|
'Example: --buy-indicators `{"rsi":"above","bb_lowerband":"below"}`',
|
||||||
|
metavar='DICT',
|
||||||
|
),
|
||||||
|
"sell_indicators": Arg(
|
||||||
|
'-s', '--sell-indicators',
|
||||||
|
help='Specify the sell indicators the hyperopt should build. '
|
||||||
|
'Example: --sell-indicators `{"rsi":"above","bb_lowerband":"below"}`',
|
||||||
|
metavar='DICT',
|
||||||
|
),
|
||||||
# List exchanges
|
# List exchanges
|
||||||
"print_one_column": Arg(
|
"print_one_column": Arg(
|
||||||
'-1', '--one-column',
|
'-1', '--one-column',
|
||||||
@ -439,15 +452,6 @@ AVAILABLE_CLI_OPTIONS = {
|
|||||||
help='Specify the list of trade ids.',
|
help='Specify the list of trade ids.',
|
||||||
nargs='+',
|
nargs='+',
|
||||||
),
|
),
|
||||||
# automation
|
|
||||||
"buy_indicators": Arg(
|
|
||||||
'-b', '--buy-indicators',
|
|
||||||
help='Specify the buy indicators the hyperopt should build.'
|
|
||||||
),
|
|
||||||
"sell_indicators": Arg(
|
|
||||||
'-s', '--sell-indicators',
|
|
||||||
help='Specify the buy indicators the hyperopt should build.'
|
|
||||||
),
|
|
||||||
# hyperopt-list, hyperopt-show
|
# hyperopt-list, hyperopt-show
|
||||||
"hyperopt_list_profitable": Arg(
|
"hyperopt_list_profitable": Arg(
|
||||||
'--profitable',
|
'--profitable',
|
||||||
|
@ -55,16 +55,7 @@ class {{ hyperopt }}(IHyperOpt):
|
|||||||
|
|
||||||
# TRIGGERS
|
# TRIGGERS
|
||||||
if 'trigger' in params:
|
if 'trigger' in params:
|
||||||
if params['trigger'] == 'bb_lower':
|
{{ buy_triggers | indent(16) }}
|
||||||
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']
|
|
||||||
))
|
|
||||||
|
|
||||||
# Check that the candle had volume
|
# Check that the candle had volume
|
||||||
conditions.append(dataframe['volume'] > 0)
|
conditions.append(dataframe['volume'] > 0)
|
||||||
@ -103,16 +94,7 @@ class {{ hyperopt }}(IHyperOpt):
|
|||||||
|
|
||||||
# TRIGGERS
|
# TRIGGERS
|
||||||
if 'sell-trigger' in params:
|
if 'sell-trigger' in params:
|
||||||
if params['sell-trigger'] == 'sell-bb_upper':
|
{{ sell_triggers | indent(16) }}
|
||||||
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']
|
|
||||||
))
|
|
||||||
|
|
||||||
# Check that the candle had volume
|
# Check that the candle had volume
|
||||||
conditions.append(dataframe['volume'] > 0)
|
conditions.append(dataframe['volume'] > 0)
|
||||||
|
Loading…
Reference in New Issue
Block a user