Sunday, January 24, 2016

thinkscript included: sdi_linregchan - a custom linear regression channel

this script encapsulates the results of my investigations of the various linear regression channel studies available on tos and expresses my personal preferences for display. here is the picture:
sdi_linregchan for SPY
there's a lot of information here so i gots some 'splaining to do:

first of all, the gray center line in long dashes is the standard linear regression for the most recent 32 (default) closes. a linear regression is the best-fit straight line through a set of data. by 'best-fit' it is meant that the differences (or variances) between the close prices of the candles and the center line are mathematically minimal across the data set. 32 closes is my default for this study because that is about a half of a 'quarter' on the time-aggregation of day.

the next lines out from the center line in gray, medium-dashes are 1.281 (default) multiples of a standard error from the center-line. standard error is the proper statistical measure of data dispersion to use when constructing channels because it is calculated from variances from the linear regression line. a channel that is 1 standard error away from the center line encloses 68% of the data. as a trader, i didn't think that price moving to 1 standard error from the center line was a particularly interesting opportunity. interesting opportunities occur, in trader-think, when an 80% variance from the norm occurs. so the rationale for using 1.281 is that, statistically, a channel that is 1.281 standard errors wide around the center line encloses 80% of the data.

the third set of lines out from the center line in gray, short-dashes are 2 standard errors out from the center line and enclose 95% of the 32 data points. in a sample of this size there is typically one, or less, close outside of a 2se channel. 

the fourth set of lines out from the center line in solid gray are aligned with the close that is maxv (maximally variant) from the center line. the maxv channel is what you will get with the tos study called linearRegCh100, although they don't say that explicitly in their documentation. in my study, the candle of the maxv is highlighted in lime and its standard error multiple is displayed in the chart bubble. 

maxv's typically hang-out close to the 2se level but sometimes go way outside. so the study will display a fifth set of lines in gray dots should the maxv exceed 3 standard errors.

the lrs label displays the slope of the linear regression line. so, -.68, says that the linear regression line is losing 68 cents per day (candle.) the vv^ in parenthesis is the tick-trend of the slope. this says that over the last 4 candles the slope decreased from 3 days-back to 2 days-back and from 2 days-back to 1 day-back but increased from 1 day-back to the current candle.

the se label displays how big, in percent, a standard error is wrt to the end-point of the center line along with a tick-trend.

and finally, the maxv label displays how big, in percent, the end-point of the upper maxv channel is wrt to the end-point of the center-line.

here's the code: (how to install)



################################
# sdi_linregchan
input length=32;
#hint length: the number of bars to include in the regression. rev: 1.0.0 http://www.smallDogInvestor.com
input se1factor=1.281;
#hint se1factor: the multiple of standard errors to use for the first channel lines
input se2factor=2;
#hint se2factor: the multiple of standard errors to use for the secondary channel lines
input se3factor=3;
#hint se3factor: the multiple of standard errors to use for usually hidden tertiary channel lines

def formingBar=!isnaN(close)&&isnan(close[-1]);
#hint: Displays a custom linear regression channel. rev: 1.0.0 http://www.smallDogInvestor.com 

def lrs=linearRegressionSlope(length=length);
# author: allen everhart
addlabel(1,
    concat("lrs:",
    concat( round(lrs,2),
# date: 24jan2016
    concat( "(",
# copylefts reserved. This is free software. That means you are free
    concat( if lrs[2]>lrs[3] then "^" else if lrs[2]<lrs[3] then "v" else "=",
# to use or modify it for your own usage but not for resale or reprinting.
    concat( if lrs[1]>lrs[2] then "^" else if lrs[1]<lrs[2] then "v" else "=",
# Help me get the word out about my blog by keeping notices of origin in place.
    concat( if lrs[0]>lrs[1] then "^" else if lrs[0]<lrs[1] then "v" else "=",
# source http://www.smallDogInvestor.com 
    ")")))))),
    color.blue
);
def lr=inertia(close, length);
# copylefts reserved. This is free software. That means you are free
def se=standardError(length=length)/lr;
# to use or modify it for your own usage but not for resale or reprinting.

addlabel(1,
# Help me get the word out about my blog by keeping notices of origin in place.
    concat("se:",
# source http://www.smallDogInvestor.com 
    concat( aspercent(round(se,3)),
    concat( "(",
    concat( if se[2]>se[3] then "^" else if se[2]<se[3] then "v" else "=",
    concat( if se[1]>se[2] then "^" else if se[1]<se[2] then "v" else "=",
    concat( if se[0]>se[1] then "^" else if se[0]<se[1] then "v" else "=",
    ")")))))),
    color.blue
);

def lrcr=LinearRegChVar("full range" = No, length = length).UpperLR;
def lrcm=LinearRegChVar("full range" = No, length = length);
def lrcs=LinearRegChVar("full range" = No, length = length).LowerLR;
def maxvpct=lrcr/lrcm -1; 

addlabel(1,
    concat("maxv:",
# source http://www.smallDogInvestor.com 
    aspercent(round(maxvpct,3))),
    color.blue
);

assignPriceColor( if close==lrcr OR close==lrcs then color.LIME else color.CURRENT);

def se1up=StandardErrorChannel("standard errors" = se1factor, "full range" = No, length = length);
def se2up=StandardErrorChannel("full range" = no, length = length, "standard errors" = se2factor);
def se1dn=StandardErrorChannel("standard errors" = se1factor, "full range" = No, length = length).LowerBand;
def se2dn=StandardErrorChannel("full range" = no, length = length, "standard errors" = se2factor).LowerBand;
addChartBubble( close==lrcr OR close==lrcs, if close==lrcr then lrcr else lrcs, concat("se*",round(absValue(lrcm-lrcr)/((lrcm-se2dn)/2),2)), color.LIME, close==lrcr);
plot linreg=lrcm;
linreg.setStyle(curve.LONG_DASH);
linreg.setdefaultColor(color.GRAY);
#linreg.setlineWeight(3);
plot se1r=se1up;
se1r.setStyle(curve.MEDIUM_DASH);
se1r.setDefaultColor(color.gRAY);
plot se1s=se1dn;
se1s.setStyle(curve.MEDIUM_DASH);
se1s.setdefaultColor(color.grAY);
plot se2r=se2up;
se2r.setStyle(curve.SHORT_DASH);
# source http://www.smallDogInvestor.com 
se2r.setdefaultColor(color.grAY);
plot se2s=se2dn;
se2s.setStyle(curve.sHORT_DASH);
se2s.setdefaultColor(color.grAY);
plot maxvr=lrcr;
maxvr.setdefaultColor(color.gray);
plot maxvs=lrcs;
maxvs.setdefaultColor(color.gray);
def se3up=StandardErrorChannel("full range" = no, length = length, "standard errors" = se3factor);
def se3dn=StandardErrorChannel("full range" = No, length = length, "standard errors" = se3factor).LowerBand;
plot se3r= if lrcr>se3up or lrcs<se3dn then se3up else double.NaN;
se3r.setdefaultColor(color.gray);
se3r.setStyle(curve.POINTS);
plot se3s= if lrcr>se3up or lrcs<se3dn then se3dn else double.nan;
se3s.setStyle(curve.POINTS);
se3s.setdefaultColor(color.GRAY);



1 comment:

  1. Nice! Can be good for selling credit spreads whenever lime-colored candle shows up and the next candle goes on a different direction.

    ReplyDelete