04-29-2018, 11:05 PM
(This post was last modified: 04-29-2018, 11:07 PM by susitronix.)
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:
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:
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:
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
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:
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:
add the main code to the update function, that will execute before we can use it:
Now we setup the main counter in the [INIT] that will count the candles for the backtest period.
The final code with the debug lines using the time array:
>>>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)).
looks better but lets use the [update] as its ment to, and the [check] for the final strategic statements:
much better ;-)
its now modular to comment/uncomment functions, besides it has become somewhat structurized.
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.
-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;
>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
>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
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);
}
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 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();
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.