05-03-2018, 07:02 PM
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:
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:
When goLong we store the candle.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:
And here the settings .toml
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
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;
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