[Share] RSI-BB-ADX with candlebatcher
#1
This is more a share of the method I'm using for candle batching than of the strategy, but as Tommies RSI strat is rather excellent and so widely known it seemed a good demonstrator.

This strategy runs on 1 minute candles and batches them in the update function. 
The less obvious bit is that instead of keeping one copy of each indicator, it keeps an array of each indicator as long as the candle size for that indicator. Each new minute candle, the next indicator in the array is updated and read. 
The upshot of this is that each minute there is an up to date result of the longer term indicator, allowing far more accurate entry and exit points checked every minute, instead of every 5, 10, 30, 60 etc minutes. This also makes a strategy less sensitive to start time - although it still makes more of a difference than I'd expect!

The timeframe for each indicator is also independent so different candle sizes can be used for bear and bull market indicators - however the indicator candle size and indicator period do become a little interchangeable as they're both changing the amount of time that the indicator is watching the market over.

Other benefits of running at 1 minute is that any stop losses or take profits that you might add can be checked that much more frequently, so are that much more useful at catching quick market movements.

Downsides:
> As with any strategy running on very short timeframes trying to tune it with GA style optimisers can results in huge profits with hundreds of trades per day that will perform absolutely miserably if ran live as the orders simply can't be filled. Tuning requires a little more understanding of what the strategy is doing and inputting sensible parameters.
> Gekko currently has a limitation on the number of candles it can pre-seed a strategy with of around 4000. When running at 1 minute, this is 2.7 days of history so you need to shrink those long SMAs


So - here's a quick example backtest from 6 months history on an alt, with Tommie's original strategy first, candlebatched second. Both have exactly the same parameters, as in the TOML file below.

Original:
[Image: DJkIwSX.png]

Candlebatched:
[Image: fBuUMVB.png]
Paper trading settings are at their defaults. These two are purely intended as a relative comparison. I obviously can't promise any results but hope it shows that there is potential!


I'm sharing this under the same CC-BY-SA 4.0 license that Tommie shared his under - I learnt a lot from that bit of code, so hopefully giving a little back.
Run the strategy in 1 minute candles in gekko and specify the candle sizes you want each indicator to run at with the timeframe parameter in the TOML.

TOML: Github
Code:
# SMA INDICATOR
SMA_long = 1000
SMA_short = 50
SMA_Timeframe = 10

# RSI BULL / BEAR
BULL_RSI = 10
BULL_RSI_high = 80
BULL_RSI_low = 45
BULL_RSI_Timeframe = 10

BEAR_RSI = 15
BEAR_RSI_high = 50
BEAR_RSI_low = 20
BEAR_RSI_Timeframe = 10

# MODIFY RSI (depending on ADX)
BULL_MOD_high = 5
BULL_MOD_low = -5
BEAR_MOD_high = 15
BEAR_MOD_low = -5

# ADX
ADX = 3
ADX_high = 70
ADX_low = 50
ADX_Timeframe = 10

Strategy: Github
Code:
/*
    Adapted to run on 1 Minute candles with candle batching
    by Gryphon/RJPGriffin Nov'18

    RSI Bull and Bear + ADX modifier
    1. Use different RSI-strategies depending on a longer trend
    2. But modify this slighly if shorter BULL/BEAR is detected
    -
    (CC-BY-SA 4.0) Tommie Hansen
    https://creativecommons.org/licenses/by-sa/4.0/
    -
    NOTE: Requires custom indicators found here:
    https://github.com/Gab0/Gekko-extra-indicators
    (c) Gabriel Araujo
    Howto: Download + add to gekko/strategies/indicators
*/

// req's
var log = require('../core/log.js');
var config = require('../core/util.js').getConfig();
var RSI = require('./indicators/RSI.js')
var ADX = require('./indicators/ADX.js')
var SMA = require('./indicators/SMA.js')


// strategy
var strat = {

 /* INIT */
 init: function() {
   // core
   this.name = 'RSI Bull and Bear + ADX M1';
   this.requiredHistory = config.tradingAdvisor.historySize;
   this.resetTrend();

   // debug? set to false to disable all logging/messages/stats (improves performance in backtests)
   this.debug = false;

   // performance
   config.backtest.batchSize = 1000; // increase performance
   config.silent = true; // NOTE: You may want to set this to 'false' @ live
   config.debug = false;

   //Add Custom Timeframe indicators
   //SMA
   this.maSlow = new SMA(this.settings.SMA_long);
   this.maFast = new SMA(this.settings.SMA_short)

   // RSI
   this.BULL_RSI = [];
   for (let i = 0; i < this.settings.BULL_RSI_Timeframe; i++) {
     this.BULL_RSI[i] = new RSI({
       interval: this.settings.BULL_RSI
     });
   }

   this.BEAR_RSI = [];
   for (let i = 0; i < this.settings.BEAR_RSI_Timeframe; i++) {
     this.BEAR_RSI[i] = new RSI({
       interval: this.settings.BEAR_RSI
     });
   }

   // ADX
   this.ADX = new ADX(this.settings.ADX);

   this.timeframes = {
     SMA: this.settings.SMA_Timeframe,
     SMA_Count: 0,
     BULL_RSI: this.settings.BULL_RSI_Timeframe,
     BULL_RSI_Count: 0,
     BEAR_RSI: this.settings.BEAR_RSI_Timeframe,
     BEAR_RSI_Count: 0,
     ADX: this.settings.ADX_Timeframe,
     ADX_Count: 0
   };

   // ADX
   this.addIndicator('ADX', 'ADX', this.settings.ADX);

   // MOD (RSI modifiers)
   this.BULL_MOD_high = this.settings.BULL_MOD_high;
   this.BULL_MOD_low = this.settings.BULL_MOD_low;
   this.BEAR_MOD_high = this.settings.BEAR_MOD_high;
   this.BEAR_MOD_low = this.settings.BEAR_MOD_low;


   // debug stuff
   this.startTime = new Date();

   // add min/max if debug
   if (this.debug) {
     this.stat = {
       adx: {
         min: 1000,
         max: 0
       },
       bear: {
         min: 1000,
         max: 0
       },
       bull: {
         min: 1000,
         max: 0
       }
     };
   }

   /* MESSAGES */

   // message the user about required history
   log.info("====================================");
   log.info('Running', this.name);
   log.info('====================================');
   log.info("Make sure your warmup period matches SMA_long and that Gekko downloads data if needed");

   // warn users
   if (this.requiredHistory < this.settings.SMA_long) {
     log.warn("*** WARNING *** Your Warmup period is lower then SMA_long. If Gekko does not download data automatically when running LIVE the strategy will default to BEAR-mode until it has enough data.");
   }

 }, // init()


 /* RESET TREND */
 resetTrend: function() {
   var trend = {
     duration: 0,
     direction: 'none',
     longPos: false,
   };

   this.trend = trend;
 },


 /* get low/high for backtest-period */
 lowHigh: function(val, type) {
   let cur;
   if (type == 'bear') {
     cur = this.stat.bear;
     if (val < cur.min) this.stat.bear.min = val; // set new
     else if (val > cur.max) this.stat.bear.max = val;
   } else if (type == 'bull') {
     cur = this.stat.bull;
     if (val < cur.min) this.stat.bull.min = val; // set new
     else if (val > cur.max) this.stat.bull.max = val;
   } else {
     cur = this.stat.adx;
     if (val < cur.min) this.stat.adx.min = val; // set new
     else if (val > cur.max) this.stat.adx.max = val;
   }
 },

 //Update all of the non gekko managed indicators here
 update: function(candle) {
   tf = this.timeframes;
   if (tf.SMA_Count >= tf.SMA) {
     this.maSlow.update(candle.close);
     this.maFast.update(candle.close);
     tf.SMA_Count = 0;
   } else {
     tf.SMA_Count++;
   }

   tf.BULL_RSI_Count = (tf.BULL_RSI_Count + 1) % (tf.BULL_RSI - 1);
   this.BULL_RSI[tf.BULL_RSI_Count].update(candle);


   tf.BEAR_RSI_Count = (tf.BEAR_RSI_Count + 1) % (tf.BEAR_RSI - 1);
   this.BEAR_RSI[tf.BEAR_RSI_Count].update(candle);

   if (tf.ADX_Count >= tf.ADX) {
     this.ADX.update(candle);
     tf.ADX_Count = 0;
   } else {
     tf.ADX_Count++;
   }
 },


 /* CHECK */
 check: function(candle) {
   // get all indicators

   var maSlow = this.maSlow.result,
     maFast = this.maFast.result,
     rsi,
     adx = this.ADX.result;

   // BEAR TREND
   // NOTE: maFast will always be under maSlow if maSlow can't be calculated
   if (maFast < maSlow) {
     rsi = this.BEAR_RSI[this.timeframes.BEAR_RSI_Count].result;
     let rsi_hi = this.settings.BEAR_RSI_high,
       rsi_low = this.settings.BEAR_RSI_low;

     // ADX trend strength?
     if (adx > this.settings.ADX_high) rsi_hi = rsi_hi + this.BEAR_MOD_high;
     else if (adx < this.settings.ADX_low) rsi_low = rsi_low + this.BEAR_MOD_low;

     if (rsi > rsi_hi) this.short();
     else if (rsi < rsi_low) this.long();

     if (this.debug) this.lowHigh(rsi, 'bear');
   }

   // BULL TREND
   else {
     rsi = this.BULL_RSI[this.timeframes.BULL_RSI_Count].result;
     let rsi_hi = this.settings.BULL_RSI_high,
       rsi_low = this.settings.BULL_RSI_low;

     // ADX trend strength?
     if (adx > this.settings.ADX_high) rsi_hi = rsi_hi + this.BULL_MOD_high;
     else if (adx < this.settings.ADX_low) rsi_low = rsi_low + this.BULL_MOD_low;

     if (rsi > rsi_hi) this.short();
     else if (rsi < rsi_low) this.long();
     if (this.debug) this.lowHigh(rsi, 'bull');
   }

   // add adx low/high if debug
   if (this.debug) this.lowHigh(adx, 'adx');

 }, // check()


 /* LONG */
 long: function() {
   if (this.trend.direction !== 'up') // new trend? (only act on new trends)
   {
     this.resetTrend();
     this.trend.direction = 'up';
     this.advice('long');
     if (this.debug) log.info('Going long');
   }

   if (this.debug) {
     this.trend.duration++;
     log.info('Long since', this.trend.duration, 'candle(s)');
   }
 },


 /* SHORT */
 short: function() {
   // new trend? (else do things)
   if (this.trend.direction !== 'down') {
     this.resetTrend();
     this.trend.direction = 'down';
     this.advice('short');
     if (this.debug) log.info('Going short');
   }

   if (this.debug) {
     this.trend.duration++;
     log.info('Short since', this.trend.duration, 'candle(s)');
   }
 },


 /* END backtest */
 end: function() {
   let seconds = ((new Date() - this.startTime) / 1000),
     minutes = seconds / 60,
     str;

   minutes < 1 ? str = seconds.toFixed(2) + ' seconds' : str = minutes.toFixed(2) + ' minutes';

   log.info('====================================');
   log.info('Finished in ' + str);
   log.info('====================================');

   // print stats and messages if debug
   if (this.debug) {
     let stat = this.stat;
     log.info('BEAR RSI low/high: ' + stat.bear.min + ' / ' + stat.bear.max);
     log.info('BULL RSI low/high: ' + stat.bull.min + ' / ' + stat.bull.max);
     log.info('ADX min/max: ' + stat.adx.min + ' / ' + stat.adx.max);
   }

 }

};

module.exports = strat;
  Reply


Messages In This Thread
[Share] RSI-BB-ADX with candlebatcher - by Gryphon - 11-27-2018, 09:37 AM

Forum Jump:


Users browsing this thread: