[TUT] STRATEGIE #5 dynamique stoploss [SHARE]
#1
Bug 
In this Tutorial we will add a dynamic stoploss.

Stoploss seems to be pretty hard to get right,
because the most approaches would decrease the profit, rather than do good to it.

First one would think, a price.long-absolut-stoploss would work well, but the reallity shows different:
>>>a smaller stop value does increase the errors and loose more than the stop would benefit..!

it simply hurts the strategy as TommieHansen stated.

On the otherside if we set the threshold more loose, then it again does not work too much.


The indicators based stoploss are also interesting but theese have problems with the indication speed,
because:
>>>>>the newest candle.data must first fight against the old averages, before it could seriously indicate a fast change.
>>>thats not always true since they would use multiplication to indicate a fast change.
>>>>>>>THUS also create a lot of false triggers due to multiplication (RSI-based)

so what we do!

i found a easy way is to create our own stop indicator.
Its very simple design:

Code:
this.price.exp = this.price.trades * this.price.dif;
the candle.trades value is intresting.
It seem to indicate the changes pretty faster than enybody else.
But it is a positive number (offcourse!).
For our indicator we wanna have a bipolar output signal, otherwise it would trigger in both trends.
therefore we multiply with the procentage difference between the candles.

The price.dif is a simple procent calculation for the absolut price:
Code:
this.price.dif = ((this.price.last - this.price.close) / this.price.last) * -100;    //LAST LONG
this.price.last = 0;
this.price.last = this.price.close; //BACKUP FOR THE NEXT CANDLE


When goLong we store the candle.close:

Code:
this.price.long = this.price.close;


The stop(trend) logic dos inhibit the RSI trader while in the stop trend.
then a unlock logic will delay the stop trend for not buy to early.

I also adjusted the RSI trader to get better positive results.
4 month
1 month

Binance
BTC/Usdt
candlesize 1min
warmup 10min

For the 4 month period with such a difficult trend, its not bad.
>>>>>>>>its only a rsi and a stoploss...<<<<<<<<<
the one month as expected, is a bit less then the bulltrend

here is the finished code:

Code:
/*
Tutorial:     trendatron #5
           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.name = 'trendatron_2';

   this.allInit();

   this.userMap();

   this.cpuTime();

   this.indInit();

   this.setupLog();
}

trenda.update = function (candle) {

   this.timeCursor();

   this.priceUpdate();

   this.calculus();

   this.resultRSI = this.tulipIndicators.myrsi.result.result;
}

trenda.log = function () {

}
trenda.check = function (candle) {

   this.stop();
   //lets trade...
   if (this.logic.stopabs !== true && this.resultRSI > this.settings.trsRSI.high && this.logic.longpos !== false) {
       this.goShort();
   }
   else if (this.logic.stopabs !== true && this.resultRSI < this.settings.trsRSI.low && this.logic.longpos !== true) {
       this.goLong();
   }
}
//<<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><
//>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>
//<<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><
trenda.stop = function () {
   if (this.logic.stopabs !== false) {
       if (this.logic.lock !== false && this.resultRSI > this.settings.trsRSI.high) {
           this.logic.lock = false;
       }
       if (this.logic.lock !== true && this.resultRSI < this.settings.trsRSI.low) {
           this.logic.stopabs = false;
           log.debug('-  ' + this.timearr + ' zz---unlock ' + '  stop ' + this.logic.stopabs + '  pc ' + this.price.close.toFixed(2) + '  exp ' + this.price.exp.toFixed(2));
       }
   }
   //SIDECHAIN STOP
   if (this.logic.stopabs !== true && this.logic.longpos !== false && this.stopabsset > this.price.abs) {
       if (this.stopabsexpset > this.price.exp) {
           this.logic.stopabs = true;
           this.logic.lock = true;
           this.goShort();
           this.logic.stopcount++;
           log.debug('-  ' + this.timearr + ' xxxxxxxxxxx ' + '  stop ' + this.logic.stopabs + '  pc ' + this.price.close.toFixed(2) + '  exp ' + this.price.exp.toFixed(2));
       }
   }
   if (this.logic.stopabs !== true && this.logic.longpos !== true && this.stopabsset > this.price.abs) {
       if (this.stopabsexpset > this.price.exp) {
           this.logic.stopabs = true;
           this.logic.lock = true;
           this.logic.waitcount++;
           log.debug('-  ' + this.timearr + ' yyyyyyyyyy ' + '  wait ' + this.logic.stopabs + '  pc ' + this.price.close.toFixed(2) + '  exp ' + this.price.exp.toFixed(2));
       }
   }
}
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');
   this.price.long = this.price.close;
   log.debug(' <<<' + this.timearr + ' Long price.close = ' + this.price.close);
}
trenda.priceUpdate = function () {
   this.price.close = this.candle.close;
   this.price.low = this.candle.low;
   this.price.high = this.candle.high;
   this.price.volume = this.candle.volume;
   this.price.vwp = this.candle.vwp;
   this.price.trades = this.candle.trades;
}
trenda.calculus = function () {
   this.price.abs = ((this.price.long - this.price.close) / this.price.long) * -100;    //LAST LONG

   this.price.dif = ((this.price.last - this.price.close) / this.price.last) * -100;    //LAST LONG
   this.price.last = 0;
   this.price.last = this.price.close;

   this.price.exp = this.price.trades * this.price.dif;
}

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
   price =
       {
           close: 0,//this.candle
           low: 0,//this.candle
           high: 0,//this.candle
           volume: 0,//this.candle
           vwp: 0,//this.candle
           trades: 0,//this.candle
           long: 0,
           last: 0,
           dif: 0,
           exp: 0
       };
   this.price = price;

   logic =
       {
           longpos: false,
           stopabs: false,
           lock: false,
           globalcount: 0,
           stopcount: 0,
           waitcount: 0
       };
   this.logic = logic;

   this.stopabsset = this.settings.___stop_abs____.stop_abs;
   this.stopabsexpset = this.settings.___stop_abs____.abs_exp;
}
trenda.cpuTime = function () {
   //CPU TIME SET
   this.startTime = new Date();
}
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];
   }
}
trenda.setupLog = function () {
   log.info
       (


       '\n' + '\t' + '\t' + '\t' + '\t' +
       '  ...last longpos = ' + this.logic.longpos + '\n' + '\t' + '\t' + '\t' +
       '+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+' + '\n' + '\t' + '\t' + '\t' +
       '  .....start backtest ' + this.name + ' varactor' + '\n' + '\t' + '\t' + '\t' +
       '+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+' + '\n' + '\t' + '\t' + '\t' +
       '\n' + '\t' + '\t' + '\t' +
       '                     <<>>' + '\n' + '\t' + '\t' + '\t' +
       '                 ><<><>><<>>' + '\n' + '\t' + '\t' + '\t' +
       '             >><<>>       <<>><<' + '\n' + '\t' + '\t' + '\t' +
       '        <>><<>    system v3   >><<>>' + '\n' + '\t' + '\t' + '\t' +
       '    <<>><<>  start date ' + this.month + ':' + this.day + ':' + this.hour + ':' + this.minute + ' >><<>>' + '\n' + '\t' + '\t' + '\t' +
       ' ><<>><    ......beginn trading       <>><<>' + '\n' + '\t' + '\t' + '\t' +
       '><<>><            ' + this.name + '         ><>><<' + '\n' + '\t' + '\t' + '\t' +
       '  >><<>>       susitronix d-sign      <<>><<' + '\n' + '\t' + '\t' + '\t' +
       '     >><<<<<>>><<            <<>>><<>><<' + '\n' + '\t' + '\t' + '\t' +
       '              ><<<<>>><<<>>><<>>' + '\n' + '\t' + '\t' + '\t' +
       '                    >>><<<' + '\n' + '\t' + '\t' + '\t' +
       '                      <>' + '\n'
       );
}
trenda.end = function () {
   this.logic.globalcount;
   this.monthdif = (((this.logic.globalcount / 60) / 24) / 30) % 12;
   this.daysdif = ((this.logic.globalcount / 60) / 24) % 30;
   this.hoursdif = (this.logic.globalcount / 60) % 24;
   this.minutesdif = this.logic.globalcount % 60;

   this.globalcountdif = this.logic.globalcount - this.globalcountbegin;

   let seconds = ((new Date() - this.startTime) / 1000),
       minutes = seconds / 60,
       str;
   //CPU TIME CALCULUS IN MILLISECONDS
   this.totaltime = ((minutes / 60) + seconds);
   this.cputime = ((this.totaltime / this.logic.globalcount) * 1000);

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

   log.info
       (
       '\n' + '\t' + '\t' +
       '.....backtest started with longpos = ' + this.longpos + '\n' + '\t' +
       '.....stop count = ' + this.logic.stopcount + '\n' + '\t' +
       '.....wait count = ' + this.logic.waitcount + '\n' + '\t' +
       '                                                       ' + '\n' + '\t' +
       '                             <<>>                      ' + '\n' + '\t' +
       '                       <<>><<>><<>><<>>                ' + '\n' + '\t' +
       '                 >><<>><<>><<>><<>><<>><<>><<          ' + '\n' + '\t' +
       '            <<>><<>>     ' + this.name + '     <<>><<>>' + '\n' + '\t' +
       '        <<>><<>>    start date ' + this.month + ':' + this.day + ':' + this.hour + ':' + this.minute + '     <<>><<>>' + '\n' + '\t' +
       '   <<>><<>>         end time ' + this.candlemonth + ':' + this.candleday + ':' + this.candlehour + ':' + this.candleminute + ' finish     <<>><<>>' + '\n' + '\t' +
       ' <<>><<>>      ' + str + ' / candles = ' + this.logic.globalcount + '       <<>><<>>' + '\n' + '\t' +
       '   <<>><<>>    candle cpu time = ' + this.cputime.toFixed(4) + ' mSec       <<>><<>>' + '\n' + '\t' +
       '      >><< <<>><<>><<>>                <<>><<>><<>> <<>> ' + '\n' + '\t' +
       '    <<>><>         <<>><<>><<>><<>><<>><<>>         <<>><< ' + '\n' + '\t' +
       '<<>><<>>><<                <<>><<>>                ><<>><<>>>< ' + '\n' + '\t'
       );
}

module.exports = trenda;

And here the settings .toml

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

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

[RSI]
optInTimePeriod = 30

[trsRSI]
high = 68
low = 30

[___stop_abs____]
stop_abs = -1.7
abs_exp = -250


The actual code for the strat would be fearly small, the rest are just debug tools.
>>>In the following tutorial we will build the hypetrend that can be seen as a complement to the stoploss, function wise.
Also we try to build a macrotrend for the longer trends in the future.

If you have questions to it, feel free to ask here in this topic because i will read them. hope this helps
or if you need some help with your strategie, no worries fire it up
  Reply


Messages In This Thread
[TUT] STRATEGIE #5 dynamique stoploss [SHARE] - by susitronix - 05-03-2018, 07:02 PM

Forum Jump:


Users browsing this thread: