TSR PINE SCRIPT

// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // © ismailcarlik //@version=5 indicator("Trend Lines, Supports and Resistances", shorttitle = "TSR", overlay = true, max_bars_back = 5000) // ╔═════════════════════════════════════════════════════════════════════════════════════════════╗ // ║ * * * I N P U T S * * * ║ // ╚═════════════════════════════════════════════════════════════════════════════════════════════╝ grpPivotPoints = "Pivot Points ・ Common" pvtLength = input.int(20, title = "Pivot Length", minval = 1, group = grpPivotPoints) pvtMarkPivots = input.bool(false, title = "Mark Pivots", group = grpPivotPoints) pvtAlertsEnabled = input.bool(true, title = "Alerts Enabled", inline = "tlAlerts", group = grpPivotPoints) pvtAlertrequency = input.string("Once Per Bar", title = " ・ Frequency", options = ["Once Per Bar", "Once Per Bar Close", "All"], inline = "tlAlerts", group = grpPivotPoints, display = display.none) grpTrendLines = "Trend Lines" tlEnabled = input.bool(true, title = "Enabled", group = grpTrendLines) tlPointsToCheck = input.int(3, title = "Points to Check", minval = 2, group = grpTrendLines) tlMaxViolation = input.int(0, title = "Maximum Violation", minval = 0, group = grpTrendLines) tlExceptBars = input.int(3, title = "Excepted Last Bars", minval = 0, group = grpTrendLines) tlShowViolated = input.bool(false, title = "Show Violated Trend Lines", group = grpTrendLines) tlExtension = input.string("Right", title = "Line Extension", options = ["None", "Left", "Right", "Both"], group = grpTrendLines) tlShowLabels = input.bool(true, title = "Show Labels", group = grpTrendLines) tlAlertsEnabled = input.bool(true, title = "Alerts Enabled", inline = "tlAlerts", group = grpTrendLines) tlAlertrequency = input.string("Once Per Bar", title = " ・ Frequency", options = ["Once Per Bar", "Once Per Bar Close", "All"], inline = "tlAlerts", group = grpTrendLines, display = display.none) grpSupportResistance = "Supports & Resistances" srEnabled = input.bool(true, title = "Enabled", group = grpSupportResistance) srPointsToCheck = input.int(3, title = "Points to Check", minval = 2, group = grpSupportResistance) srMaxViolation = input.int(0, title = "Maximum Violation Allowed", minval = 0, group = grpSupportResistance) srExceptBars = input.int(3, title = "Excepted Last Bars", minval = 0, group = grpSupportResistance) srShowLabels = input.bool(true, title = "Show Labels", group = grpSupportResistance) srAlertsEnabled = input.bool(true, title = "Alerts Enabled", inline = "srAlerts", group = grpSupportResistance) srAlertrequency = input.string("Once Per Bar", title = " ・ Frequency", options = ["Once Per Bar", "Once Per Bar Close", "All"], inline = "srAlerts", group = grpSupportResistance, display = display.none) grpVisual = "Style" stlHighColor = input.color(color.blue, title = "High Color", inline = "colors", group = grpVisual) stlLowColor = input.color(color.red, title = "Low Color", inline = "colors", group = grpVisual) lineWidth = input.int(1, title = "Line Width", minval = 1, group = grpVisual) // ╔═════════════════════════════════════════════════════════════════════════════════════════════╗ // ║ * * * T Y P E S * * * ║ // ╚═════════════════════════════════════════════════════════════════════════════════════════════╝ // @type Used to represent a point pair. // @field firstPoint First point of pair. // @field secondPoint Second point of pair. type pointPair chart.point firstPoint chart.point secondPoint // @type Used to represent a trend line. // @field mainLine Main visible line of the trend. // @field extensionLine Extension line of the trend. // @field priceLabel Price label of the trend. // @field isViolated Violation status of the trend. type trendLine line mainLine line extensionLine = na label priceLabel = na bool isViolated = false // @type Used to represent a support or resistance level. // @field levelBox Level box for support or resistance. // @field price Price level of the support or resistance. // @field priceLabel Price label of the support or resistance. type srLevel box levelBox float price label priceLabel = na // ╔═════════════════════════════════════════════════════════════════════════════════════════════╗ // ║ * * * V A R I A B L E S * * * ║ // ╚═════════════════════════════════════════════════════════════════════════════════════════════╝ tlExtendMode = str.lower(array.get(str.split(tlExtension, ""), 0)) tlAlertrequencyMode = switch tlAlertrequency "Once Per Bar" => alert.freq_once_per_bar "Once Per Bar Close" => alert.freq_once_per_bar_close "All" => alert.freq_all => alert.freq_once_per_bar srAlertrequencyMode = switch srAlertrequency "Once Per Bar" => alert.freq_once_per_bar "Once Per Bar Close" => alert.freq_once_per_bar_close "All" => alert.freq_all => alert.freq_once_per_bar pvtAlertrequencyMode = switch pvtAlertrequency "Once Per Bar" => alert.freq_once_per_bar "Once Per Bar Close" => alert.freq_once_per_bar_close "All" => alert.freq_all => alert.freq_once_per_bar var array highPivots = array.new() var array lowPivots = array.new() var array uptrends = array.new() var array downtrends = array.new() var array supports = array.new() var array resistances = array.new() // ╔═════════════════════════════════════════════════════════════════════════════════════════════╗ // ║ * * * M E T H O D S * * * ║ // ╚═════════════════════════════════════════════════════════════════════════════════════════════╝ // @function Returns reversed version of array. // @param id (chart.point[]) Array object. // @returns (chart.point[]) Reversed version of given array. method reversed(array id) => array reversedArray = array.new() for [i, v] in id reversedArray.unshift(v) reversedArray // @function Checks for the bars if highs above trend line price. // @param id (trendLine) Trend line object. // @param exceptBars (int) Count of last bars for exception. // @returns (int) Count of the bars above trend line price. method getHighsAbovePrice(trendLine id, int exceptBars) => historyReference = bar_index - id.mainLine.get_x1() count = 0 if exceptBars < historyReference for i = historyReference to exceptBars if high[i] > line.get_price(id.mainLine, bar_index - i) count += 1 count // @function Checks for the bars if lows below trend line price. // @param id (trendLine) Trend line object. // @param exceptBars (int) Count of last bars for exception. // @returns (int) Count of the bars below trend line price. method getLowsBelowPrice(trendLine id, int exceptBars) => historyReference = bar_index - id.mainLine.get_x1() count = 0 if exceptBars < historyReference for i = historyReference to exceptBars if low[i] < line.get_price(id.mainLine, bar_index - i) count += 1 count // @function Sets the trend lines status to violated. // @param id (trendLine) Trend line object. // @param trendColor (color) Color of the trend line. // @returns (void) method setViolated(trendLine id, color trendColor) => id.isViolated := true line.delete(id.extensionLine) label.delete(id.priceLabel) line.set_style(id.mainLine, line.style_dotted) line.set_extend(id.mainLine, extend = tlExtendMode) line.set_color(id.mainLine, tlShowViolated ? color.new(trendColor, 50) : na) // ╔═════════════════════════════════════════════════════════════════════════════════════════════╗ // ║ * * * F U N C T I O N S * * * ║ // ╚═════════════════════════════════════════════════════════════════════════════════════════════╝ // @function Compares two points and returns true if first one is higher. // @param firstPoint (chart.point) First point to compare. // @param secondPoint (chart.point) Second point to compare. // @returns (bool) Whether the first point is higher than the second. f_isHigher (chart.point firstPoint, chart.point secondPoint) => firstPoint.price > secondPoint.price // @function Compares two points and returns true if first one is lower. // @param firstPoint (chart.point) First point to compare. // @param secondPoint (chart.point) Second point to compare. // @returns (bool) Whether the first point is lower than the second. f_isLower (chart.point firstPoint, chart.point secondPoint) => firstPoint.price < secondPoint.price // @function Checks for violation of support level. // @param point (chart.point) Point of support level. // @param exceptBars (int) Count of last bars for exception. // @returns (int) Count of violations. f_checkSupportViolation (chart.point point, int exceptBars) => historyReference = bar_index - point.index violationCount = 0 if exceptBars < historyReference for i = historyReference to exceptBars if low[i] < point.price violationCount += 1 violationCount // @function Checks for violation of reistance level. // @param point (chart.point) Point of resistance level. // @param exceptBars (int) Count of last bars for exception. // @returns (int) Count of violations. f_checkResistanceViolation(chart.point point, int exceptBars) => historyReference = bar_index - point.index violationCount = 0 if exceptBars < historyReference for i = historyReference to exceptBars if high[i] > point.price violationCount += 1 violationCount // @function Draws support level to chart. // @param index (int) Bar index of support level. // @returns (void) f_drawSupport(int index) => historyReference = bar_index - index lowValue = low[historyReference] boxColor = color.new(stlHighColor, 70) textColor = color.new(stlHighColor, 50) supportBox = box.new(left = index, top = math.min(open[historyReference], close[historyReference]), right = bar_index, bottom = lowValue, bgcolor = boxColor, border_color = boxColor) supportLabel = srShowLabels ? label.new(x = bar_index - int(historyReference / 2), y = lowValue, text = "Support : " + str.tostring(lowValue, format.mintick), style = label.style_label_up, color = color.new(boxColor, 100), textcolor = textColor) : na supports.push(srLevel.new(levelBox = supportBox, price = lowValue, priceLabel = supportLabel)) // @function Draws resistance level to chart. // @param index (int) Bar index of reistance level. // @returns (void) f_drawResistance(int index) => historyReference = bar_index - index highValue = high[historyReference] boxColor = color.new(stlLowColor, 70) textColor = color.new(stlLowColor, 50) resistanceBox = box.new(left = index, top = highValue, right = bar_index, bottom = math.max(open[historyReference], close[historyReference]), bgcolor = boxColor, border_color = boxColor) resistanceLabel = srShowLabels ? label.new(x = bar_index - int(historyReference / 2), y = highValue, text = "Resistance : " + str.tostring(highValue, format.mintick), style = label.style_label_down, color = color.new(boxColor, 100), textcolor = textColor) : na resistances.push(srLevel.new(levelBox = resistanceBox, price = highValue, priceLabel = resistanceLabel)) // @function Gets all pair combinations of given point array. // @param srcArray (chart.point[]) Source array. // @returns (pointPair[]) Array of point pairs. f_getAllPairCombinations(array srcArray) => int inputLength = array.size(srcArray) array pairs = array.new() for i = 0 to inputLength - 2 by 1 for j = i + 1 to inputLength - 1 by 1 pairs.push(pointPair.new(firstPoint = srcArray.get(i), secondPoint = srcArray.get(j))) pairs // @function Draws an uptrend to chart. // @param start (chart.point) Starting point of trend line. // @param end (chart.point) Ending point of trend line. // @returns (void) f_drawUptrend(chart.point start, chart.point end) => uExtension = tlExtendMode == "n" ? na : line.new(start, end, color = color.new(stlHighColor, 50), extend = tlExtendMode, style = line.style_dashed, width = lineWidth) uMain = line.new(start, end, color = stlHighColor, style = line.style_arrow_both, width = lineWidth) uPrice = line.get_price(uMain, bar_index) uLabel = tlShowLabels ? label.new(x = bar_index, y = uPrice, text = "Uptrend : " + str.tostring(uPrice, format.mintick), style = label.style_label_left, color = color.new(stlHighColor, 80), textcolor = stlHighColor) : na uptrends.push(trendLine.new(mainLine = uMain, extensionLine = uExtension, priceLabel = uLabel)) // @function Draws a downtrend to chart. // @param start (chart.point) Starting point of trend line. // @param end (chart.point) Ending point of trend line. // @returns (void) f_drawDowntrend(chart.point start, chart.point end) => uExtension = tlExtendMode == "n" ? na : line.new(start, end, color = color.new(stlLowColor, 50), extend = tlExtendMode, style = line.style_dashed, width = lineWidth) uMain = line.new(start, end, color = stlLowColor, style = line.style_arrow_both, width = lineWidth) uPrice = line.get_price(uMain, bar_index) uLabel = tlShowLabels ? label.new(x = bar_index, y = uPrice, text = "Downtrend : " + str.tostring(uPrice, format.mintick), style = label.style_label_left, color = color.new(stlLowColor, 80), textcolor = stlLowColor) : na downtrends.push(trendLine.new(mainLine = uMain, extensionLine = uExtension, priceLabel = uLabel)) // @function Clears all lines, boxes, labels off the chart and empties all trend line, support and resistance arrays. // @returns (void) f_clearAll() => for [i, v] in line.all line.delete(v) for [i, v] in box.all box.delete(v) for [i, v] in label.all label.delete(v) supports.clear() resistances.clear() uptrends.clear() downtrends.clear() // ╔═════════════════════════════════════════════════════════════════════════════════════════════╗ // ║ * * * C A L C U L A T I O N S * * * ║ // ╚═════════════════════════════════════════════════════════════════════════════════════════════╝ ph = ta.pivothigh(pvtLength, pvtLength) pl = ta.pivotlow(pvtLength, pvtLength) if not na(ph) highPivots.unshift(chart.point.from_index(bar_index[pvtLength], ph)) if pvtAlertsEnabled alert(str.format("New possible resistance (high pivot) detected at {0} now.", str.tostring(ph, format.mintick)), pvtAlertrequencyMode) if not na(pl) lowPivots.unshift(chart.point.from_index(bar_index[pvtLength], pl)) if pvtAlertsEnabled alert(str.format("New possible support (low pivot) detected at {0} now.", str.tostring(pl, format.mintick)), pvtAlertrequencyMode) // ╔═════════════════════════════════════════════════════════════════════════════════════════════╗ // ║ * * * P L O T S * * * ║ // ╚═════════════════════════════════════════════════════════════════════════════════════════════╝ if barstate.islast f_clearAll() if tlEnabled for [i, v] in f_getAllPairCombinations(lowPivots.slice(0, tlPointsToCheck).reversed()) if f_isLower(v.firstPoint, v.secondPoint) f_drawUptrend(v.firstPoint, v.secondPoint) for [i, v] in uptrends if v.getLowsBelowPrice(exceptBars = tlExceptBars) > tlMaxViolation v.setViolated(trendColor = stlHighColor) for [i, v] in uptrends trendPrice = line.get_price(v.mainLine, bar_index) if not v.isViolated and low <= trendPrice and tlAlertsEnabled alert(str.format("Uptrend at {0} broken with a new low price at {1} now.", str.tostring(trendPrice, format.mintick), str.tostring(low, format.mintick)), tlAlertrequencyMode) for [i, v] in f_getAllPairCombinations(highPivots.slice(0, tlPointsToCheck).reversed()) if f_isHigher(v.firstPoint, v.secondPoint) f_drawDowntrend(v.firstPoint, v.secondPoint) for [i, v] in downtrends if v.getHighsAbovePrice(exceptBars = tlExceptBars) > tlMaxViolation v.setViolated(trendColor = stlLowColor) for [i, v] in downtrends trendPrice = line.get_price(v.mainLine, bar_index) if not v.isViolated and high >= trendPrice and tlAlertsEnabled alert(str.format("Downtrend at {0} broken with a new high price at {1} now.", str.tostring(trendPrice, format.mintick), str.tostring(high, format.mintick)), tlAlertrequencyMode) if srEnabled sCount = 0, lIndex = 0 rCount = 0, hIndex = 0 while sCount < srPointsToCheck if f_isLower(lowPivots.get(lIndex), lowPivots.get(lIndex + 1)) if f_checkSupportViolation(lowPivots.get(lIndex), exceptBars = srExceptBars) <= srMaxViolation f_drawSupport(lowPivots.get(lIndex).index) sCount += 1 lIndex += 1 while rCount < srPointsToCheck if f_isHigher(highPivots.get(hIndex), highPivots.get(hIndex + 1)) if f_checkResistanceViolation(highPivots.get(hIndex), exceptBars = srExceptBars) <= srMaxViolation f_drawResistance(highPivots.get(hIndex).index) rCount += 1 hIndex += 1 for [i, v] in supports if low <= v.price and srAlertsEnabled alert(str.format("Support at {0} broken by new low price at {1} now.", str.tostring(v.price, format.mintick), str.tostring(low, format.mintick)), srAlertrequencyMode) for [i, v] in resistances if high >= v.price and srAlertsEnabled alert(str.format("Resistance at {0} broken by new high price at {1} now.", str.tostring(v.price, format.mintick), str.tostring(high, format.mintick)), srAlertrequencyMode) plotshape(not na(ph) and pvtMarkPivots ? ph : na, title = "High Pivots", style = shape.triangleup, color = stlHighColor, location = location.abovebar, size = size.tiny, offset = -pvtLength) plotshape(not na(pl) and pvtMarkPivots ? pl : na, title = "Low Pivots", style = shape.triangledown, color = stlLowColor, location = location.belowbar, size = size.tiny, offset = -pvtLength)