Last active
July 7, 2025 13:24
-
-
Save niquedegraaff/4428558435f74cd30de1d9b95895af01 to your computer and use it in GitHub Desktop.
Enhanced version 3 of built-in ZigZagLib library. This version supports HH LH / LL HL labels to be shown, it also exports a prevPivot function that allows the user to retrieve the previous privot with same isHigh value as latest pivot. It also stores a isHigher field in the Pivot type. This can come in handy if user wants to calculate a trend (o…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ | |
// © niquedegraaff | |
//@version=6 | |
library("Absolute_ZigZag_Lib", overlay = true) | |
// @type The source to use | |
// @param high (float) The high value for the pivot lows. | |
// @param low (float) The low value for the pivot highs. | |
// @param priority (string) Which source has higher priority ("high" or "low"). Default is "high" | |
export type Source | |
float high = high | |
float low = low | |
string priority = "high" | |
// @type Features to enable | |
// @param closeBreaksClose (bool) Check if current (highest/lowest) pivot close broke previous pivot close. | |
// @param closeBreaksPivot (bool) Check if current (highest/lowest) pivot close broke previous pivot (high or low). | |
export type Features | |
bool closeBreaksClose = false | |
bool closeBreaksPivot = false | |
// @type Tooltips to show | |
// @param name (bool) Show the pivot's name in the tooltip? | |
// @param price (bool) Show the pivot's price in the tooltip? | |
// @param close (bool) Show the pivot's close price in the tooltip? | |
// @param closeBreaksClose (bool) Show if current (highest/lowest) pivot close broke previous pivot close (Only effective if feature is enabled). | |
// @param closeBreaksPivot (bool) Show if current (highest/lowest) pivot close broke previous pivot (high/low) (Only effective if feature is enabled). | |
export type Tooltips | |
bool name = true | |
bool price = true | |
bool close = true | |
bool closeBreaksClose = false | |
bool closeBreaksPivot = false | |
// @type Theme | |
// @desc Used to define a ZigZag theme with customizable styling options for lines, labels, and tooltips. | |
// @param enabled (bool) Enable built-in ZigZag rendering, including lines and labels. Set to false to fully customize rendering externally. | |
// @param colorDefault (color) The fallback color used when no specific direction is detected. | |
// @param colorNeutral (color) Color used for neutral moves (e.g., equal highs/lows). | |
// @param colorBullish (color) Color used for bullish moves (price going up). | |
// @param colorBearish (color) Color used for bearish moves (price going down). | |
// @param lineWidth (int) Width of the ZigZag lines (1–4). | |
// @param labelSize (string) Size of the label text (e.g., size.small, size.normal, size.large). | |
// @param showLabelL (bool) Show label for regular low pivot ('L'). | |
// @param showLabelLL (bool) Show label for Lower Low pivot ('LL'). | |
// @param showLabelHL (bool) Show label for Higher Low pivot ('HL'). | |
// @param showLabelH (bool) Show label for regular high pivot ('H'). | |
// @param showLabelLH (bool) Show label for Lower High pivot ('LH'). | |
// @param showLabelHH (bool) Show label for Higher High pivot ('HH'). | |
// @param coloredLines (bool) If true, ZigZag lines are colored according to trend direction (bullish/bearish/neutral). | |
// @param showCloseInfo (bool) Show additional price information related to closing values in labels. | |
// @param showTooltips (bool) Enable mouse-over tooltips with additional pivot information. | |
// @param tooltips (Tooltips) Tooltip configuration (e.g., formatting or content rules). | |
export type Theme | |
bool enabled = false | |
color colorDefault = color.gray | |
color colorNeutral = color.yellow | |
color colorBullish = color.green | |
color colorBearish = color.red | |
int lineWidth = 2 | |
string labelSize = size.normal | |
bool showLabelL = true | |
bool showLabelLL = true | |
bool showLabelHL = true | |
bool showLabelH = true | |
bool showLabelLH = true | |
bool showLabelHH = true | |
bool coloredLines = false | |
bool showCloseInfo = false | |
bool showTooltips = true | |
Tooltips tooltips | |
// @type All settings for the indicator | |
// @param source (Source) The source to be used. | |
// @param features (Features) The features to be used. | |
// @param theme (Theme) The theme to be used. | |
// @param limit (int) The max number of pivots to be shown | |
export type Settings | |
Source source | |
Features features | |
Theme theme | |
int limit // Default to a reasonable integer instead of na | |
// @type Used to determine a coordination on the chart | |
// @param x (int) The time | |
// @param y (float) The price | |
export type Point | |
int x // time | |
float y // price | |
// @type Used to determine pivots on the chart. | |
// @param point (Point) The current coordination on the chart | |
// @param isHigh (bool) Whether this Pivot is a pivot high or low. | |
// @param isHigher (bool) Whether this Pivot is higher than the previous paired pivot (not last pivot, but 2 back). Defaults to false instead of na. | |
// @param name (string) The name of the pivot. | |
// @param abbr (string) The abbreviation of the name of the pivot. | |
// @param close (float) The highest/lowest close price of the swing to this pivot. | |
// @param comulativeVolume (float) The cumulative volume for this pivot (optional). | |
// @param closeBreaksClose (bool) Whether the pivot (highest/lowest) close breaks the previous pivot (highest/lowest) close. Defaults to false. | |
// @param closeBreaksPivot (bool) Whether the pivot (highest/lowest) close breaks the previous pivot (high/low). Defaults to false. | |
// @param isLast (bool) Whether this pivot is the most recent one. | |
// @param ln (line) Line to draw (optional) | |
// @param lb (label) Label to draw (optional) | |
export type Pivot | |
Point point | |
bool isHigh | |
bool isHigher = false // Changed from na to false | |
string name = "" | |
string abbr = "" | |
float close = close | |
float comulativeVolume = 0.0 // Changed from na to 0.0 | |
bool closeBreaksPivot = false // Changed from na to false | |
bool closeBreaksClose = false // Changed from na to false | |
bool isLast = true | |
line ln = na | |
label lb = na | |
// @function Gets the first Pivot | |
// @param this (array<Pivot>) The object to work with. | |
// @return (Pivot) The first Pivot in the array or NA if not available. | |
export method getFirst(array<Pivot> this) => | |
this.size() > 0 ? this.get(0) : na | |
// @function Gets the latest Pivot | |
// @param this (array<Pivot>) The object to work with. | |
// @return (Pivot) The last Pivot in the array or NA if not available. | |
export method getLast(array<Pivot> this) => | |
int size = this.size(), size > 0 ? this.get(size - 1) : na | |
// @function Gets previous Pivot by index number. | |
// @param this (array<Pivot>) The object to work with. | |
// @param index (int) The index number (optional, default is 1) | |
// @return (Pivot) The previous Pivot or NA if not available. | |
export method getPrev(array<Pivot> this, int index = 1) => | |
int size = this.size(), size > index ? this.get(size - 1 - index) : na | |
// @function Checks if current pivot is higher than the previous paired pivot (2 back). | |
// @param this (Pivot) The object to work with. | |
// @param pivots (array<Pivot>) The array of pivots. | |
// @return (bool) Whether the pivot is higher or not. Returns false if array is too small (instead of na). | |
method isHigher(Pivot this, Pivot[] pivots) => | |
int size = pivots.size() | |
if size > 2 | |
this.point.y > pivots.get(size - 3).point.y | |
else | |
false // Changed from na to false | |
// @function Checks if the current pivot is at the current bar | |
// @param this (Pivot) The object to work with. | |
// @return (bool) Whether the current pivot is at the current bar or not. | |
export method isAtCurrentBar(Pivot this) => | |
this.point.x >= last_bar_time | |
// @function Checks if current pivot is a higher high | |
// @param this (Pivot) The object to work with. | |
// @return (bool) True if the pivot is a higher high, false if not. | |
export method isHigherHigh(Pivot this) => | |
bool r = this.isHigh and this.isHigher | |
// @function Checks if current pivot is a lower high | |
// @param this (Pivot) The object to work with. | |
// @return (bool) True if the pivot is a lower high, false if not. | |
export method isLowerHigh(Pivot this) => | |
bool r = this.isHigh and not this.isHigher | |
// @function Checks if current pivot is a higher low | |
// @param this (Pivot) The object to work with. | |
// @return (bool) True if the pivot is a higher low, false if not. | |
export method isHigherLow(Pivot this) => | |
bool r = not this.isHigh and this.isHigher | |
// @function Checks if current pivot is a lower low | |
// @param this (Pivot) The object to work with. | |
// @return (bool) True if the pivot is a lower low, false if not. | |
export method isLowerLow(Pivot this) => | |
bool r = not this.isHigh and not this.isHigher | |
// @function Gets the latest Pivot High based on previous number of Pivot highs back. Default is the latest. | |
// @param this (array<Pivot>) The object to work with. | |
// @param prev (int) Number of previous pivot highs back (1 = latest, >1 is earlier ones). | |
// @return (Pivot) The latest Pivot High or NA if not available. | |
export method getHigh(array<Pivot> this, int prev = 1) => | |
int size = this.size() | |
int n = math.max(1, prev) | |
Pivot lastPivot = this.getLast() | |
Pivot returnPivot = na | |
if not na(lastPivot) | |
if n == 1 and lastPivot.isHigh | |
returnPivot := lastPivot | |
else | |
n := n * (lastPivot.isHigh ? 2 : 1) | |
if size > n | |
returnPivot := this.get(size - 1 - n) | |
returnPivot | |
// @function Gets the latest pivot high | |
// @param this (array<Pivot>) The object to work with. | |
// @return (Pivot) The latest Pivot high in the array or NA if not available. | |
export method getLastHigh(array<Pivot> this) => | |
this.getHigh(1) | |
// @function Gets the previous pivot high | |
// @param this (array<Pivot>) The object to work with. | |
// @return (Pivot) The previous Pivot high in the array or NA if not available. | |
export method getPrevHigh(array<Pivot> this) => | |
this.getHigh(2) | |
// @function Gets the Pivot Low | |
// @param this (array<Pivot>) The object to work with. | |
// @param prev (int) Number of previous pivot lows back (1 = latest, >1 is earlier ones). | |
// @return (Pivot) The latest Pivot Low or NA if not available. | |
export method getLow(array<Pivot> this, int prev = 1) => | |
int size = this.size() | |
int n = math.max(1, prev) | |
Pivot lastPivot = this.getLast() | |
Pivot returnPivot = na | |
if not na(lastPivot) | |
if n == 1 and not lastPivot.isHigh | |
returnPivot := lastPivot | |
else | |
n := n * (lastPivot.isHigh ? 1 : 2) | |
if size > n | |
returnPivot := this.get(size - 1 - n) | |
returnPivot | |
// @function Gets the latest pivot low | |
// @param this (array<Pivot>) The object to work with. | |
// @return (Pivot) The latest Pivot low in the array or NA if not available. | |
export method getLastLow(array<Pivot> this) => | |
this.getLow(1) | |
// @function Gets the previous pivot low | |
// @param this (array<Pivot>) The object to work with. | |
// @return (Pivot) The previous Pivot low in the array or NA if not available. | |
export method getPrevLow(array<Pivot> this) => | |
this.getLow(2) | |
// @function Builds name (and abbreviation) string for current pivot | |
// @param this (Pivot) The object to work with. | |
// @return (string) The name for this pivot. | |
// @return (string) Abbreviation of the name for this pivot. | |
method buildNameString(Pivot this) => | |
string highLowAbbr = this.isHigh ? "H" : "L" | |
string highLow = highLowAbbr + (this.isHigh ? "igh" : "ow") | |
string higherLowerAbbr = "" | |
string higherLower = "" | |
// Only append higher/lower if isHigher has been set (not default false) | |
if this.isHigher != Pivot.new(this.point, this.isHigh).isHigher // Check against default value | |
higherLowerAbbr := this.isHigher ? "H" : "L" | |
higherLower := higherLowerAbbr + (this.isHigher ? "igher " : "ower ") | |
string name = str.format("{0}{1}", higherLower, highLow) | |
string abbr = str.format("{0}{1}", higherLowerAbbr, highLowAbbr) | |
[name, abbr] | |
// @function Builds the string for the CloseBreaksClose feature | |
// @param this (Pivot) The object to work with. | |
// @return (string) The string indicating if close breaks previous close. | |
method buildCloseBreaksCloseString(Pivot this) => | |
string str = this.closeBreaksClose ? (this.isHigh ? "꜀" : "ᶜ") : "" | |
// @function Builds the string for the CloseBreaksPivot feature | |
// @param this (Pivot) The object to work with. | |
// @return (string) The string indicating if close breaks previous pivot. | |
method buildCloseBreaksPivotString(Pivot this) => | |
string str = this.closeBreaksPivot ? (this.isHigh ? "ₚ" : "ᵖ") : "" | |
// @function Generates the text for the label of the Pivot | |
// @param this (Pivot) The object to work with. | |
// @param settings (Settings) The global settings for the indicator. | |
// @return (string) Text: HH for higher high, LH for lower high, HL for higher low, LL for lower low | |
method buildLabelTextString(Pivot this, Settings settings) => | |
string str = "" | |
if settings.theme.showCloseInfo | |
str := settings.features.closeBreaksClose ? this.buildCloseBreaksCloseString() : str | |
str += settings.features.closeBreaksPivot ? this.buildCloseBreaksPivotString() : "" | |
// If isHigher is still default (false) and hasn't been set, show only abbr | |
if this.isHigher == Pivot.new(this.point, this.isHigh).isHigher | |
str := this.abbr | |
else | |
str := this.isHigh ? str + "\n" + this.abbr : this.abbr + "\n" + str | |
// @function Creates a color based on current pivot conditions. | |
// @param this (Pivot) The object to work with. | |
// @param prev (Pivot) The previous pivot | |
// @param theme (Theme) The theme settings | |
// @returns (color) The color for this pivot | |
method generateColor(Pivot this, Pivot prev, Theme theme) => | |
color c = theme.colorDefault | |
if this.isHigherLow() | |
c := not prev.isHigher ? theme.colorNeutral : theme.colorBullish | |
if this.isLowerLow() | |
c := theme.colorBearish | |
if this.isHigherHigh() | |
c := theme.colorBullish | |
if this.isLowerHigh() | |
c := prev.isHigher ? theme.colorNeutral : theme.colorBearish | |
c | |
// @function Checks if current close broke previous pivot value | |
// @param this (Pivot) The object to work with. | |
// @return (bool) Whether the current close broke the previous pivot value | |
method closeBrokePrevPivot(Pivot this) => | |
this.isHigh ? this.closeBreaksPivot : not this.closeBreaksPivot | |
// @function Checks if current close broke previous pivot close | |
// @param this (Pivot) The object to work with. | |
// @return (bool) Whether the current close broke the previous pivot close | |
method closeBrokePrevPivotClose(Pivot this) => | |
this.isHigh ? this.closeBreaksClose : not this.closeBreaksClose | |
// @function Calculates the cumulative volume from previous pivot to current pivot | |
method calculateComulativeVolume(Pivot this) => | |
this.comulativeVolume + volume | |
// @function Builds a tooltip string | |
// @param this (Pivot) The object to work with. | |
// @param settings (Settings) The global settings. | |
// @return (string) The tooltip | |
method buildTooltipString(Pivot this, Settings settings) => | |
array<string> tooltips = array.new<string>() | |
string strName = this.name | |
string strHighOrLow = this.isHigh ? "high" : "low" | |
string strAboveOrBelow = this.isHigh ? "above" : "below" | |
string strHighestOrLowest = this.isHigh ? "highest" : "lowest" | |
if settings.theme.tooltips.name | |
tooltips.push("name\t\t\t: " + strName) | |
if settings.theme.tooltips.price | |
tooltips.push("price\t\t\t: " + str.tostring(this.point.y)) | |
if settings.theme.tooltips.close | |
tooltips.push(strHighestOrLowest + " close\t\t: " + str.tostring(this.close)) | |
if settings.theme.tooltips.closeBreaksPivot | |
tooltips.push(str.format("close {0} pivot\t: {1}", this.isAtCurrentBar() or this.isLast ? "breaks" : "broke", this.closeBrokePrevPivot())) | |
if settings.theme.tooltips.closeBreaksClose | |
tooltips.push(str.format("close {0} close\t: {1}", this.isAtCurrentBar() or this.isLast ? "breaks" : "broke", this.closeBrokePrevPivotClose())) | |
// Return the joined string | |
string str = array.join(tooltips, "\n") | |
// @function Adds a new pivot to the pivots array. | |
// @param this (array<Pivot>) The object to work with. | |
// @param point (Point) The point coordinates of the new pivot. | |
// @param isHigh (bool) Whether the pivot is a high or not (then it is a low). | |
// @param settings (Settings) The global settings. | |
// @return (Pivot) The latest Pivot. | |
export method add(array<Pivot> this, Point point, bool isHigh, Settings settings) => | |
Theme theme = settings.theme | |
Pivot lastPivot = this.getLast() | |
Pivot prevPivot = this.getPrev() | |
Pivot pivot = Pivot.new(point, isHigh) | |
pivot.close := (isHigh ? math.max(close, close[1]) : math.min(close, close[1])) | |
pivot.close := (isHigh and close > pivot.close) or (not isHigh and close < pivot.close) ? close : pivot.close | |
if not na(lastPivot) | |
color pivotColor = pivot.generateColor(lastPivot, theme) | |
// If we have a previous Pivot... | |
if not na(prevPivot) | |
pivot.closeBreaksPivot := pivot.isHigh ? close > prevPivot.point.y : close < prevPivot.point.y | |
pivot.closeBreaksClose := pivot.isHigh ? close > prevPivot.close : close < prevPivot.close | |
pivot.isHigher := point.y > prevPivot.point.y | |
[name, abbr] = pivot.buildNameString() | |
pivot.name := name | |
pivot.abbr := abbr | |
pivotColor := pivot.generateColor(lastPivot, theme) | |
// Create the line for the new Pivot | |
if theme.enabled | |
pivot.ln := line.new( | |
x1 = lastPivot.point.x, | |
y1 = lastPivot.point.y, | |
x2 = pivot.point.x, | |
y2 = pivot.point.y, | |
xloc = xloc.bar_time, | |
extend = extend.none, | |
color = theme.coloredLines ? pivotColor : theme.colorDefault, | |
style = line.style_solid, | |
width = theme.lineWidth) | |
// Create label for the new Pivot | |
if theme.enabled | |
pivot.lb := label.new( | |
x = pivot.point.x, | |
y = pivot.point.y, | |
text = pivot.buildLabelTextString(settings), | |
xloc = xloc.bar_time, | |
yloc = isHigh ? yloc.abovebar : yloc.belowbar, | |
color = color.rgb(0, 0, 0, 100), | |
style = label.style_none, | |
textcolor = (pivot.abbr == "L" and theme.showLabelL) or (pivot.abbr == "LL" and theme.showLabelLL) or (pivot.abbr == "HL" and theme.showLabelHL) or (pivot.abbr == "H" and theme.showLabelH) or (pivot.abbr == "LH" and theme.showLabelLH) or (pivot.abbr == "HH" and theme.showLabelHH) ? pivotColor : #00000000, | |
size = theme.labelSize, | |
textalign = text.align_center, | |
text_font_family = font.family_default, | |
tooltip = theme.showTooltips ? pivot.buildTooltipString(settings) : "") | |
// Last pivot is no longer the last pivot | |
lastPivot.isLast := false | |
this.set(this.size() - 1, lastPivot) | |
// Remove old pivot when max number of pivots is reached | |
if this.size() >= settings.limit | |
Pivot oldestPivot = this.shift() | |
oldestPivot.ln.delete() | |
oldestPivot.lb.delete() | |
oldestPivot := this.first() | |
oldestPivot.ln.delete() | |
// Push the new pivot to the end of the array | |
this.push(pivot) | |
// Return the new Pivot | |
pivot | |
// @function Updates pivot in array | |
// @param this (array<Pivot>) The object to work with. | |
// @param pivot (Pivot) The pivot to update. | |
// @param point (Point) The new point coordinates. | |
// @param settings (Settings) The global settings. | |
// @return (Pivot) The updated Pivot | |
method update(array<Pivot> this, Pivot pivot, Point point, Settings settings) => | |
Theme theme = settings.theme | |
Pivot prevPivot = na | |
pivot.point.x := point.x | |
pivot.point.y := point.y | |
pivot.ln.set_xy2(point.x, point.y) | |
pivot.lb.set_xy(point.x, point.y) | |
pivot.close := (pivot.isHigh ? math.max(close, close[1]) : math.min(close, close[1])) | |
if not na(this) | |
prevPivot := this.getPrev(2) | |
pivot.close := (pivot.isHigh and close > pivot.close) or (not pivot.isHigh and close < pivot.close) ? close : pivot.close | |
if not na(prevPivot) | |
Pivot lastPivot = this.getLast() | |
pivot.isHigher := point.y > prevPivot.point.y | |
// Check if close is higher/lower than previous pivot and pivot's bar close value. | |
pivot.closeBreaksPivot := pivot.isHigh ? close > prevPivot.point.y : close < prevPivot.point.y | |
pivot.closeBreaksClose := pivot.isHigh ? close > prevPivot.close : close < prevPivot.close | |
// Rebuild name string | |
[name, abbr] = pivot.buildNameString() | |
pivot.name := name | |
pivot.abbr := abbr | |
if theme.enabled | |
color pivotColor = pivot.generateColor(lastPivot, theme) | |
color lineColor = pivotColor | |
pivotColor := (pivot.abbr == "L" and theme.showLabelL) or (pivot.abbr == "LL" and theme.showLabelLL) or (pivot.abbr == "HL" and theme.showLabelHL) or (pivot.abbr == "H" and theme.showLabelH) or (pivot.abbr == "LH" and theme.showLabelLH) or (pivot.abbr == "HH" and theme.showLabelHH) ? pivotColor : #00000000 | |
pivot.lb.set_text(pivot.buildLabelTextString(settings)) | |
pivot.lb.set_textcolor(pivotColor) | |
if theme.showTooltips | |
pivot.lb.set_tooltip(pivot.buildTooltipString(settings)) | |
pivot.ln.set_color(theme.coloredLines ? lineColor : theme.colorDefault) | |
this.set(this.size() - 1, pivot) | |
pivot | |
// @function Scans for new pivot | |
// @param this (array<Pivot>) The object to work with. | |
// @param source (float) The source value to scan. | |
// @param isHigh (bool) Whether we look for a pivot high or not. | |
// @param settings (Settings) The settings. | |
method scan(array<Pivot> this, float source, bool isHigh, Settings settings) => | |
Point point = Point.new(time, source) | |
Pivot lastPivot = this.getLast() | |
if not na(lastPivot) | |
if lastPivot.isHigh | |
if point.y > lastPivot.point.y | |
this.update(lastPivot, point, settings) | |
if not isHigh | |
this.add(point, isHigh, settings) | |
else | |
if point.y < lastPivot.point.y | |
this.update(lastPivot, point, settings) | |
if isHigh | |
this.add(point, isHigh, settings) | |
else | |
this.add(point, isHigh, settings) | |
// @function Creates a new ZigZag Instance | |
// @param customSettings (Settings) The settings for this instance. | |
// @return (array<Pivot>) The array of pivots. | |
export new(Settings customSettings) => | |
Settings settings = customSettings | |
// Ensure all settings components are initialized | |
if na(settings.source) | |
settings.source := Source.new() | |
if na(settings.theme) | |
settings.theme := Theme.new() | |
if na(settings.features) | |
settings.features := Features.new() | |
// Change settings based on enabled/disabled features | |
if settings.features.closeBreaksClose == false | |
settings.theme.tooltips.closeBreaksClose := false | |
if settings.features.closeBreaksPivot == false | |
settings.theme.tooltips.closeBreaksPivot := false | |
// Create pivots | |
var Pivot[] pivots = array.new<Pivot>() | |
float srcLow = settings.source.low | |
float srcHigh = settings.source.high | |
if srcHigh != srcLow and srcLow < srcLow[1] and srcHigh > srcHigh[1] | |
if settings.source.priority == "high" // IF HIGH CAME FIRST | |
pivots.scan(srcHigh, true, settings) // HIGH | |
pivots.scan(srcLow, false, settings) // LOW | |
else | |
pivots.scan(srcLow, false, settings) // LOW | |
pivots.scan(srcHigh, true, settings) // HIGH | |
else | |
if srcHigh > srcHigh[1] | |
if srcLow >= srcLow[1] | |
pivots.scan(srcHigh, true, settings) // HIGH | |
if srcLow < srcLow[1] | |
if srcHigh <= srcHigh[1] | |
pivots.scan(srcLow, false, settings) // LOW | |
// Return the pivots array | |
pivots | |
export method barIsPivot(array<Pivot> pivots) => | |
var lastPivot = pivots.getLast() | |
// @function Helper function to generate a lower timeframe period (string) for current timeframe period. | |
// You can use this in conjunction with request.security_lower_tf() to figure out if current high | |
// of this bar was created before the low of this bar. | |
// @return (string) Timeframe period for lower timeframe. | |
export getLowerTimeframePeriod() => | |
int tf = timeframe.in_seconds(timeframe.period) | |
string ltf = switch true | |
tf <= 60 => '10S' | |
tf <= 300 => '1' // 5 minutes => 1 minute | |
tf <= 600 => '2' // 10 minutes => 2 minutes | |
tf <= 1800 => '3' // 30 minutes => 3 minutes | |
tf <= 3600 => '5' // 1 hour => 5 minutes | |
tf <= 14400 => '15' // 4 hour => 15 minutes | |
tf <= 86400 => '30' // 1 day => 30 minutes | |
tf <= 172800 => '60' // 2 days => 1 hour | |
tf <= 259200 => '240' // 3 days => 4 hours | |
tf <= 432000 => '360' // 5 days => 6 hours | |
tf <= 604800 => '720' // 1 week => 12 hours | |
tf <= 1209600 => 'D' // 2 weeks => 1 day | |
tf <= 2628000 => '2D' // 1 month => 2 days | |
tf <= 5256000 => '5D' // 2 months => 5 days | |
tf <= 7884000 => 'W' // 3 months => 1 week | |
tf <= 15768000 => '2W' // 6 months => 2 weeks | |
tf <= 31536000 => '1M' // 1 year => 1 month | |
=> timeframe.period | |
// --------------------------------------------------------------------------------------------------------------------- | |
// USAGE EXAMPLE AREA | |
// --------------------------------------------------------------------------------------------------------------------- | |
// Input: General options | |
int iPivotLimit = input.int( | |
title = "Limit", | |
defval = 1000, | |
minval = 1, | |
step = 1, | |
tooltip = "The maximum amount of pivots to be shown.", | |
group = "S O U R C E") | |
string iSource = input.string( | |
title = "Source", | |
defval = "high/low", | |
options = ["high/low", "custom"], | |
group = "S O U R C E") | |
float iSourceHigh = input.source( | |
title = "Custom High", | |
defval = close, | |
group = "S O U R C E") | |
float iSourceLow = input.source( | |
title = "Custom Low", | |
defval = close, | |
group = "S O U R C E") | |
string iSourcePriority = input.string( | |
title = "Prioritize", | |
defval = "auto", | |
options = ["auto", "high", "low"], | |
tooltip = "In the case if we have both a higher high and a lower low, which is prioritized? If set to automatic, the indicator will look at lower timeframe.", | |
group = "S O U R C E") | |
// Input: Features | |
bool iFeatureCloseBreaksClose = input.bool( | |
title = "Close Breaks Close", | |
defval = true, | |
tooltip = "Check if current pivot (highest/lowest) close broke previous paired pivot (highest/lowest) close.", | |
group = "F E A T U R E S") | |
bool iFeatureCloseBreaksPivot = input.bool( | |
title = "Close Breaks Pivot", | |
defval = true, | |
tooltip = "Check if current pivot (highest/lowest) close broke previous paired pivot (high/low).", | |
group = "F E A T U R E S") | |
// Input: Set theming options | |
bool iThemeHide = input.bool( | |
title = "Hide", | |
defval = false, | |
tooltip = "You can hide or show everything at once with this setting.", | |
group = "T H E M I N G") | |
bool iThemeShowCloseInfo = input.bool( | |
title = "Show close info", | |
defval = true, | |
tooltip = "Show extra close info above and below pivot labels?\nC = Close is higher than previous paired pivot close. \nCP = Close is higher than previous paired pivot.", | |
group = "T H E M I N G") | |
color iThemeColorDefault = input.color( | |
title = "Default", | |
defval = color.rgb(120, 123, 134, 0), | |
group = "T H E M I N G") | |
color iThemeColorNeutral = input.color( | |
title = "Neutral", | |
defval = color.rgb(200, 200, 000, 0), | |
group = "T H E M I N G") | |
color iThemeColorBullish = input.color( | |
title = "Bullish", | |
defval = color.rgb(000, 200, 000, 0), | |
group = "T H E M I N G") | |
color iThemeColorBearish = input.color( | |
title = "Bearish", | |
defval = color.rgb(200, 000, 000, 0), | |
group = "T H E M I N G") | |
string iThemeStyle = input.string( | |
title = "Style", | |
defval = "labels & lines", | |
options = ["labels & lines", "labels", "none"], | |
tooltip = "If \"none\" is selected, the default color will be used for all drawings.", | |
group = "T H E M I N G") | |
int iThemeLineWidth = input.int( | |
title = "Line width", | |
defval = 2, | |
minval = 1, | |
maxval = 50, | |
tooltip = "Width in pixels", | |
group = "T H E M I N G") | |
string iThemeLabelSize = input.string( | |
title = "Label size", | |
defval = "normal", | |
options = ["huge", "large", "normal", "small", "tiny"], | |
group = "T H E M I N G") | |
bool iThemeShowLabelL = input.bool( | |
title = "Show label L", | |
defval = true, | |
group = "T H E M I N G") | |
bool iThemeShowLabelLL = input.bool( | |
title = "Show label LL", | |
defval = true, | |
group = "T H E M I N G") | |
bool iThemeShowLabelHL = input.bool( | |
title = "Show label HL", | |
defval = true, | |
group = "T H E M I N G") | |
bool iThemeShowLabelH = input.bool( | |
title = "Show label H", | |
defval = true, | |
group = "T H E M I N G") | |
bool iThemeShowLabelLH = input.bool( | |
title = "Show label LH", | |
defval = true, | |
group = "T H E M I N G") | |
bool iThemeShowLabelHH = input.bool( | |
title = "Show label HH", | |
defval = true, | |
group = "T H E M I N G") | |
// Input: Set Tooltip Options | |
bool iTooltipDisable = input.bool( | |
title = "Disable", | |
defval = false, | |
tooltip = "This setting overrides all below tooltip settings.", | |
group = "T O O L T I P S") | |
bool iTooltipName = input.bool( | |
title = "Show name", | |
defval = true, | |
group = "T O O L T I P S") | |
bool iTooltipPrice = input.bool( | |
title = "Show price", | |
defval = true, | |
group = "T O O L T I P S") | |
bool iTooltipClose = input.bool( | |
title = "Show close", | |
defval = true, | |
group = "T O O L T I P S") | |
bool iTooltipCloseBreaksClose = input.bool( | |
title = "Show close breaks close", | |
defval = true, | |
group = "T O O L T I P S") | |
bool iTooltipCloseBreaksPivot = input.bool( | |
title = "Show close breaks pivot", | |
defval = true, | |
group = "T O O L T I P S") | |
// Setup the highFirst value for the ZigZag indicator | |
ltf = getLowerTimeframePeriod() | |
[ltf_high, ltf_low] = request.security_lower_tf(syminfo.tickerid, ltf, [iSourceHigh, iSourceLow]) | |
string sourcePriorityAuto = (ltf == timeframe.period ? false : ltf_high.lastindexof(ltf_high.max()) <= ltf_low.lastindexof(ltf_low.min())) ? "high" : "low" | |
// Setup the source for the ZigZag indicator | |
Source sourceSettings = Source.new( | |
high = iSource == "high/low" ? high : iSourceHigh, | |
low = iSource == "high/low" ? low : iSourceLow, | |
priority = iSourcePriority == "auto" ? sourcePriorityAuto : iSourcePriority) | |
// Setup to be used features for the ZigZag indicator | |
Features featuresSettings = Features.new( | |
closeBreaksClose = iFeatureCloseBreaksClose, | |
closeBreaksPivot = iFeatureCloseBreaksPivot) | |
// Setup the theme for the ZigZag indicator | |
Theme themeSettings = Theme.new( | |
enabled = not iThemeHide, | |
colorDefault = iThemeColorDefault, | |
colorNeutral = iThemeStyle == "none" ? iThemeColorDefault : iThemeColorNeutral, | |
colorBullish = iThemeStyle == "none" ? iThemeColorDefault : iThemeColorBullish, | |
colorBearish = iThemeStyle == "none" ? iThemeColorDefault : iThemeColorBearish, | |
coloredLines = iThemeStyle == "labels & lines" ? true : false, | |
lineWidth = iThemeLineWidth, | |
labelSize = iThemeLabelSize, | |
showLabelL = iThemeShowLabelL, | |
showLabelHL = iThemeShowLabelHL, | |
showLabelLL = iThemeShowLabelLL, | |
showLabelH = iThemeShowLabelH, | |
showLabelLH = iThemeShowLabelLH, | |
showLabelHH = iThemeShowLabelHH, | |
showCloseInfo = iThemeShowCloseInfo, | |
showTooltips = not iTooltipDisable, | |
tooltips = Tooltips.new(iTooltipName, iTooltipPrice, iTooltipClose, iTooltipCloseBreaksClose, iTooltipCloseBreaksPivot)) | |
// All settings for the ZigZag indicator | |
settings = Settings.new(sourceSettings, featuresSettings, themeSettings, iPivotLimit) | |
// Create the ZigZag indicator | |
array<Pivot> pivots = new(settings) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment