2006 Nov: Building Automatic Trendlines

ICE Data Services -


AutomaticTrendlines.efs  EFSLibrary - Discussion Board
  

File Name: AutomaticTrendlines.efs


Description:
This study are based on the November 2006 article, Building Automatic Trendlines, by Giorgos E. Siligardos, PhD.


Formula Parameters:
Swing: # of Bars: 0
Swing: Wave Type: % Change in Price [% Retracement, % Change in Price]
Swing: Wave Percentage: 20
Line Thickness: 2
Confirmed Swing Line Color: Blue
Developing Swing Line Color: Red
Display Swing Labels: False
Display % Retracement Label: False
Number of Historical Labels: 100
Number of Historical Trend Lines: 10
Display Trend Lines: True
Trend Line Thickness: 2
Trend Line Color: Maroon

Notes:
The study contains several formula parameters that may be configured through the Edit Studies option in the Advanced Chart. There are several parameters that allow for the customization of the SI indicator that the trend lines are based on, which are the first three parameters. The defaults for these parameters set the SI indicator to the calculation described in the article with one exception. The percent change or percent retracement is based on the high or low of the bar for peaks and troughs, respectively. There are also parameters to control the formatting for the SI lines and the automatic trend lines as well as the colors for the most current peak or trough that is developing, but not yet confirmed. There are also two parameters that enable labels for the swings and a label for the current percent retracement value, which are both off by default. There are two parameters that can be used to limit the number of drawn swing lines and trend lines. The parameter for the trend lines sets the limit of 10 by default, which means 10 trend lines based on peaks and 10 additional trend lines based on the troughs. Lastly, there is a parameter for turning off the display of the trend lines. The related article is copyrighted material. If you are not a subscriber of Stocks & Commodities, please visit www.traders.com.

Download File:
AutomaticTrendlines.efs




EFS Code:






/***************************************Provided By : eSignal (c) Copyright 2006Description:  Building Automatic Trendlines               by Giorgos E. Siligardos, PhDVersion 1.0  08/31/2006Notes:* Nov 2006 Issue of Stocks and Commodities Magazine* SI indicator is modified from EFS Library formula:   RealTimeSwings.efs (http://kb.esignalcentral.com/article.asp?article=1450&p=4)Formula Parameters:                     Default:    * Swing: # of Bars                  0        This is the minimum number of bars required to define a         swing point.  This number is for both sides of the swing         point (i.e. 5 bars on the left and right of the swing bar).    * Swing: Wave Type                  % Change in Price        (% Retracement, % Change in Price)    * Swing: Wave Percentage            20        The number 5 will be treated as 5.0%.  The number 0.05 will         be treated as 0.0005%.    * Line Thickness                    2    * Confirmed Swing Line Color        Blue    * Developing Swing Line Color       Red    * Display Swing Labels              False    * Display % Retracement Label       False    * Number of Historical Labels       100    * Number of Historical Trend Lines  10    * Display Trend Lines               True    * Trend Line Thickness              2    * Trend Line Color                  MaroonNotes:1.1 3/24/2004* Added labels to display point value, % retracement, number of bars  and price level of swings.  The number of historical labels is set   to 100 for performance reasons.  Increase this number to view more  historical labels.* Added labels to display current swing's % retracement.    Description of Swing Labels:    At Swing Highs -  Points (% Retracement)                      Price (Number of Bars)    At Swing Lows -   Price (Number of Bars)                      Points (% Retracement)*****************************************************************/function preMain() {    setPriceStudy(true);    setStudyTitle("Automatic Trendlines ");    setShowCursorLabel(false);    setShowTitleParameters(false);        var fp1 = new FunctionParameter("nNum", FunctionParameter.NUMBER);    fp1.setName("Swing: # of Bars");    fp1.setLowerLimit(0);    fp1.setDefault(0);        var fp2a = new FunctionParameter("sWaveType", FunctionParameter.STRING);    fp2a.setName("Swing: Wave Type");    fp2a.addOption("% Retracement");    fp2a.addOption("% Change in Price");    fp2a.setDefault("% Change in Price");        var fp2 = new FunctionParameter("nRet", FunctionParameter.NUMBER);    fp2.setName("Swing: Wave Percentage");    fp2.setLowerLimit(0);    fp2.setDefault(20);    var fp5 = new FunctionParameter("nThickness", FunctionParameter.NUMBER);    fp5.setName("Line Thickness");    fp5.setLowerLimit(1);    fp5.setDefault(2);    var fp6 = new FunctionParameter("cColor1", FunctionParameter.COLOR);    fp6.setName("Confirmed Swing Line Color");    fp6.setDefault(Color.blue);    var fp7 = new FunctionParameter("cColor2", FunctionParameter.COLOR);    fp7.setName("Developing Swing Line Color");    fp7.setDefault(Color.red);        var fp8 = new FunctionParameter("bSwingLabels", FunctionParameter.STRING);    fp8.setName("Display Swing Labels");    fp8.addOption("True");    fp8.addOption("False");    fp8.setDefault("False");        var fp9 = new FunctionParameter("bRetLabel", FunctionParameter.STRING);    fp9.setName("Display \% Retracement Label");    fp9.addOption("True");    fp9.addOption("False");    fp9.setDefault("False");        var fp10 = new FunctionParameter("nNumLabels", FunctionParameter.NUMBER);    fp10.setName("Number of Historical Labels");    fp10.setLowerLimit(1);    fp10.setDefault(100);        var fp11 = new FunctionParameter("nNumATL", FunctionParameter.NUMBER);    fp11.setName("Number of Historical Trend Lines");    fp11.setLowerLimit(1);    fp11.setDefault(10);        var fp12 = new FunctionParameter("bTrendLines", FunctionParameter.STRING);    fp12.setName("Display Trend Lines");    fp12.addOption("True");    fp12.addOption("False");    fp12.setDefault("True");        var fp13 = new FunctionParameter("nTLThickness", FunctionParameter.NUMBER);    fp13.setName("Trend Line Thickness");    fp13.setLowerLimit(1);    fp13.setDefault(2);    var fp14 = new FunctionParameter("cTLColor", FunctionParameter.COLOR);    fp14.setName("Trend Line Color");    fp14.setDefault(Color.maroon);}var bEdit = true;       // tracks change of user inputsvar cntr = 0;           // image counter for swing linesvar bInit = false;      // initialization routine completionvar nNumBars = null;    // number of bars for defining swingsvar sWaveTypeG = null;  // wave type for confirming swingsvar nRetpcnt = null;    // percent retracement for defining swingsvar nThicknessG = null; // line thicknessvar cColorcon = null;   // confirmed swing colorvar cColordev1 = null;  // developing swing colorvar sHSource = null;    // price source for high swingsvar sLSource = null;    // price source for low swingsvar x1a = null;         // x-coordinate for point a of developing line 1var x1b = null;         // x-coordinate for point b of developing line 1var x2a = null;         // x-coordinate for point a of developing line 2var x2b = null;         // x-coordinate for point b of developing line 2var y1a = null;         // y-coordinate for point a of developing line 1var y1b = null;         // y-coordinate for point b of developing line 1var y2a = null;         // y-coordinate for point a of developing line 2var y2b = null;         // y-coordinate for point b of developing line 2var vLastSwing = null;  // tracking swing type of last confirmed swingvar nScntr = 0;         // bar counter for swing confirmationvar nLcntr = 0;         // label counter for swing labelsvar aSwingsIndex = new Array(6); // tracks current swings indexes for last 5 swingsvar aSwingsPrice = new Array(6); // tracks current swing prices for last 5 swingsvar nNumLabelsG = null; // max number of swing labelsvar bSwingLabelsG = null;  // controls swing labels displayvar vSpace = null;      // spacer for Labels// Automatic Trendline variablesvar nTcntr = 0;         // counter for trendline TagIDs.var bDrawn = false;     // flag for tracking the most recently drawn ATLvar aSwingsType = new Array(6);  // 1 =  peak, -1 = troughvar nNumATLG = null;       // global var for ATL limit.var bTrendLinesG = null;   // global var for Trend Line displayvar nTLThicknessG = null;  // global var for Trend Line thicknessvar cTLColorG = null;      // global var for Trend Line colorfunction main(nNum, sWaveType, nRet, nThickness, cColor1, cColor2,                 bSwingLabels, bRetLabel, nNumLabels,                 nNumATL, bTrendLines, nTLThickness, cTLColor) {    var nState = getBarState();    var nIndex = getCurrentBarIndex();    var h = high(0);    var l = low(0);    var c = close(0);    var i = 0;    // record keeping    if (nState == BARSTATE_NEWBAR) {        if (cntr > 500) cntr = 0;  // limits number of swing lines to 500.        if (x1a != null) x1a -= 1;        if (x1b != null) x1b -= 1;        if (x2a != null) x2a -= 1;        if (x2b != null) x2b -= 1;        i = 0;        for (i = 0; i < 6; ++i) {            if (aSwingsIndex[i] != null) aSwingsIndex[i] -= 1;        }    }    //Initialization    if (bEdit == true) {        if (nNumBars == null) nNumBars = nNum;        if (sWaveTypeG == null) sWaveTypeG = sWaveType;        if (nRetpcnt == null) nRetpcnt = nRet/100;        if (nThicknessG == null) nThicknessG = nThickness;        if (cColorcon == null) cColorcon = cColor1;        if (cColordev1 == null) cColordev1 = cColor2;        if (sHSource == null) sHSource = "High";        if (sLSource == null) sLSource = "Low";        if (x1a == null) x1a = 0;        if (y1a == null) y1a = c;        if (nNumLabelsG == null) nNumLabelsG = nNumLabels;        if (bSwingLabelsG == null) bSwingLabelsG = bSwingLabels;        if (nNumATLG == null) nNumATLG = nNumATL;        if (bTrendLinesG == null) bTrendLinesG = bTrendLines;        if (nTLThicknessG == null) nTLThicknessG = nTLThickness;        if (cTLColorG == null) cTLColorG = cTLColor;        nLcntr = nNumLabels;        // Initialize vSpace        var OM = (close(0) * 0.005); //offset multiplier        var sInterval = getInterval();        if (sInterval == "D") OM = OM*3;        if (sInterval == "W") OM = OM*20;        if (sInterval == "M") OM = OM*30;        var TimeFrame = parseInt(sInterval);        if (TimeFrame >= 1 && TimeFrame <= 5) {            OM = OM*(TimeFrame/15);        } else if (TimeFrame > 5 && TimeFrame <= 15) {            OM = OM*(TimeFrame/10);        }else if (TimeFrame > 15) {            OM = OM*(TimeFrame/5);        }        if (!isNaN(TimeFrame)) OM = (OM/TimeFrame)*3;        vSpace = OM;        bEdit = false;    }    if (bInit == false) {        bInit = Init(h,l,c);    }    // Swings    if (nState == BARSTATE_NEWBAR) {        nScntr += 1;        // confirmed Swings        if (nScntr > nNumBars) {            confirmSwings();            if (bInit == true) {                doLine("dev1");                doLine("dev2");            }        }    }        checkSwings(h, l);    if (bInit == true) {        doLine("dev1");        doLine("dev2");    }    // % Retracement Label    var nWaveRet = (Math.abs(y2a-y2b) / Math.abs(y1b-y1a))*100;    if (x1b == x2b) nWaveRet = 0.0;    if (bRetLabel == "True") {        var sWaveRetText = " \%Retraced: " + nWaveRet.toFixed(2) + " ";        drawTextRelative(2, y2b, sWaveRetText, cColordev1, null,            Text.BOLD|Text.LEFT|Text.VCENTER|Text.FRAME, "Arial", 10, "Ret");    }    // Automatic Trendlines (ATL)    if (nState == BARSTATE_NEWBAR && bDrawn == false) autoTL();        return;}/******  Functions *****//***********************/function Init(h,l,c) {    if (close(-(nNumBars*2)) == null) {        return false;    } else {        // Find initial line.        // The initial line will be the first high or low swing,        // which has the greater difference of the swing point to        // the close of the first bar.        var Index = getCurrentBarIndex()        var hIndex = Index;        var lIndex = Index;        var j = nNumBars*2;        if (j == 0) j = 1;        var aHigh = getValue(sHSource, 0, -j);        var aLow = getValue(sLSource, 0, -j);        var vHH = aHigh[0];        var vLL = aLow[0];        var tempIndex = Index;        var i = 0;        for (i = 0; i < j; ++i) {            if (aHigh[i] > vHH) {                vHH = aHigh[i];                hIndex = tempIndex;            }            if (aLow[i] < vLL) {                vLL = aLow[i];                lIndex = tempIndex;            }            tempIndex -= 1;        }        if (vHH - y1a > y1a - vLL) {            vLastSwing = "L";            x1b = hIndex - Index;            y1b = vHH;            doLine("dev1");            x2a = x1b;            y2a = vHH;            x2b = 0;            y2b = c;            doLine("dev2");        } else {            vLastSwing = "H";            x1b = lIndex - Index;            y1b = vLL;            doLine("dev1");            x2a = x1b;            y2a = vLL;            x2b = 0;            y2b = c;            doLine("dev2");        }            }        if (vLastSwing != null) {        return true;    } else {        return false;    }}function doLine(sType) {    //confirmed    if (sType == "con") {        cntr += 1;        nTcntr += 1;        bDrawn = false;  // reset ATL drawing        if (nTcntr > nNumATLG) nTcntr = 1;        drawLineRelative(x1a, y1a, x1b, y1b, PS_SOLID,             nThicknessG, cColorcon, sType+cntr);        //Swing Labels        if (bSwingLabelsG == "True") doSwingLabels(sType);        x1a = x2a;        y1a = y2a;        x1b = x2b;        y1b = y2b;        x2a = x1b;        y2a = y1b;        aSwingsIndex.pop();        aSwingsIndex.unshift(x1b);        aSwingsPrice.pop();        aSwingsPrice.unshift(y1b);        if (vLastSwing == "H") {            y2b = getValue(sHSource);            aSwingsType.pop();            aSwingsType.unshift(1);  // record type of swing for ATL        }        if (vLastSwing == "L") {            y2b = getValue(sLSource);            aSwingsType.pop();            aSwingsType.unshift(-1); // record type of swing for ATL        }    }    // dev1    if (sType == "dev1") {        drawLineRelative(x1a, y1a, x1b, y1b, PS_SOLID,             nThicknessG, cColordev1, sType);        aSwingsIndex[0] = x1b;        aSwingsPrice[0] = y1b;        //Swing Labels        if (bSwingLabelsG == "True") doSwingLabels(sType);    }        // dev2        if (sType == "dev2") {        if (x2a != 0 && x2a != x2b) {            if ( (vLastSwing == "H" && sHSource == "Close") || (vLastSwing == "L" && sLSource == "Close") ) {                x2b = 0;                y2b = close();            }            drawLineRelative(x2a, y2a, x2b, y2b, PS_SOLID,                 nThicknessG, cColordev1, sType);        } else {            removeLine(sType);        }    }        return;}function doSwingLabels(sType) {    var sTagNamePts = "SwingPtsDev";    var sTagNameRet = "SwingRetDev";    var sTagNamePr = "SwingPrDev";    var sTagNameBars = "SwingBarsDev";    var nWaveRet = ((Math.abs(aSwingsPrice[1]-aSwingsPrice[0]) / Math.abs(aSwingsPrice[1]-aSwingsPrice[2])) * 100);    var nBars = (aSwingsIndex[0] - aSwingsIndex[1]);        if (sType == "con") {        //nWaveRet = (Math.abs(y2a-y2b) / Math.abs(y1b-y1a));        nLcntr += 1;        if (nLcntr > nNumLabelsG) nLcntr = 1;        sTagNamePts = "SwingPts"+sType+nLcntr;        sTagNameRet = "SwingRet"+sType+nLcntr;        sTagNamePr = "SwingPr"+sType+nLcntr;        sTagNameBars = "SwingBars"+sType+nLcntr;    }        var pts = (y1b-y1a).toFixed(2);    if (y1a < y1b) { // swing high        drawTextRelative(x1b, y1b+vSpace, pts + " ", eval("cColor"+sType), null,             Text.BOTTOM|Text.RIGHT, "Arial", 10, sTagNamePts); // Points        if (!isNaN(nWaveRet)) {            drawTextRelative(x1b, y1b+vSpace, "| ("+nWaveRet.toFixed(2)+"\%)", eval("cColor"+sType), null,                 Text.BOTTOM|Text.LEFT, "Arial", 10, sTagNameRet); // % Retracement        }        drawTextRelative(x1b, y1b+vSpace, y1b.toFixed(2) + " ", eval("cColor"+sType), null,            Text.TOP|Text.RIGHT, "Arial", 10, sTagNamePr); // Price        if (!isNaN(nBars)) {            drawTextRelative(x1b, y1b+vSpace, "| ("+nBars+" Bars)", eval("cColor"+sType), null,                Text.TOP|Text.LEFT, "Arial", 10, sTagNameBars); // Number of Bars        }    } else { // swing low        drawTextRelative(x1b, y1b-vSpace, pts + " ", eval("cColor"+sType), null,             Text.TOP|Text.RIGHT, "Arial", 10, sTagNamePts); // Points        if (!isNaN(nWaveRet)) {            drawTextRelative(x1b, y1b-vSpace, "| ("+nWaveRet.toFixed(2)+"\%)", eval("cColor"+sType), null,                 Text.TOP|Text.LEFT, "Arial", 10, sTagNameRet); // % Retracement        }        drawTextRelative(x1b, y1b-vSpace, y1b.toFixed(2) + " ", eval("cColor"+sType), null,            Text.BOTTOM|Text.RIGHT, "Arial", 10, sTagNamePr); // Price        if (!isNaN(nBars)) {            drawTextRelative(x1b, y1b-vSpace, "| ("+nBars+" Bars)", eval("cColor"+sType), null,                Text.BOTTOM|Text.LEFT, "Arial", 10, sTagNameBars); // Number of Bars        }    }    return;}function confirmSwings() {    if (x1b != x2b) {   // underdeveloped dev1 line        if (sWaveTypeG == "% Retracement") {            var nWave = (Math.abs(y2a-y2b) / Math.abs(y1b-y1a));        } else {            var nWave = (Math.abs(y2a-y2b) / y1b);        }        if (vLastSwing == "L" && nWave >= nRetpcnt ) {            // Swing High            nScntr = 0;            vLastSwing = "H";            doLine("con");        } else if (vLastSwing == "H" && nWave >= nRetpcnt ) {            // Swing Low            nScntr = 0;            vLastSwing = "L";            doLine("con");        }    }        return;}function checkSwings(h, l) {    // dev1    if (vLastSwing == "L") {         // find Swing High        if (h >= y1b) {  // higher high, no swing            nScntr = 0;            x1b = 0;            y1b = h;            doLine("dev1");            x2a = 0;            y2a = h;        }    } else if (vLastSwing == "H") {  // find Swing Low        if (l <= y1b) {  // Lower low, no swing            nScntr = 0;            x1b = 0;            y1b = l;            doLine("dev1");            x2a = 0;            y2a = l;        }    }    // dev2    if (nScntr == 0) {        x2b = 0;        if (vLastSwing == "H") y2b = h;        if (vLastSwing == "L") y2b = l;    } else {        if (vLastSwing == "H" && h >= y2b) {            y2b = h; x2b = 0;        } else if (vLastSwing == "L" && l <= y2b) {            y2b = l; x2b = 0;        }    }    return;}function autoTL() { // draw Automatic Trendlines    if (bTrendLinesG == "False" || getBarState() != BARSTATE_NEWBAR) return;        if (aSwingsIndex[4] == null) return;  // not enough confirmed swings yet    var bCond = false;              // condition flag    var nATLx1 = 0;                 // x-coordinate for start of ray    var nATLx2 = 0;                 // x-coordinate for second point of ray    var nATLy1 = null;              // y-coordinate for start of ray    var nATLy2 = null;              // y-coordinate for second point of ray    var sATL_ID = "ATL" + nTcntr;   // tagID for ATL    var nIndex = getCurrentBarIndex();        var P1 = aSwingsType[5];    var P2 = aSwingsType[4];    var P3 = aSwingsType[3];    var P4 = aSwingsType[2];        // Condition 1    if (P4 == 1 && P2 == 1 && aSwingsPrice[4] < aSwingsPrice[2]) {        if (atlHigh(aSwingsIndex[4], aSwingsIndex[2]) < high(0)) {            nATLx1 = aSwingsIndex[4];            nATLx2 = aSwingsIndex[2];            nATLy1 = aSwingsPrice[4];            nATLy2 = aSwingsPrice[2];            sATL_ID += "_h";            bCond = true;        }    }        // Condition 2    if (bCond == false) {        if (P4 == -1 && P2 == -1 && aSwingsPrice[4] > aSwingsPrice[2]) {            if (atlLow(aSwingsIndex[4], aSwingsIndex[2]) > low(0)) {                nATLx1 = aSwingsIndex[4];                nATLx2 = aSwingsIndex[2];                nATLy1 = aSwingsPrice[4];                nATLy2 = aSwingsPrice[2];                sATL_ID += "_l";                bCond = true;            }        }    }        // Condition 3    if (bCond == false) {        if (P3 == 1 && P1 == 1 && aSwingsPrice[5] < aSwingsPrice[3]) {            if (atlHigh(aSwingsIndex[5], aSwingsIndex[3]) < atlHigh(aSwingsIndex[3], 0)) {                nATLx1 = aSwingsIndex[5];                nATLx2 = aSwingsIndex[3];                nATLy1 = aSwingsPrice[5];                nATLy2 = aSwingsPrice[3];                sATL_ID += "_h";                bCond = true;            }        }    }        // Condition 4    if (bCond == false) {        if (P3 == -1 && P1 == -1 && aSwingsPrice[5] > aSwingsPrice[3]) {            if (atlLow(aSwingsIndex[5], aSwingsIndex[3]) > atlLow(aSwingsIndex[3], 0)) {                nATLx1 = aSwingsIndex[5];                nATLx2 = aSwingsIndex[3];                nATLy1 = aSwingsPrice[5];                nATLy2 = aSwingsPrice[3];                sATL_ID += "_l";                bCond = true;            }        }    }            // draw trend line    if (nATLy1 != null && nATLy2 != null && bCond == true) {        drawRay(nATLx1, nATLy1, nATLx2, nATLy2, sATL_ID);        bDrawn = true;    }        return;}function atlHigh(x1, x2) {    // returns highest high between bar indexes x1 and x2    // where x2 is most recent index.        var nH = high(x1);        for (var i = x1; i <= x2; i++) {        nH = Math.max(nH, high(i));    }        return nH;}function atlLow(x1, x2) {    // returns Lowest low between bar indexes x1 and x2    // where x2 is most recent index.    var nL = low(x1);        for (var i = x1; i <= x2; i++) {        nL = Math.min(nL, low(i));    }    return nL;}function getSlope(x1, y1, x2, y2) {    return (y2 - y1) / (x2 - x1);}function drawRay(x1, y1, x2, y2, sID) {    var x1_ray = x1;    var y1_ray = y1;        var nSlope = getSlope(x1, y1, x2, y2);        // draw ray from bar with greatest slope factor between swings.    var j = x1;    var nEnd = x2;        if (nSlope > 0) {         // up trend        for(j; j <= nEnd; j++) {            var nTempSlope = getSlope(j, low(j), x2, y2);            if (nTempSlope > nSlope) {                nSlope = nTempSlope;                x1_ray = j;                y1_ray = low(j);            }        }    } else if (nSlope < 0) {  // down trend        for(j; j <= nEnd; j++) {            var nTempSlope = getSlope(j, high(j), x2, y2);            if (nTempSlope < nSlope) {                nSlope = nTempSlope;                x1_ray = j;                y1_ray = high(j);            }        }    }        var nSlopeAdj = nSlope * 500;    y2 += nSlopeAdj;    x2 += 500;        drawLineRelative(x1_ray, y1_ray, x2, y2, PS_SOLID,         nTLThicknessG, cTLColorG, sID);    return;}