TriPatternRank.efs
File Name: TriPatternRank.efs
Description:
Based on Mechanically Recognizing Triangular Formations by Giorgos Siligardos, Ph.D. This article appeared in the March 2004 issue of Stock & Commodities.
Formula Parameters:
- Swing: # of Bars - 1
- Swing: Wave Type - %Change in Price [%Change in Price, %Retracement]
- Swing: Wave Percentage - 20%
- Swing High Price Source - Close [Open, High, Low, Close]
- Swing Low Price Source - Close [Open, High, Low, Close]
- Line Thickness - 2
- Confirmed Swing Line Color - Blue
- Developing Swing Line Color - Yellow
Notes:
The related article is copyrighted material. If you are not a subscriber of Stocks & Commodities, please visit www.traders.com.
This formula has a minor modification made to it since the publication of the article. The logic for current developing leg of the zig zag has been modified to draw B-r line from point B to current bar close (r).
Download File:
TriPatternRank.efs
EFS Code:
/***************************************************************** Provided By : eSignal. (c) Copyright 2004 Study: Triangular Pattern Rank Version: 1.1 1/21/2004 Formula Parameters: Default: * Swing: # of Bars 1 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 3 represents 3.0%. The number 0.03 represents 0.0003%. * Swing High Price Source Close * Swing Low Price Source Close * Line Thickness 2 * Confirmed Swing Line Color Blue * Developing Swing Line Color Yellow Notes: 1.1 *Modified logic for current developing leg of the zig zag to draw B-r line from B to current bar close (r). *****************************************************************/ function preMain() { setPriceStudy(true); setStudyTitle("Triangular Pattern Rank "); setShowCursorLabel(false); setShowTitleParameters(false); setDefaultBarFgColor(Color.cyan); //setComputeOnClose(); var fp1 = new FunctionParameter("nNum", FunctionParameter.NUMBER); fp1.setName("Swing: # of Bars"); fp1.setLowerLimit(1); fp1.setDefault(1); 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 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("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.yellow); } 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 cColorDev = 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 var nScntr = 0; // bar counter for swing confirmation var nSpace = null; // space between labels and bars var A = null; // Linear Regression y = Ax + B var B = null; // Linear Regression y = Ax + B var r2 = 0; // Linear Regression r-squared var MA5 = null; // 5 period MA Study var SS = 0; // Small Swings counter var nTPR = 0; // Triangular Pattern Rank function main(nNum, sWaveType, nRet, sHighSource, sLowSource, nThickness, cColor1, cColor2) { var nState = getBarState(); var nIndex = getCurrentBarIndex(); var h = getValue(sHighSource); var l = getValue(sLowSource); var c = close(); // 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; } //Initialization 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 (cColorDev == null) cColorDev = cColor2; if (sHSource == null) sHSource = sHighSource; if (sLSource == null) sLSource = sLowSource; if (x1a == null) x1a = 0; if (y1a == null) y1a = c; if (nSpace == null) { nSpace = ((high() - low())*.2); TFlabels(false, "NA"); } if (MA5 == null) MA5 = new MAStudy(5, 0, "Close", MAStudy.SIMPLE); if (bInit == false) { bInit = Init(h,l,c); } // Swings if (nState == BARSTATE_NEWBAR) { nScntr += 1; // confirm Swings if (nScntr > nNumBars) { confirmSwings(); if (bInit == true) { doLine("dev1"); doLine("dev2"); } } } checkSwings(h, l); if (bInit == true) doLine("dev2"); //Linear Regression RegTriangle(); return MA5.getValue(MAStudy.MA); } /***********************/ /****** 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); x1a = x2a; y1a = y2a; x1b = x2b; y1b = y2b; x2a = x1b; y2a = y1b; if (vLastSwing == "H") y2b = getValue(sHSource); if (vLastSwing == "L") y2b = getValue(sLSource); } // dev1 if (sType == "dev1") { drawLineRelative(x1a, y1a, x1b, y1b, PS_SOLID, nThicknessG, cColorDev, sType); } // dev2 if (sType == "dev2") { if (x2a != 0 && x2a != x2b) { drawLineRelative(x2a, y2a, 0, close(), PS_SOLID, nThicknessG, cColorDev, sType); } else { removeLine(sType); } } return; } function TFlabels(bTF, nSS) { drawTextAbsolute(2, 100, "TF = "+bTF, Color.maroon, null, Text.BOLD|Text.ONTOP|Text.LEFT|Text.BOTTOM|Text.RELATIVETOBOTTOM, null, 14, "TF"); var nR = (Math.abs(y2a-y2b) / Math.abs(y1b-y1a)); if (nR > 0) { nR = (100*nR).toFixed(2) + "%"; } else { nR = "NA"; } drawTextAbsolute(2, 80, "TPR = "+nTPR, Color.maroon, null, Text.BOLD|Text.ONTOP|Text.LEFT|Text.BOTTOM|Text.RELATIVETOBOTTOM, null, 14, "TPR"); drawTextAbsolute(2, 40, "%Ret = "+nR, Color.maroon, null, Text.BOLD|Text.ONTOP|Text.LEFT|Text.BOTTOM|Text.RELATIVETOBOTTOM, null, 14, "Ret"); drawTextAbsolute(2, 20, "SS = "+nSS, Color.maroon, null, Text.BOLD|Text.ONTOP|Text.LEFT|Text.BOTTOM|Text.RELATIVETOBOTTOM, null, 14, "SS"); 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 RegTriangle() { var nState = getBarState(); var nIndex = getCurrentBarIndex(); var i = 0; // y = Ax + B; // A = SUM( (x-xAVG)*(y-yAVG) ) / SUM( (x-xAVG)^2 ) // B = yAVG - (A*xAVG) // Slope = -1 * A if (nScntr < 10 || nScntr > 60) { //removeLine("reg"); removeLine("Up"); removeLine("Dn"); nTPR = 0; TFlabels(false, 0); } else { var aReg = close(0, -nScntr); var vClose = aReg[0]; if (aReg[nScntr-1] != null) { LinReg(aReg, aReg.length, true); // Reg //drawLineRelative(0, B, -(nScntr-1), (A*(nScntr-1)) + B, PS_SOLID, 1, Color.blue, "reg"); //Up and Down indicators var aUp = new Array(nScntr); var aDn = new Array(nScntr); var RegValue = B; // Reg indicator values SS = 0; // Small Swings i = 0; for (i = 0; i < nScntr; ++i) { if (aReg[i] > RegValue) { aUp[i] = aReg[i]; } if (aReg[i] < RegValue) { aDn[i] = aReg[i]; } if (i < nScntr-1) { var vMA0 = MA5.getValue(MAStudy.MA, -i); var vMA1 = MA5.getValue(MAStudy.MA, (-i-1)); if (vMA0 > RegValue && vMA1 <= RegValue + A) SS += 1; if (vMA0 < RegValue && vMA1 >= RegValue + A) SS += 1; } RegValue += A; } i = 0; var j = 0; for (i = 0; i < nScntr; ++i) { if (aUp[i] == null) { j = 0; for (j = i+1; j < nScntr; ++j) { if (aUp[j] != null) { aUp[i] = aUp[j]; j = nScntr; } } } if (aDn[i] == null) { j = 0; for (j = i+1; j < nScntr; ++j) { if (aDn[j] != null) { aDn[i] = aDn[j]; j = nScntr; } } } } LinReg(aUp, aUp.length, false); var UpSlope = -A; drawLineRelative(0, B, -(nScntr-1), (A*(nScntr-1)) + B, PS_SOLID, 2, Color.red, "Up"); LinReg(aDn, aDn.length, false); var DnSlope = -A; drawLineRelative(0, B, -(nScntr-1), (A*(nScntr-1)) + B, PS_SOLID, 2, Color.red, "Dn"); } /*** Triangular Formation (TF) ***/ var bTF = true; var pcntRetracement = (Math.abs(y2a-y2b) / Math.abs(y1b-y1a)); if (SS < 3) bTF = false; if (UpSlope >= 0 || DnSlope <= 0) bTF = false; if (pcntRetracement > 0.50) bTF = false; if (bTF == false) nTPR = 0; /*** Triangular Pattern Rank (TPR) ***/ if (bTF == true) { nTPR = 1; //rule 1 if (nScntr >= 15 && nScntr <= 30) nTPR += 2; if (nScntr > 30 && nScntr <= 55) nTPR += 1; //rule 2 if (r2 <= 0.2) nTPR += 2; if (r2 > 0.2 && r2 <= 0.5) nTPR += 1; //rule 3 if (pcntRetracement <= 0.20) nTPR += 4; if (pcntRetracement > 0.20 && pcntRetracement <= 0.38) nTPR += 3; //rule 4 var aVol = volume(0, -nScntr); LinReg(aVol, aVol.length, false); if (-A < 0) nTPR += 4; } TFlabels(bTF, SS); } return; } function LinReg(vArray, nLength, bR2) { var Len = nLength; var xSum = 0; var ySum = 0; var i = 0; for (i = 0; i < nLength; ++i) { if (vArray[i] == null) Len -= 1; } for (i = 0; i < Len; ++i) { xSum += i; ySum += vArray[i]; } var xAvg = xSum/Len; var yAvg = ySum/Len; var aSum1 = 0; var aSum2 = 0; var aSum3 = 0; i = 0; for (i = 0; i < Len; ++i) { aSum1 += (i-xAvg) * (vArray[i]-yAvg); aSum2 += (i-xAvg)*(i-xAvg); aSum3 += (vArray[i]-yAvg)*(vArray[i]-yAvg); } A = (aSum1 / aSum2); B = yAvg - (A*xAvg); // r-squared if (bR2 == true) r2 = (aSum1*aSum1) / (aSum2*aSum3); return; }