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