GUARDS (can have multiple)
- Define a favorable range (but don't act yet, need to wait for trigger)
- Examples:
- RSI > 20
- fisher_RSI >0.3
- To test, insert into:
- "populate_sell_trend":
- # GUARDS AND TRENDS
- if params.get('sell-GUARD-enabled'):
- conditions.append(dataframe['GUARD'] > params['sell-GUARD-value'])
- "sell_indicator_space":
- Integer(75, 100, name='sell-GUARD-value'), or Real(-0.12, +1.40, name='sell-GUARD-value'),
- Categorical([True, False], name='sell-GUARD-enabled'),
- Note: Above is for sell signal. For buy signal, look at "populate_buy_trend", "indicator_space", and delete "sell-".
TRIGGER (can have only 1 single or 1 combination)
- act (buy/sell) now, provided the range (Guard) is favorable.
- examples:
- closing price cross above/below an indicator (e.g. bollinger band, parabolic sar)
- a pattern emerges (e.g. CDLHAMMER)
- if want to find the single best trigger:
- buy_strategy_generator > populate_buy_trend
- # TRIGGERS
- if 'trigger1' in params:
- if params['trigger1'] == 'bb_lower':
- conditions.append(dataframe['close'] < dataframe['bb_lowerband'])
- if params['trigger1'] == 'macd_cross_signal':
- conditions.append(qtpylib.crossed_above(dataframe['macd'], dataframe['macdsignal']))
- indicator_space
- Categorical(['bb_lower', 'macd_cross_signal'], name='trigger1')
- if want to use multiple triggers (to trigger 1 action) (and does not evaluate which trigger is better):
- (dataframe['bb_lowerband'] > dataframe['close']) &
- (dataframe['CDLHAMMER'] == 100)
- How to pick the best-in-class within multiple triggers. Assume, for a buy signal, wanna pick the best EMA crossover (call it trigger1) and the best HA range (call it trigger2). So:
- buy_strategy_generator > populate_buy_trend
- # TRIGGERS
- if 'trigger1' in params:
- if params['trigger1'] == 'ema3x5':
- conditions.append(qtpylib.crossed_above(dataframe['ema3'], dataframe['ema5']))
- if params['trigger1'] == 'ema3x10':
- conditions.append(qtpylib.crossed_above(dataframe['ema3'], dataframe['ema10']))
- if 'trigger2' in params:
- if params['trigger2'] == 'ha_close>ema3':
- conditions.append(dataframe['ha_close'] > dataframe['ema3'])
- if params['trigger2'] == 'ha_close>ema5':
- conditions.append(dataframe['ha_close'] > dataframe['ema5'])
- indicator_space
- Categorical(['ema3x5', 'ema3x10'], name='trigger1'),
- Categorical(['ha_close>ema3', 'ha_close>ema5'], name='trigger2'),
- For signals which involve "OR" (compared to the usual "AND")
- focus on setting up individual conditions correctly first (using "AND")
- can be verified with a backtest
- finally, introduce the "OR"
- cannot be verified with a backtest
How to read Categorical results
- IF sell_indicator_space :
- Categorical([True, False], name='sell-sar_reversal-enabled'),
- Categorical([True, False], name='sell-macd_cross_signal-enabled'),
- Categorical(['sell-macd_cross_signal', 'sell-sar_reversal'], name='sell-trigger3')
- CASE1
- Hyperopt result:
- 'sell-macd_cross_signal-enabled': True,
- 'sell-sar_reversal-enabled': True,
- 'sell-trigger3': 'sell-macd_cross_signal'
- This means:
- turn on macd
- turn on sar
- so that your (verification) backtest will be accurate.
- CASE2
- Hyperopt result:
- 'sell-macd_cross_signal-enabled': False,
- 'sell-sar_reversal-enabled': True,
- 'sell-trigger3': 'sell-macd_cross_signal'
- THIS MEANS:
- turn on macd
- turn on sar
- so that your (verification) backtest will be accurate.
- CASE3
- Hyperopt result:
- 'sell-macd_cross_signal-enabled': False,
- 'sell-sar_reversal-enabled': True,
- 'sell-trigger3': 'sell-sar_reversal'
- THIS MEANS:
- turn off macd
- turn on sar
- so that your (verification) backtest will be accurate.
- CONCLUSION:
- If an indicator is labelled either "True" or a "sell-trigger", then turn it on. Ignore any "False" or "not a sell-trigger" label that exists simultaneously for that indicator.
Optimizing Bollinger bands (confirmed works? yes)
- strategy file
- populate_indicators
- bollinger2 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
- dataframe['bb_lowerband2'] = bollinger2['lower']
- dataframe['bb_middleband2'] = bollinger2['mid']
- dataframe['bb_upperband2'] = bollinger2['upper']
- bollinger3 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=3)
- dataframe['bb_lowerband3'] = bollinger3['lower']
- dataframe['bb_middleband3'] = bollinger3['mid']
- dataframe['bb_upperband3'] = bollinger3['upper']
- bollinger4 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=4)
- dataframe['bb_lowerband4'] = bollinger4['lower']
- dataframe['bb_middleband4'] = bollinger4['mid']
- dataframe['bb_upperband4'] = bollinger4['upper']
- populate_buy_trend (if required by strategy)
- (dataframe['close'] < dataframe['bb_lowerband2'])
- populate_sell_trend (if required by strategy)
- (dataframe['close'] > dataframe['bb_lowerband1'])
- hyperopt file
- buy side (if required by strategy)
- buy_strategy_generator > populate_buy_trend
- # TRIGGERS
- if 'trigger' in params:
- if params['trigger'] == 'bb_lower2':
- conditions.append(dataframe['close'] < dataframe['bb_lowerband2'])
- if params['trigger'] == 'bb_lower3':
- conditions.append(dataframe['close'] < dataframe['bb_lowerband3'])
- if params['trigger'] == 'bb_lower4':
- conditions.append(dataframe['close'] < dataframe['bb_lowerband4'])
- indicator_space
- Categorical(['bb_lower2', 'bb_lower3', 'bb_lower4'], name='trigger')
- sell side (if required by strategy)
- sell_strategy_generator > populate_sell_trend
- (similar to populate_buy_trend)
- sell_indicator_space
- (similar to indicator_space)
Optimising RSI (confirmed works? yes)
- strategy file
- populate_indicators
- dataframe['rsi'] = ta.RSI(dataframe)
- populate_buy_trend (if required by strategy)
- (dataframe['rsi'] < 20) & (use guard if inequality?)
- populate_sell_trend (if required by strategy)
- (qtpylib.crossed_above(dataframe['rsi'], 98)) & (use trigger if cross?)
- hyperopt file
- buy side (if required by strategy)
- buy_strategy_generator > populate_buy_trend
- # GUARDS AND TRENDS
- if params.get('rsi-enabled'):
- conditions.append(dataframe['rsi'] < params['rsi-value'])
- indicator_space
- Integer(5, 50, name='rsi-value'),
- Categorical([True, False], name='rsi-enabled'),
- sell side (if required by strategy)
- sell_strategy_generator > populate_sell_trend
- #TRIGGERS
- if params.get('sell-rsi-enabled'):
- conditions.append(dataframe['rsi'] > params['sell-rsi-value'])
- sell_indicator_space
- Integer(60, 100, name='sell-rsi-value'),
- Categorical([True, False], name='sell-rsi-enabled'),
Optimising Stochastic Indicator's "SlowK" (confirmed works? yes)
- strategy file
- populate_indicators
- stoch = ta.STOCH(dataframe)
- dataframe['slowd'] = stoch['slowd']
- dataframe['slowk'] = stoch['slowk']
- populate_buy_trend (if required by strategy)
- (dataframe['slowk'] < 20) &
- hyperopt file
- buy side (if required by strategy)
- buy_strategy_generator > populate_buy_trend
- # GUARDS AND TRENDS
- if params.get('slowk-enabled'):
- conditions.append(dataframe['slowk'] < params['slowk-value'])
- indicator_space
- Integer(0, 50, name='slowk-value'),
- Categorical([True, False], name='slowk-enabled'),
Ref1: https://www.ig.com/uk/trading-strategies/16-candlestick-patterns-every-trader-should-know-180615
- strategy file
- populate_indicators
- dataframe['CDLHAMMER'] = ta.CDLHAMMER(dataframe)
- populate_buy_trend
- (dataframe['CDLHAMMER'] == 100) &
- hyperopt file
- buy side (if required by strategy)
- buy_strategy_generator > populate_buy_trend
- #GUARDS
- if params.get('CDLHAMMER-enabled'):
- conditions.append(dataframe['CDLHAMMER'] == 100)
- indicator_space
- Categorical([True, False], name='CDLHAMMER-enabled'),
- strategy file
- populate_indicators
- dataframe['sar'] = ta.SAR(dataframe)
- populate_sell_trend
- (qtpylib.crossed_above(dataframe['sar'], dataframe['close'])) &
- hyperopt file
- buy side (if required by strategy) (untested)
- buy_strategy_generator > populate_buy_trend
- # TRIGGERS
- if 'trigger' in params:
- if params['trigger'] == 'sar_reversal':
- conditions.append(qtpylib.crossed_above(
- dataframe['close'], dataframe['sar']
- ))
- sell side (if required by strategy) (confirmed works? yes)
- sell_strategy_generator > populate_sell_trend
- #GUARDS
- if params.get('sell-sar_reversal-enabled'):
- conditions.append(qtpylib.crossed_above(dataframe['sar'], dataframe['close']))
- sell_indicator_space
- Categorical([True, False], name='sell-sar_reversal-enabled'),
Optimising Fisher RSI (confirmed works? yes)
- strategy file
- populate_indicators
- adj_rsi = 0.1 * (dataframe['rsi'] - 50)
- dataframe['fisher_rsi'] = (np.exp(2 * adj_rsi) - 1) / (np.exp(2 * adj_rsi) + 1)
- populate_sell_trend
- (dataframe['fisher_rsi'] > 0.3) &
- hyperopt file
- sell side (if required by strategy) (confirmed works? yes)
- sell_strategy_generator > populate_sell_trend
- # GUARDS AND TRENDS
- if params.get('sell-fisher_rsi-enabled'):
- conditions.append(dataframe['fisher_rsi'] > params['sell-fisher_rsi-value'])
- sell_indicator_space (confirmed works? yes)
- Real(-0.99990920426, +0.99990920426, name='sell-fisher_rsi-value'),
- Categorical([True, False], name='sell-fisher_rsi-enabled'),
After hyperopt process is completed: (1) Note the optimized "rsi" value in the hyperopt results (e.g. 'rsi-value': 30,); then (2) manually calculate the optimized "fisher_rsi" (i.e. fisher_rsi=-0.9640275801) (use https://www.desmos.com/scientific); then (3) update the value in "populate_sell_trend" (i.e. (dataframe['fisher_rsi'] > -0.9640275801) &)
Optimising EMA (exponential moving average) (confirmed works? yes)
- strategy file
- populate_indicators
- dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3)
- dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5)
- dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10)
- dataframe['ema20'] = ta.EMA(dataframe, timeperiod=20)
- dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50)
- dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100)
- populate_buy_trend (if required by strategy)
- qtpylib.crossed_above(dataframe['ema20'], dataframe['ema50']) &
- populate_sell_trend (if required by strategy)
- qtpylib.crossed_above(dataframe['ema50'], dataframe['ema100']) &
- hyperopt file
- buy side (if required by strategy)
- buy_strategy_generator > populate_buy_trend
- # TRIGGERS
- if 'trigger' in params:
- if params['trigger'] == 'ema3x5':
- conditions.append(qtpylib.crossed_above(dataframe['ema3'], dataframe['ema5']))
- if params['trigger'] == 'ema3x10':
- conditions.append(qtpylib.crossed_above(dataframe['ema3'], dataframe['ema10']))
- if params['trigger'] == 'ema3x20':
- conditions.append(qtpylib.crossed_above(dataframe['ema3'], dataframe['ema20']))
- if params['trigger'] == 'ema3x50':
- conditions.append(qtpylib.crossed_above(dataframe['ema3'], dataframe['ema50']))
- if params['trigger'] == 'ema3x100':
- conditions.append(qtpylib.crossed_above(dataframe['ema3'], dataframe['ema100']))
- if params['trigger'] == 'ema5x10':
- conditions.append(qtpylib.crossed_above(dataframe['ema5'], dataframe['ema10']))
- if params['trigger'] == 'ema5x20':
- conditions.append(qtpylib.crossed_above(dataframe['ema5'], dataframe['ema20']))
- if params['trigger'] == 'ema5x50':
- conditions.append(qtpylib.crossed_above(dataframe['ema5'], dataframe['ema50']))
- if params['trigger'] == 'ema5x100':
- conditions.append(qtpylib.crossed_above(dataframe['ema5'], dataframe['ema100']))
- if params['trigger'] == 'ema10x20':
- conditions.append(qtpylib.crossed_above(dataframe['ema10'], dataframe['ema20']))
- if params['trigger'] == 'ema10x50':
- conditions.append(qtpylib.crossed_above(dataframe['ema10'], dataframe['ema50']))
- if params['trigger'] == 'ema10x100':
- conditions.append(qtpylib.crossed_above(dataframe['ema10'], dataframe['ema100']))
- if params['trigger'] == 'ema20x50':
- conditions.append(qtpylib.crossed_above(dataframe['ema20'], dataframe['ema50']))
- if params['trigger'] == 'ema20x100':
- conditions.append(qtpylib.crossed_above(dataframe['ema20'], dataframe['ema100']))
- if params['trigger'] == 'ema50x100':
- conditions.append(qtpylib.crossed_above(dataframe['ema50'], dataframe['ema100']))
- indicator_space
- Categorical(['ema3x5', 'ema3x10', 'ema3x20', 'ema3x50', 'ema3x100', 'ema5x10', 'ema5x20', 'ema5x50', 'ema5x100', 'ema10x20', 'ema10x50', 'ema10x100', 'ema20x50', 'ema20x100', 'ema50x100'], name='trigger')
- sell side (if required by strategy)
- sell_strategy_generator > populate_sell_trend
- # TRIGGERS
- if 'sell-trigger' in params:
- if params['sell-trigger'] == 'ema3x5':
- conditions.append(qtpylib.crossed_above(dataframe['ema3'], dataframe['ema5']))
- if params['sell-trigger'] == 'ema3x10':
- conditions.append(qtpylib.crossed_above(dataframe['ema3'], dataframe['ema10']))
- if params['sell-trigger'] == 'ema3x20':
- conditions.append(qtpylib.crossed_above(dataframe['ema3'], dataframe['ema20']))
- if params['sell-trigger'] == 'ema3x50':
- conditions.append(qtpylib.crossed_above(dataframe['ema3'], dataframe['ema50']))
- if params['sell-trigger'] == 'ema3x100':
- conditions.append(qtpylib.crossed_above(dataframe['ema3'], dataframe['ema100']))
- if params['sell-trigger'] == 'ema5x10':
- conditions.append(qtpylib.crossed_above(dataframe['ema5'], dataframe['ema10']))
- if params['sell-trigger'] == 'ema5x20':
- conditions.append(qtpylib.crossed_above(dataframe['ema5'], dataframe['ema20']))
- if params['sell-trigger'] == 'ema5x50':
- conditions.append(qtpylib.crossed_above(dataframe['ema5'], dataframe['ema50']))
- if params['sell-trigger'] == 'ema5x100':
- conditions.append(qtpylib.crossed_above(dataframe['ema5'], dataframe['ema100']))
- if params['sell-trigger'] == 'ema10x20':
- conditions.append(qtpylib.crossed_above(dataframe['ema10'], dataframe['ema20']))
- if params['sell-trigger'] == 'ema10x50':
- conditions.append(qtpylib.crossed_above(dataframe['ema10'], dataframe['ema50']))
- if params['sell-trigger'] == 'ema10x100':
- conditions.append(qtpylib.crossed_above(dataframe['ema10'], dataframe['ema100']))
- if params['sell-trigger'] == 'ema20x50':
- conditions.append(qtpylib.crossed_above(dataframe['ema20'], dataframe['ema50']))
- if params['sell-trigger'] == 'ema20x100':
- conditions.append(qtpylib.crossed_above(dataframe['ema20'], dataframe['ema100']))
- if params['sell-trigger'] == 'ema50x100':
- conditions.append(qtpylib.crossed_above(dataframe['ema50'], dataframe['ema100']))
- sell_indicator_space
- Categorical(['ema3x5', 'ema3x10', 'ema3x20', 'ema3x50', 'ema3x100', 'ema5x10', 'ema5x20', 'ema5x50', 'ema5x100', 'ema10x20', 'ema10x50', 'ema10x100', 'ema20x50', 'ema20x100', 'ema50x100'], name='sell-trigger')
do you have strategy file with this?
ReplyDelete