// Downloaded From https://www.WiseStockTrader.com /* * Name: Automatic Trend Lines * This Amibroker script is designed to automate the process of drawing: * 1. Trend lines (sloping) * 2. Support & resistance lines (horizontal) * 3. Channel lines (parallel lines to trend lines & horizontal lines) * This script is not a recommendation to buy or sell anything. It's to be * used as is without any guarantees or warranties on its reliability. * Author: Prajan * Version: v2.0.2 (20160816) * */ /* * USER DEFINED PARAMETERS */ // We only want to draw trend lines where they are within +/-X% of the last close PctLmt = Param("% from last Close to draw", 3, 0, 100, 1, 0); // Number of breaks allowed before NullBars area BreaksLimit = Param("Number of breaks allowed (before NullBars)", 2, 0, 100, 1, 0); // Do we deem a price body as a valid "break"? If just the close as a valid break leave No. OpenBreak = ParamToggle("Price body considered break?", "No|Yes", 0); // What are the minimum numbers of touches to draw a trend line, being mindful // that a sloping trend line already has two trend line touches, whereas horizontal // and channel lines only have one. TouchesLimit = Param("Minimum trend line touches", 2, 0, 10, 1, 0); // Only look back over the last X number of bars from the right-most edge of // the chart. By placing a value in here besides 0 it can help speed up the // computation time spent with processing this script. LastBars = Param("Only use last X bars (0 = Use all)", 0, 0, 10000, 100, 0); // Ignore all trend line breaks and touches in the last X bars NullBars = Param("Ignore touches and breaks in last X bars", 10, 0, 100, 1, 0); // Swing level SwingPoints = Param("Swing points", 2, 1, 3, 1, 0 ); // Do you wish to plot sloping trend lines? PlotTL = ParamToggle("Plot trend lines?", "No|Yes", 1); // Do you wish to plot horizontal support and resistance lines? PlotSR = ParamToggle("Plot sup/res lines?", "No|Yes", 1); // Do you wish to plot sloping channel lines? PlotChannels = ParamToggle("Plot channel lines?", "No|Yes", 1); // What colour do you wish to plot for upper lines? UpperColor = ParamColor("Upper trend line colours", ColorRGB( 17,199,251 ) ); // What colour do you wish to plot for lower lines? LowerColor = ParamColor("Lower trend line colours", ColorRGB( 243,126,120 ) ); // Do you wish to plot upper lines? PlotUpper = ParamToggle("Plot upper lines?", "No|Yes", 1); // Do you wish to plot lower lines? PlotLower = ParamToggle("Plot lower lines?", "No|Yes", 1); /* * FUNCTIONS */ // Determine if the bars passed in form a swing high. // @param {int} left bar // @param {int} middle bar // @param {int} right bar // @return {boolean} if the three bars have created a swing high is True function isSwingHigh( left, middle, right ) { result = False; if ( H[left] <= H[middle] && H[middle] > H[right] ) result = True; return result; } // Determines if the bars passed in form a swing low. // @param {int} left bar // @param {int} middle bar // @param {int} right bar // @return {boolean} if the three bars have created a swing low is True function isSwingLow( left, middle, right ) { result = False; if ( L[left] >= L[middle] && L[middle] < L[right] ) result = True; return result; } // This function refines the swing array. // @param {int[]} array of bar indexes // @param {boolean} get swing high if True, otherwise get swing lows // @return {int[]} array of bar indexes function getSwingArray( swing, isHigh ) { z = 0; result = Null; for ( i = 2; i < BarCount; i += 1 ) { if ( IsNull( swing[i] ) ) break; if ( swing[i] < BarCount-LastBars && LastBars > 0 ) continue; if ( isHigh && isSwingHigh( swing[i-2], swing[i-1], swing[i] ) ) { result[z] = swing[i-1]; z = z + 1; } else if ( !isHigh && isSwingLow( swing[i-2], swing[i-1], swing[i] ) ) { result[z] = swing[i-1]; z = z + 1; } } return result; } // This function returns the highest or lowest bar between two bars. // @param {int} bar1 - the leftmost bar // @param {int} bar2 - the rightmost bar // @param {boolean} isHigh - get highest bar if True, otherwise lowest bar // @return {int} highest or lowest bar function getBar( bar1, bar2, isHigh ) { result = bar1; for ( i = bar1; i <= bar2; i += 1 ) { if ( isHigh && H[i] >= H[result] ) result = i; if ( !isHigh && L[i] <= L[result] ) result = i; } return result; } // This function calculates the slope value. // @param {int} bar1 // @param {int} bar2 // @param {boolean} isHigh // @return {double} slope value function getSlope( bar1, bar2, isHigh ) { result = -1; if ( bar1 - bar2 == 0 ) { result = 0; } else if ( isHigh ) { result = ( H[bar1] - H[bar2] ) / ( bar1 - bar2 ); } else if ( !isHigh ) { result = ( L[bar1] - L[bar2] ) / ( bar1 - bar2 ); } return result; } // This function plots the trend line. Don't directly call from code, // pass through the checkTrendline procedure first. // @param {int} bar1 // @param {int} bar2 // @param {boolean} isHigh // @param {double} slope // @param {int} tlType 0 = horizontal; 1 = sloping; -1 = parallel (channel) // @return {boolean} was trend line plotted? function plotTrendLine( bar1, bar2, isHigh, slope, tlType ) { touches = 1; // being i == bar1 breaks = 0; isPlotted = False; flag = 0; for ( i = bar1+1; i < BarCount-NullBars; i += 1 ) { if ( isHigh ) { trendlineValue = H[bar1] + ( slope * ( i - bar1 ) ); if ( C[i] > trendlineValue ) { breaks = breaks + 1; } else if ( O[i] > trendlineValue && OpenBreak ) { breaks = breaks + 1; } // rather than just being a touch we're checking that the touch // was a swing point as trendlines can go through a cluster of price // points and meet the touch trigger, here we're refining what's // classified as a legitimate "touch" if ( H[i] >= trendlineValue ) flag = i+1; if ( flag == i && isSwingHigh( i-2, i-1, i ) ) touches = touches + 1; } else { trendlineValue = L[bar1] + ( slope * ( i - bar1 ) ); if ( C[i] < trendlineValue ) { breaks = breaks + 1; } else if ( O[i] < trendlineValue && OpenBreak ) { breaks = breaks + 1; } if ( L[i] <= trendlineValue ) flag = i+1; if ( flag == i && isSwingLow( i-2, i-1, i ) ) touches = touches + 1; } if ( breaks > BreaksLimit ) break; } if ( breaks <= BreaksLimit && touches >= TouchesLimit ) { // time to plot the trend line if ( isHigh ) { // Plot if parallel (channel) line if ( tlType == -1 ) { trendlineArray = LineArray( bar1, H[bar1], bar1+1, H[bar1]+slope, 1 ); Plot( trendlineArray, "ch-up-"+bar1, LowerColor ); } // Plot if horizontal line if ( tlType == 0 ) { trendlineArray = LineArray( bar1, H[bar1], BarCount, H[bar1], 1 ); Plot( trendlineArray, "hz-"+bar1, UpperColor ); } // Plot if sloping line if ( tlType == 1 ) { trendlineArray = LineArray( bar1, H[bar1], bar2, H[bar2], 1 ); Plot( trendlineArray, "tl-up-"+bar1+"."+bar2, UpperColor ); } isPlotted = True; } else { if ( tlType == -1 ) { trendlineArray = LineArray( bar1, L[bar1], bar1+1, L[bar1]+slope, 1 ); Plot( trendlineArray, "ch-dn-"+bar1, UpperColor ); } if ( tlType == 0 ) { trendlineArray = LineArray( bar1, L[bar1], BarCount, L[bar1], 1 ); Plot( trendlineArray, "hz-"+bar1, LowerColor ); } if ( tlType == 1 ) { trendlineArray = LineArray( bar1, L[bar1], bar2, L[bar2], 1 ); Plot( trendlineArray, "tl-dn-"+bar1+"."+bar2, LowerColor ); } isPlotted = True; } } return isPlotted; } // Here is the main procedure that plots trend lines, however, it's // operating as a gatekeeper to help determine whether values inserted // into the parameters are valid. The types of trend lines passed through // this function are: // 1. Sloping trend lines (required = bar1, bar2, isHigh, slope) // 2. Horizontal support & resistance lines (required = bar1, isHigh, slope) // 3. Sloping channel lines (required = bar1, bar2, isHigh, slope) // @param {int} bar1 // @param {int} bar2 // @param {boolean} isHigh // @param {double} slope // @param {int} tlType 0 = horizontal; 1 = sloping; -1 = parallel (channel) procedure checkTrendline( bar1, bar2, isHigh, slope, tlType ) { if ( IsNull( bar2 ) ) bar2 = 0; if ( IsNull( slope ) && bar1 == bar2 ) slope = 0; if ( IsNull( slope ) ) slope = getSlope( bar1, bar2, isHigh ); if ( isHigh ) trendlineEnd = H[bar1] + ( slope * ( BarCount-1 - bar1 ) ); if ( !isHigh ) trendlineEnd = L[bar1] + ( slope * ( BarCount-1 - bar1 ) ); if ( abs( 1 - ( trendlineEnd / LastValue( C ) ) ) * 100 <= PctLmt ) { if ( plotTrendline( bar1, bar2, isHigh, slope, tlType ) ) { // Check corresponding channel lines if ( PlotChannels ) { channelBar = getBar( bar1, bar2, !isHigh ); plotTrendline( channelBar, channelBar, !isHigh, slope, -1 ); } } } } /* * MAIN * Here is the beginning of the script. */ // 1. Initialise our swing points with all bars swingHighs = BarIndex(); swingLows = BarIndex(); // 2. Recursively loop through the array by obtaining the SwingPoint level needed for ( i = 0; i < SwingPoints; i += 1 ) { if ( PlotUpper ) swingHighs = getSwingArray( swingHighs, True ); if ( PlotLower ) swingLows = getSwingArray( swingLows, False ); } // 3. Count the number of elements in the array swingHighCount = BarCount - NullCount( swingHighs, 0 ); swingLowCount = BarCount - NullCount( swingLows, 0 ); // 4a. Loop through the swing high array for ( a = 0; a < swingHighCount; a += 1 ) { for ( b = a+1; b < swingHighCount; b += 1 ) { bar1 = swingHighs[a]; bar2 = swingHighs[b]; if ( !IsNull( bar1 ) && !IsNull( bar2 ) ) { slope = getSlope( bar1, bar2, True ); // Check sloping trend lines if ( PlotTL ) checkTrendLine( bar1, bar2, True, slope, 1 ); // Check horizontal resistance lines if ( PlotSR ) checkTrendLine( bar1, bar1, True, 0, 0 ); } } } // 4b. Loop through the swing low array for ( a = 0; a < swingLowCount; a += 1 ) { for ( b = a+1; b < swingLowCount; b += 1 ) { bar1 = swingLows[a]; bar2 = swingLows[b]; if ( !IsNull( bar1 ) && !IsNull( bar2 ) ) { slope = getSlope( bar1, bar2, False ); // Check sloping trend lines if ( PlotTL ) checkTrendLine( bar1, bar2, False, slope, 1 ); // Check horizontal resistance lines if ( PlotSR ) checkTrendLine( bar1, bar1, False, 0, 0 ); } } }