2007 Sep: Trading Trendline Breaks, Part 2

ICE Data Services -

Trendline_Breaks.efs  

EFSLibrary - Discussion Board  

File Name: Trendline_Breaks.efs

 

Description:
This study is based on the Sept 2007 article, Trading Trendline Breaks, Part 2, by Sylvain Vervoort.

 

Formula Parameters:

  • Swing: # of Bars: 5
    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: % Retracement
    (% Retracement, % Change in Price)
  • Swing: Wave Percentage: 30
    The number 5 will be treated as 5.0%. The number 0.05 will be treated as 0.0005%.
  • Swing High Price Source: High
  • Swing Low Price Source: Low
  • 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

Notes:
Study is a modified version of eSignal's RealTimeSwings.efs, which incorporates Vervoort's strategy signals based on ZigZag indicator.

Study provides historical analysis only, see author's notes in the article. The study displays the ZigZag indicator as well as the PU and PD price levels used for the trade signals, which are highlighted on the chart with "Long" and "Short" labels accompanied by up/down arrows. One difference with this EFS study that differs from the logic used in the article is that the forward looking aspect of the signals has been removed. To create realistic signals that may be evaluated in real time, the trade conditions are evaluated on the bars that confirm the previous swing points by the appropriate price action as defined by the formula parameters. The related article is copyrighted material. If you are not a subscriber of Stocks & Commodities, please visit www.traders.com.

 

Download File:
Trendline_Breaks.efs



EFS Code:

/***************************************
Provided By : 
    eSignal (Copyright © eSignal), a division of Interactive Data 
    Corporation. 2007. All rights reserved. This sample eSignal 
    Formula Script (EFS) is for educational purposes only and may be 
    modified and saved under a new file name.  eSignal is not responsible
    for the functionality once modified.  eSignal reserves the right 
    to modify and overwrite this EFS file with each new release.
    
Description:  Trading Trendline Breaks, Part 2
              by Sylvain Vervoort

Version 1.0  7/9/2007

Notes:
* Study is a modified version of eSignal's RealTimeSwings.efs,
    which incorporates Vervoort's strategy signals based on
    ZigZag indicator.
* Study provides historical analysis only, see author's notes
    in the article.
*   Description of Swing Labels:
        At Swing Highs -  Points (% Retracement)
                          Price (Number of Bars)
    
        At Swing Lows -   Price (Number of Bars)
                          Points (% Retracement)


Formula Parameters:                 Default:
    * Swing: # of Bars              5
        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              % Retracement
        (% Retracement, % Change in Price)
    * Swing: Wave Percentage        30
        The number 5 will be treated as 5.0%.  The number 0.05 will 
        be treated as 0.0005%.
    * Swing High Price Source       High
    * Swing Low Price Source        Low
    * 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

*****************************************************************/

function preMain() {
    setPriceStudy(true);
    setStudyTitle("Trend Line Breaks ");
    //setShowCursorLabel(false);
    setShowTitleParameters(false);
    
    //TASC mod
    setCursorLabelName("PD", 0);
    setCursorLabelName("PU", 1);
    setDefaultBarFgColor(Color.red, 0);     //PD
    setDefaultBarFgColor(Color.green, 1);   //PU
    setDefaultBarThickness(2, 0);
    setDefaultBarThickness(2, 1);
    setPlotType(PLOTTYPE_FLATLINES, 0);
    setPlotType(PLOTTYPE_FLATLINES, 1);
    
    
    var fp1 = new FunctionParameter("nNum", FunctionParameter.NUMBER);
    fp1.setName("Swing: # of Bars");
    fp1.setLowerLimit(1);
    fp1.setDefault(5);
    
    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(7);

    var fp3 = new FunctionParameter("sHighSource", FunctionParameter.STRING);
    fp3.setName("Swing High Price Source");
    fp3.addOption("Open");
    fp3.addOption("High");
    fp3.addOption("Low");
    fp3.addOption("Close");
    fp3.setDefault("Close");

    var fp4 = new FunctionParameter("sLowSource", FunctionParameter.STRING);
    fp4.setName("Swing Low Price Source");
    fp4.addOption("Open");
    fp4.addOption("High");
    fp4.addOption("Low");
    fp4.addOption("Close");
    fp4.setDefault("Close");

    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 bEdit = true;       // tracks change of user inputs
var cntr = 0;           // image counter for swing lines
var bInit = false;      // initialization routine completion
var nNumBars = null;    // number of bars for defining swings
var sWaveTypeG = null;  // wave type for confirming swings
var nRetpcnt = null;    // percent retracement for defining swings
var nThicknessG = null; // line thickness
var cColorcon = null;   // confirmed swing color
var cColordev1 = null;  // developing swing color
var sHSource = null;    // price source for high swings
var sLSource = null;    // price source for low swings
var x1a = null;         // x-coordinate for point a of developing line 1
var x1b = null;         // x-coordinate for point b of developing line 1
var x2a = null;         // x-coordinate for point a of developing line 2
var x2b = null;         // x-coordinate for point b of developing line 2
var y1a = null;         // y-coordinate for point a of developing line 1
var y1b = null;         // y-coordinate for point b of developing line 1
var y2a = null;         // y-coordinate for point a of developing line 2
var y2b = null;         // y-coordinate for point b of developing line 2
var vLastSwing = null;  // tracking swing type of last confirmed swing (H or L)
var nScntr = 0;         // bar counter for swing confirmation
var nLcntr = 0;         // label counter for swing labels
var aSwingsIndex = new Array(4); // tracks current swings indexes for last 4 swings
var aSwingsPrice = new Array(4); // tracks current swing prices for last 4 swings
var nNumLabelsG = null; // max number of swing labels
var bSwingLabelsG = null;  // controls swing labels display
var vSpace = null;      // spacer for Labels

//TASC mod
var bBT = true;     // back test flag
var vPosition = 0;  // 0=flat, 1=long, -1=short
var nPD = null;
var nPU = null;

function main(nNum, sWaveType, nRet, sHighSource, sLowSource, 
              nThickness, cColor1, cColor2, bSwingLabels, bRetLabel, nNumLabels) {
    var nState = getBarState();
    var nIndex = getCurrentBarIndex();
    var h = getValue(sHighSource);
    var l = getValue(sLowSource);
    var c = close();
    var i = 0;

    // record keeping
    if (nState == BARSTATE_NEWBAR) {
        if (cntr > 100) cntr = 0;
        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 < 3; ++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 = sHighSource;
        if (sLSource == null) sLSource = sLowSource;
        if (x1a == null) x1a = 0;
        if (y1a == null) y1a = c;
        if (nNumLabelsG == null) nNumLabelsG = nNumLabels;
        if (bSwingLabelsG == null) bSwingLabelsG = bSwingLabels;
        nLcntr = nNumLabels;
        // Initialize vSpace
        var OM = (close() * 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;
        
        //TASC mod
        setDefaultBarThickness(nThickness, 0);
        setDefaultBarThickness(nThickness, 1);
        
        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");
    }

    //TASC mod - back testing conditions
    if (nIndex == 0) bBT = false;
    if (nState == BARSTATE_NEWBAR) {
        if (vPosition != 1 && nPU != null && close(-1) >= nPU && vLastSwing == "L") { // long signal
            if (bBT == true) Strategy.doLong("long", Strategy.MARKET, Strategy.THISBAR);
            vPosition = 1;
            drawShape(Shape.UPARROW, BelowBar1, Color.green);
            drawText("Long", BelowBar2, Color.green, Text.FRAME|Text.BOLD, rawtime(0));
        } else if (vPosition != -1 && nPD != null && close(-1) <= nPD && vLastSwing == "H") { // short signal
            if (bBT == true) Strategy.doShort("short", Strategy.MARKET, Strategy.THISBAR);
            vPosition = -1;
            drawShape(Shape.DOWNARROW, AboveBar1, Color.red);
            drawText("Short", AboveBar2, Color.red, Text.FRAME|Text.BOLD, rawtime(0));
        }
    }
    
    return new Array(nPD, nPU);
}



/******  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;
        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;
        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);
        if (vLastSwing == "L") y2b = getValue(sLSource);

        //TASC mod
        if (aSwingsPrice[0] != null && vLastSwing != null) {
            if (vLastSwing == "H") {
                nPD = aSwingsPrice[1] - (aSwingsPrice[1]*0.05);
            } else if (vLastSwing == "L") {
                nPU = aSwingsPrice[1] + (aSwingsPrice[1]*0.05);
            }
            
        }

    }

    // 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;
}