Wednesday, January 13, 2021

Hyperopt Notes

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'),
Optimising CDLHAMMER (CanDLestick Hammer) (confirmed works? yes)
  • 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'),
Optimising Parabolic SAR (stop and reverse) (confirmed works? yes)
  • 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')

    Friday, January 8, 2021

    PC acting weird

    •  Monitor shows "no signal"
      • graphic card spoilt (confirm by pluggin monitor into another PC)
      • cable spoilt (confirm by using different cable)
      • monitor spoilt (confirm by using different monitor)
    • No electricity supply to Keyboard/mouse (which uses USB port) 
      • Test keyboard/mouse on a different PC
      • Test a different keyboard/mouse on the current PC
      • Could be casing problem? (bring to hardware shop to check connections)

    Popular Posts