Absolute ZigZag Lib
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © niquedegraaff

// @version=5
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          (bool)  Which source has higher priorty ("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).
// @param comulativeVolume  (bool)  Calculate the comulative volume for each pivot.
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 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 Used to create a (color) theme to draw Zigzag
// @param enabled           (bool)  Use this ZigZag indicator library build-in lines and labels? (Set to false if you want to build your own)
// @param colorDefault      (color) The default color.
// @param colorNeutral      (color) The neutral color.
// @param colorBullish      (color) The bullish color.
// @param colorBearish      (color) The bearish color.
// @param coloredLines      (bool)  Wether the lines should be colored according to bullish/bearish/neutral colors too.
export type Theme 
    bool     enabled       = false
    color    colorDefault  = color.gray
    color    colorNeutral  = color.yellow 
    color    colorBullish  = color.green 
    color    colorBearish  = color.red 
    string   labelSize     = size.normal
    int      lineWidth     = 2
    bool     coloredLines  = false 
    bool     showCloseInfo = false
    bool     showTooltips  = true 
    Tooltips tooltips      = na


// @type All settings for the indicator
// @param source            (Source)    The source to be used.
// @param features          (Features)  The features to be used.
// @oparam highFirst        (bool)      In case we have a higher high and a higher low, which comes first?
// @param theme             (Theme)     The theme to be used.
// @param tooltips          (Tooltips)  The tooltips to 
export type Settings 
    Source   source    = na
    Features features  = na
    Theme    theme     = 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 coordiation on the chart
// @param isHigh            (bool)      Wether this Pivot is a pivot high or low.
// @param isHigher          (bool)      Wether this Pivot is higher than the previous paired pivot. (not last pivot, but 2 back).
// @param isCurrentBar      (bool)      Wether the pivot is at the current bar
// @param name              (string)    The name of the pivot.
// @param abbr              (string)    The abbr of the name of the pivot.
// @param close             (float)     The highest/lowest close price of the swing to this pivot.
// @param closeBreaksClose  (bool)      Wether the pivot (highest/lowest) close breaks the previous pivot (highest/lowest) close.
// @param closeBreaksPivot  (bool)      Wether the pivot (highest/lowest) close breaks the previous pivot (high/low).
// @param ln                (line)      Line to draw (optional)
// @param lb                (label)     Label to draw (optional)
export type Pivot 
    Point  point                            
    bool   isHigh                         
    bool   isHigher = na     
    string name = na
    string abbr = na
    float  close = close
    float  comulativeVolume = na
    bool   closeBreaksPivot = na
    bool   closeBreaksClose = na
    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 previous one.
// @param this      (Pivot)         The object to work with.
// @param pivots    (array<Pivot>)  The array of pivots.
// @return          (bool)          Weither the pivot is higher or not. Returns (na) if array was too small.
method isHigher(Pivot this, Pivot[] pivots) => 
    int size = pivots.size()
    if size > 2
	    this.point.y > pivots.get(size - 3).point.y 
    else 
        na


// @function Checks if the current pivot is at the current bar
// @param this      (Pivot)         The object to work with.
// @return          (bool)          Wether 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 prev number Pivot high back. Default the latest
// @param this      (array<Pivot>)  The object to work with.
// @param prev      (int)           Number of prev pivot highs back. (1 = latest, 1 < is previous 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
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 n         (int)           Number of pivot lows back. (1 = latest, 1 < is previous 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 = "" 
    if not na(this.isHigher) 
        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.
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.
method buildCloseBreaksPivotString(Pivot this) =>
    string str = this.closeBreaksClose ? (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 = ""
    string highInfo = ""
    string lowInfo = ""
    if settings.theme.showCloseInfo 
        str := settings.features.closeBreaksClose ? this.closeBreaksClose ? this.buildCloseBreaksCloseString() : "" : str 
        str += settings.features.closeBreaksPivot ? this.closeBreaksPivot ? this.buildCloseBreaksPivotString() : "" : ""
    if na(this.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 last      (Pivot)         The previous pivot
// @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)  Wether 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)  Wether the current close broke the previous pivot close
method closeBrokePrevPivotClose(Pivot this) =>
    this.isHigh ? this.closeBreaksClose : not this.closeBreaksClose


// @function Calculates the comulative 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"

    // tooltips.push("X:\t" + str.tostring(this.point.x))
    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.isHigh ? this.closeBreaksPivot : not this.closeBreaksPivot))
    if settings.theme.tooltips.closeBreaksClose
        tooltips.push(str.format("close {0} close\t: {1}", this.isAtCurrentBar() or this.isLast ? "breaks" : "broke", this.isHigh ? this.closeBreaksClose : not this.closeBreaksClose))

    // 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)          Wether the pivot is a high or not (then it is a low).
// @param settings  (Settings)      The global settings.
// @return          (Pivot)         The latest Pivot.
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   = pivotColor,
              size        = theme.labelSize,
              textalign   = text.align_center,
              text_font_family = font.family_default,
              tooltip     = theme.showTooltips ? pivot.buildTooltipString(settings) : na)

        // Last pivot is no longer the last pivot
        lastPivot.isLast := false
        this.set(this.size() - 1, lastPivot)

    // Remove old pivot when max amount of pivot is reached
    if this.size() > 1000 
        this.shift()

    // Push the new pivot to the end of the array
    this.push(pivot)

    // Return the new Pivot
    pivot


// @function        Update pivot in array
// @param this      (array<Pivot>)  The object to work with.
// @return          (Pivot)         The latest Pivot Low
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 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)
                pivot.lb.set_text(pivot.buildLabelTextString(settings))
                pivot.lb.set_textcolor(pivotColor) 
                if theme.showTooltips
                    pivot.lb.set_tooltip(lastPivot.buildTooltipString(settings))
                pivot.ln.set_color(theme.coloredLines ? pivotColor : theme.colorDefault)
           
            // DEBUG
            // if not pivot.isHigh
            //     line debug = line.new(prevPivot.point.x, prevPivot.point.y, point.x, point.y, xloc.bar_time, extend.none, pivot.isHigh ? color.new(color.lime, 70) : color.new(color.yellow, 70), line.style_solid, 1)
        this.set(this.size() - 1, pivot)
    pivot
  

// @function Scans for new pivot
// @param this      (array<Pivot>) The object to work with.
// @param isHigh    (bool) Wether 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.
// @param return            (array<Pivot>)  The array of pivots.
export new(Settings customSettings = na) =>
    Settings settings = customSettings

    // If no settings were given, create default settings
    if na(settings) 
        settings := Settings.new()
    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 not na(settings.theme.tooltips) 
        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, 1, settings)  // HIGH
            pivots.scan(srcLow,  0, settings)  // LOW
        else  
            pivots.scan(srcLow,  0, settings)  // LOW
            pivots.scan(srcHigh, 1, settings)  // HIGH
    else
        if srcHigh > srcHigh[1]  
            if srcLow >= srcLow[1]
                pivots.scan(srcHigh, 1, settings) // HIGH
        if srcLow < srcLow[1] 
            if srcHigh <= srcHigh[1]
                pivots.scan(srcLow, 0, 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 on conjuction with request.security_lower_tf() to figure out if current high of 
//           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
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")

string iThemeLabelSize = input.string(
  title   = "Label size",
  defval  = "normal",
  options = ["huge", "large", "normal", "small", "tiny"],
  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")


// 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
//   This is an example to find out how you can find the value that came first, the high or the low?  
//   We can also just set highFirst to 1. But for accuracy, using the below setup is recommended.
//   So, in this example we use the ZigZag build-in helper function to generate a lower timeframe period string!
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,
  labelSize     = iThemeLabelSize,
  lineWidth     = iThemeLineWidth,
  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)


// Create the ZigZag indicator
array<Pivot> pivots = new(settings)

