I wrote a optimization code for scanning parameters of indicator (customized one) for Hyperopt optimization. The indicator is based on a nonlinear smoothing filter on momentum. Buy-sell conditions are sign changes of its first derivative. It takes two parameters, ie. length, power. I compare backtest results on both Freqtrade and Tradingview to validate that indicator working properly.
For optimization I used this approach: link , basically scan two parameters for certain ranges. However, I could not get any result from Hyperopt optimization. The code is below. Thanks in advance,
Best,
Hikmet
Code:
from pandas import DataFrame
from typing import Dict, Any, Callable, List
from functools import reduce
from skopt.space import Categorical, Dimension, Integer, Real
import freqtrade.vendor.qtpylib.indicators as qtpylib
from freqtrade.optimize.hyperopt_interface import IHyperOpt
jleni = 24
jlenf = 25
jpowi = 10
jpowf = 11
class jnonlinopt(IHyperOpt):
@staticmethod
def populate_indicators(dataframe: DataFrame, metadata: dict) -> DataFrame:
for lenrange in range(jleni, jlenf):
for powrange in range(jpowi, jpowf):
dataframe[f'len({lenrange})pow({powrange})'] = qtpylib.jnonlin(dataframe['close'], lenrange, powrange)
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 = []
# TRIGGERS
if 'trigger' in params:
for lenrange in range(jleni, jlenf):
for powrange in range(jpowi, jpowf):
if params['trigger'] == f'len({lenrange})pow({powrange})':
conditions.append(dataframe[f'len({lenrange})pow({powrange})']>dataframe[f'len({lenrange})pow({powrange})'].shift(1)
& dataframe[f'len({lenrange})pow({powrange})'].shift(1)<dataframe[f'len({lenrange})pow({powrange})'].shift(2))
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]:
buyTriggerList = []
for lenrange in range(jleni, jlenf):
for powrange in range(jpowi, jpowf):
buyTriggerList.append(
f'lenrange_({lenrange})_powrange_({powrange}')
return [
Categorical(buyTriggerList, 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
"""
# print(params)
conditions = []
# TRIGGERS
if 'sell-trigger' in params:
for lenrange in range(jleni, jlenf):
for powrange in range(jpowi, jpowf):
if params['trigger'] == f'len({lenrange})pow({powrange})':
conditions.append(dataframe[f'len({lenrange})pow({powrange})']<dataframe[f'len({lenrange})pow({powrange})'].shift(1)
& dataframe[f'len({lenrange})pow({powrange})'].shift(1)>dataframe[f'len({lenrange})pow({powrange})'].shift(2))
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
"""
sellTriggerList = []
for lenrange in range(jleni, jlenf):
for powrange in range(jpowi, jpowf):
sellTriggerList.append(
f'lenrange_({lenrange})_powrange_({powrange}')
return [
Categorical(sellTriggerList, name='sell-trigger')
]
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
(dataframe['jnonlin'] > dataframe['jnonlin'].shift(1) )
& (dataframe['jnonlin'].shift(1) < dataframe['jnonlin'].shift(2) )
),
'buy'] = 1
return dataframe
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Based on TA indicators. Should be a copy of from strategy
must align to populate_indicators in this file
Only used when --spaces does not include sell
"""
dataframe.loc[
(
(dataframe['jnonlin'] < dataframe['jnonlin'].shift(1) )
& (dataframe['jnonlin'].shift(1) > dataframe['jnonlin'].shift(2) )
),
'sell'] = 1
return dataframe
@staticmethod
def generate_roi_table(params: Dict) -> Dict[int, float]:
"""
Generate the ROI table that will be used by Hyperopt
"""
roi_table = {}
roi_table[0] = params['roi_p1'] + params['roi_p2'] + params['roi_p3']
roi_table[params['roi_t3']] = params['roi_p1'] + params['roi_p2']
roi_table[params['roi_t3'] + params['roi_t2']] = params['roi_p1']
roi_table[params['roi_t3'] + params['roi_t2'] + params['roi_t1']] = 0
return roi_table
@staticmethod
def stoploss_space() -> List[Dimension]:
"""
Stoploss Value to search
"""
return [
Real(-0.5, -0.02, name='stoploss'),
]
@staticmethod
def roi_space() -> List[Dimension]:
"""
Values to search for each ROI steps
"""
return [
Integer(10, 120, name='roi_t1'),
Integer(10, 60, name='roi_t2'),
Integer(10, 40, name='roi_t3'),
Real(0.01, 0.04, name='roi_p1'),
Real(0.01, 0.07, name='roi_p2'),
Real(0.01, 0.20, name='roi_p3'),
]
Dear community,
I wrote a optimization code for scanning parameters of indicator (customized one) for Hyperopt optimization. The indicator is based on a nonlinear smoothing filter on momentum. Buy-sell conditions are sign changes of its first derivative. It takes two parameters, ie. length, power. I compare backtest results on both Freqtrade and Tradingview to validate that indicator working properly.
For optimization I used this approach: link , basically scan two parameters for certain ranges. However, I could not get any result from Hyperopt optimization. The code is below. Thanks in advance, Best, Hikmet
Code: