[TUT] STRATEGIE #2 TIME CURSOR [SHARE]
#1
Bug 
In the following tutorial you can learn how to:

-build a useful timecursor for our debug purposes
>>> use a Array
>>>>> use a for loop

>>>ONLY START THE SIMULATION WHEN I ASK YOU TO (incomplete snippets wont work)

IF YOU ARE NEW TO GEKKO AND JAVA SCRIPT, PLEASE LOOKING FOR [TUT] #1
BASSic TULIP RSI

The timecursor, can be added to eny debug line.
First in the settings we set the Start date, of the Backtest period.
Then the time cursor will calculate the same date/time as we looking at in the gekko --ui Test result waveform window.
...the time reference to eny event...

For solving the month/day problem we use our first Array where we simply preset the monthdays, for each month, into it.

The simple way for the time reference would be, the build-in date function, but i found that it will have lots of decimal places.
To go around we could use the function:

Code:
myValue.toFixed(0)


this will loose all the decimal places BUT!!! it crates a rounding with error included and becomes useless.

i designed my own whole number counter that works pretty spot-on.

Version3 uses the settings:
candle_size //(minutes!) this sets a [for loop], to update the right minutes-ammount if the candle_size is bigger than 1 minute.
>>> therefore we design our first [for loop].

Here is the code from the last TUT with a little tuning of the RSI:
Code:
/*
Tutorial:     trendatron #0
           rsi trader
philipp wyler
2018-04-25
*/

var _ = require('lodash');
var log = require('../core/log.js');
var config = require('../core/util.js').getConfig();

var trenda = {};

trenda.init = function () {
   //add candle.close
   price =
       {
           close: 0,//this.candle
       };
   this.price = price;

   logic =
       {
           longpos: false
       };
   this.logic = logic;

   //first fetch settings from .toml
   var customRSIsettings = this.settings.RSI;

   // define the indicators we need     //move the settings into >>>rsi input length
   this.addTulipIndicator('myrsi', 'rsi', customRSIsettings);
}

trenda.update = function (candle) {

}

trenda.log = function () {

}

trenda.check = function (candle) {
   //update price.close
   this.price.close = this.candle.close;

   //update the indicator before using it
   var resultRSI = this.tulipIndicators.myrsi.result.result;

   //add debug line and display the rsi value
   //log.debug('RSI result = ' + resultRSI);

   //lets trade...
   if (resultRSI > this.settings.trsRSI.high && this.logic.longpos !== false) {
       this.logic.longpos = false;
       this.advice('short');
       log.debug('goShort price.close = ' + this.price.close);
   }
   else if (resultRSI < this.settings.trsRSI.low && this.logic.longpos !== true) {
       this.logic.longpos = true;
       this.advice('long');
       log.debug('goLong price.close = ' + this.price.close);
   }
}

module.exports = trenda;
use your editor and load a existing gekko strategie.js file from the gekko folder (gekko/strategies/.....)
>select all and delete the content
>>copy/paste my example code strat above
>>>Save as: rename to:
>>>>trendatron_1.js //and save
WARNIG: MY CODE INDENTS HAVE BEEN BIT  MESSED UP HERE
JUST: in your editor right-click choose [format document] before save...

The settings.toml code:
Code:
[RSI]
optInTimePeriod = 15

[trsRSI]
high = 71
low = 28
use your editor and load a existing gekko strategie.toml file from the gekko folder (gekko/config/strategies/.....)
>select all and delete the content
>>copy/paste my example code user settings above
>>>Save as: rename to:
>>>>trendatron_1.toml
>>>>>Save as type //<<<SELECT TYPE: ALL FILES (SCROLL UP TO FIND IT..!)


Now we implement the timecurser step by step as i would write the code.
First write settings.toml

Code:
[___trendatron___]
#<<<>>><<<>>><<<#
__longPos = false

#>>><<<>>><<<>>>#
[_backtest_start_]
__________day = 1
______month = 4
_____hour = 18
_minute = 38
candle_size = 1
#<<<>>><<<>>><<<#

[RSI]
optInTimePeriod = 15

[trsRSI]
high = 71
low = 28
we also use the logic.longpos to tell gekko if we start trading with currency or asset.
that way we dont need to edit the code for using basic functions like this.

Now i have nice names in the settings but for writing code i use different names.
instead of just initializing the settings in the [INIT] we create a mapping:
Code:
trenda.init = function () {
   
   this.longpos = this.settings.___trendatron___.__longPos;
   month = this.settings._backtest_start_.______month;
   day = this.settings._backtest_start_.__________day;
   hour = this.settings._backtest_start_._____hour;
   minute = this.settings._backtest_start_._minute;

   this.montharr = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
   this.month = month;
   this.day = day;
   this.hour = hour;
   this.minute = minute;
   this.timearr = [];
   this.candlesize = this.settings._backtest_start_.candle_size;

   //add candle.close
   price =
       {
           close: 0,//this.candle
       };
   this.price = price;

   logic =
       {
           longpos: this.longpos
       };
   this.logic = logic;

   //first fetch settings from .toml
   var customRSIsettings = this.settings.RSI;

   // define the indicators we need     //move the settings into >>>rsi input length
   this.addTulipIndicator('myrsi', 'rsi', customRSIsettings);
}
we have also initialized two arrays:
this.montharr //here we set the values for each month directly. This will also set the length to 12
this.timearr //here we only init a empty array since we dont know/have the content yet.

>>>WE CAN CHECK A ARRAY LENGTH IN THE DEBUG LINE:
Code:
log.debug('Array length ' + this.myArray.length);

add the main code to the update function, that will execute before we can use it:
Code:
trenda.update = function (candle) {
   
   if (this.logic.globalcount == 0) {
       this.mcount = this.minute;
       this.hcount = this.hour;
       this.dcount = this.day;
       this.moncount = this.month;
   }

   y = this.candlesize;
   for (i = 0; i < y; i++) {
       this.logic.globalcount++;//COUNT BACKTEST CANDLES

       z = this.moncount - 1;
       this.monthframe = this.montharr[z];
       candleminute = this.logic.globalcount % 60;//MINUTE MODULUS////
       this.candleminute = candleminute;
       //HOUR COUNT
       if (this.mcount == 59) {
           this.hcount++;//HOUR COUNT
           this.mcount = 0;
       }
       else if (this.mcount < 59) {
           this.mcount++;
       }
       //DAY COUNT
       if (this.hcount == 24) {
           this.dcount++;//DAY COUNT
           this.hcount = 0;
       }
       //MONTHDAY
       if (this.dcount > (this.monthframe)) {
           this.moncount++;
           this.dcount = 1
       }
       //MONTH
       else if (this.moncount > 12) {
           this.moncount = 1;
       }
       this.candlehour = this.hcount;//HOUR
       this.candleday = this.dcount;//DAY
       this.candlemonth = this.moncount;//MONTH
       this.timearr = [this.candlemonth, this.candleday, this.candlehour, this.candleminute];
   }
}

Now we setup the main counter in the [INIT] that will count the candles for the backtest period.
Code:
logic =
       {
           longpos: false,
           globalcount: 0 //candle counter
       };
   this.logic = logic;



The final code with the debug lines using the time array:
Code:
/*
Tutorial:     trendatron #0
           rsi trader
philipp wyler
2018-04-25
*/

var _ = require('lodash');
var log = require('../core/log.js');
var config = require('../core/util.js').getConfig();

var trenda = {};

trenda.init = function () {

   this.longpos = this.settings.___trendatron___.__longPos;
   month = this.settings._backtest_start_.______month;
   day = this.settings._backtest_start_.__________day;
   hour = this.settings._backtest_start_._____hour;
   minute = this.settings._backtest_start_._minute;

   this.montharr = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
   this.month = month;
   this.day = day;
   this.hour = hour;
   this.minute = minute;
   this.timearr = [];
   this.candlesize = this.settings._backtest_start_.candle_size;

   //add candle.close
   price =
       {
           close: 0,//this.candle
       };
   this.price = price;

   logic =
       {
           longpos: false,
           globalcount: 0
       };
   this.logic = logic;

   //first fetch settings from .toml
   var customRSIsettings = this.settings.RSI;

   // define the indicators we need     //move the settings into >>>rsi input length
   this.addTulipIndicator('myrsi', 'rsi', customRSIsettings);
}

trenda.update = function (candle) {

   if (this.logic.globalcount == 0) {
       this.mcount = this.minute;
       this.hcount = this.hour;
       this.dcount = this.day;
       this.moncount = this.month;
   }

   y = this.candlesize;
   for (i = 0; i < y; i++) {
       this.logic.globalcount++;//COUNT BACKTEST CANDLES

       z = this.moncount - 1;
       this.monthframe = this.montharr[z];
       candleminute = this.logic.globalcount % 60;//MINUTE MODULUS////
       this.candleminute = candleminute;
       //HOUR COUNT
       if (this.mcount == 59) {
           this.hcount++;//HOUR COUNT
           this.mcount = 0;
       }
       else if (this.mcount < 59) {
           this.mcount++;
       }
       //DAY COUNT
       if (this.hcount == 24) {
           this.dcount++;//DAY COUNT
           this.hcount = 0;
       }
       //MONTHDAY
       if (this.dcount > (this.monthframe)) {
           this.moncount++;
           this.dcount = 1
       }
       //MONTH
       else if (this.moncount > 12) {
           this.moncount = 1;
       }
       this.candlehour = this.hcount;//HOUR
       this.candleday = this.dcount;//DAY
       this.candlemonth = this.moncount;//MONTH
       this.timearr = [this.candlemonth, this.candleday, this.candlehour, this.candleminute];
   }
}

trenda.log = function () {

}

trenda.check = function (candle) {
   //update price.close
   this.price.close = this.candle.close;

   //update the indicator before using it
   var resultRSI = this.tulipIndicators.myrsi.result.result;

   //lets trade...
   if (resultRSI > this.settings.trsRSI.high && this.logic.longpos !== false) {
       this.logic.longpos = false;
       this.advice('short');
       log.debug('>>> ' + this.timearr + ' Short price.close = ' + this.price.close);
   }
   else if (resultRSI < this.settings.trsRSI.low && this.logic.longpos !== true) {
       this.logic.longpos = true;
       this.advice('long');
       log.debug(' <<<' + this.timearr + ' Long price.close = ' + this.price.close);
   }
}

module.exports = trenda;
>>>save this code as: trendatron_1.js
>>>>>save also the latest settings.toml from above, as trendatron_1.toml (File type "all files")
>>>>>>>run the code


The code works but looks alllready stuffed with nothing in there yet.
>>>>>We create subroutines/functions that can be called from every where:
(this makes sense for functions that are called more than once, or that are only to be initialized, like the timecursor (set and forget)).
Code:
/*
Tutorial:     trendatron #2
           rsi trader
philipp wyler
2018-04-25
*/

var _ = require('lodash');
var log = require('../core/log.js');
var config = require('../core/util.js').getConfig();

var trenda = {};

trenda.init = function () {

   this.allInit();

   this.userMap();

   this.indInit();
}

trenda.update = function (candle) {

   this.timeCursor();
}

trenda.log = function () {

}

trenda.check = function (candle) {
   //update price.close
   this.price.close = this.candle.close;

   //update the indicator before using it
   var resultRSI = this.tulipIndicators.myrsi.result.result;

   //add debug line and display the rsi value
   //log.debug('RSI result = ' + resultRSI);

   //lets trade...
   if (resultRSI > this.settings.trsRSI.high && this.logic.longpos !== false) {
       this.goShort();
   }
   else if (resultRSI < this.settings.trsRSI.low && this.logic.longpos !== true) {
       this.goLong();
   }
}


trenda.goShort = function () {
   this.logic.longpos = false;
   this.advice('short');
   log.debug('>>> ' + this.timearr + ' Short price.close = ' + this.price.close);
}
trenda.goLong = function () {
   this.logic.longpos = true;
   this.advice('long');
   log.debug(' <<<' + this.timearr + ' Long price.close = ' + this.price.close);
}



trenda.indInit = function () {
   // define the indicators we need     //move the settings into >>>rsi input length
   this.addTulipIndicator('myrsi', 'rsi', this.customRSIsettings);
}

trenda.allInit = function () {

   //first fetch settings from .toml
   this.customRSIsettings = this.settings.RSI;

   //add candle.close
   price =
       {
           close: 0,//this.candle
       };
   this.price = price;

   logic =
       {
           longpos: false,
           globalcount: 0
       };
   this.logic = logic;
}
trenda.userMap = function () {

   this.longpos = this.settings.___trendatron___.__longPos;
   month = this.settings._backtest_start_.______month;
   day = this.settings._backtest_start_.__________day;
   hour = this.settings._backtest_start_._____hour;
   minute = this.settings._backtest_start_._minute;

   this.montharr = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
   this.month = month;
   this.day = day;
   this.hour = hour;
   this.minute = minute;
   this.timearr = [];
   this.candlesize = this.settings._backtest_start_.candle_size;
}
trenda.timeCursor = function () {
   if (this.logic.globalcount == 0) {
       this.mcount = this.minute;
       this.hcount = this.hour;
       this.dcount = this.day;
       this.moncount = this.month;
   }

   y = this.candlesize;
   for (i = 0; i < y; i++) {
       this.logic.globalcount++;//COUNT BACKTEST CANDLES

       z = this.moncount - 1;
       this.monthframe = this.montharr[z];
       candleminute = this.logic.globalcount % 60;//MINUTE MODULUS////
       this.candleminute = candleminute;
       //HOUR COUNT
       if (this.mcount == 59) {
           this.hcount++;//HOUR COUNT
           this.mcount = 0;
       }
       else if (this.mcount < 59) {
           this.mcount++;
       }
       //DAY COUNT
       if (this.hcount == 24) {
           this.dcount++;//DAY COUNT
           this.hcount = 0;
       }
       //MONTHDAY
       if (this.dcount > (this.monthframe)) {
           this.moncount++;
           this.dcount = 1
       }
       //MONTH
       else if (this.moncount > 12) {
           this.moncount = 1;
       }
       this.candlehour = this.hcount;//HOUR
       this.candleday = this.dcount;//DAY
       this.candlemonth = this.moncount;//MONTH
       this.timearr = [this.candlemonth, this.candleday, this.candlehour, this.candleminute];
   }
}

module.exports = trenda;

looks better but lets use the [update] as its ment to, and the [check] for the final strategic statements:

Code:
/*
Tutorial:     trendatron #2
           rsi trader
philipp wyler
2018-04-25
*/

var _ = require('lodash');
var log = require('../core/log.js');
var config = require('../core/util.js').getConfig();

var trenda = {};
//<<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><
//>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>
//<<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><

trenda.init = function () {

   this.allInit();

   this.userMap();

   this.indInit();
}

trenda.update = function (candle) {

   this.timeCursor();
   this.price.close = this.candle.close;
   this.resultRSI = this.tulipIndicators.myrsi.result.result;
}

trenda.log = function () {

}

trenda.check = function (candle) {

   //lets trade...
   if (this.resultRSI > this.settings.trsRSI.high && this.logic.longpos !== false) {
       this.goShort();
   }
   else if (this.resultRSI < this.settings.trsRSI.low && this.logic.longpos !== true) {
       this.goLong();
   }
}
//<<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><
//>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>
//<<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><
trenda.goShort = function () {
   this.logic.longpos = false;
   this.advice('short');
   log.debug('>>> ' + this.timearr + ' Short price.close = ' + this.price.close);
}
trenda.goLong = function () {
   this.logic.longpos = true;
   this.advice('long');
   log.debug(' <<<' + this.timearr + ' Long price.close = ' + this.price.close);
}


trenda.indInit = function () {
   // define the indicators we need     //move the settings into >>>rsi input length
   this.addTulipIndicator('myrsi', 'rsi', this.customRSIsettings);
}

trenda.allInit = function () {

   //first fetch settings from .toml
   this.customRSIsettings = this.settings.RSI;

   //add candle.close
   price =
       {
           close: 0,
       };
   this.price = price;

   logic =
       {
           longpos: false,
           globalcount: 0
       };
   this.logic = logic;
}
trenda.userMap = function () {

   this.longpos = this.settings.___trendatron___.__longPos;
   month = this.settings._backtest_start_.______month;
   day = this.settings._backtest_start_.__________day;
   hour = this.settings._backtest_start_._____hour;
   minute = this.settings._backtest_start_._minute;

   this.montharr = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
   this.month = month;
   this.day = day;
   this.hour = hour;
   this.minute = minute;
   this.timearr = [];
   this.candlesize = this.settings._backtest_start_.candle_size;
}
trenda.timeCursor = function () {
   if (this.logic.globalcount == 0) {
       this.mcount = this.minute;
       this.hcount = this.hour;
       this.dcount = this.day;
       this.moncount = this.month;
   }

   y = this.candlesize;
   for (i = 0; i < y; i++) {
       this.logic.globalcount++;//COUNT BACKTEST CANDLES

       z = this.moncount - 1;
       this.monthframe = this.montharr[z];
       candleminute = this.logic.globalcount % 60;//MINUTE MODULUS////
       this.candleminute = candleminute;
       //HOUR COUNT
       if (this.mcount == 59) {
           this.hcount++;//HOUR COUNT
           this.mcount = 0;
       }
       else if (this.mcount < 59) {
           this.mcount++;
       }
       //DAY COUNT
       if (this.hcount == 24) {
           this.dcount++;//DAY COUNT
           this.hcount = 0;
       }
       //MONTHDAY
       if (this.dcount > (this.monthframe)) {
           this.moncount++;
           this.dcount = 1
       }
       //MONTH
       else if (this.moncount > 12) {
           this.moncount = 1;
       }
       this.candlehour = this.hcount;//HOUR
       this.candleday = this.dcount;//DAY
       this.candlemonth = this.moncount;//MONTH
       this.timearr = [this.candlemonth, this.candleday, this.candlehour, this.candleminute];
   }
}

module.exports = trenda;

much better ;-)
its now modular to comment/uncomment functions, besides it has become somewhat structurized.
Code:
//this.timeCursor();
now the whole function is switched off


thats it for the timecursor and subcircuits.
in the next short tutorial a simple cpu-prozessing-time messurement tool and debug functions are the topic.
  Reply


Forum Jump:


Users browsing this thread: