Trendline_Breaks.efs
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; }