[Pinescript] Calculate average ZigZag

Discussion in 'Automated Trading' started by williamblake72, Apr 14, 2024.

  1. Hello,

    I have taken a script from the user RozaniGhani-RG about the ZigZag indicator. The ZigZag indicator identifies segments of the swing of the market.

    I have modified the original script inserting an initial date from which the script must make the calculation. Now I would like to calculate the "average zigzag segment", simply measuring the heights of each segment and then making the average of these heights.

    Well, the script "blocks" when it is trying to calculate the avg range. I think it is the first segment which takes a not valid value.
    Can someone help me to find out the solution, please? I lost 2 hours and got nothing (I'm newbie of pinescript :)

    Thank you very much

    Here the script:

    // © RozaniGhani-RG
    //@version=5
    indicator('Zigzag Chart Points', 'ZCP', true, max_bars_back = 600)

    // 0. Inputs
    // 1. Variables and arrays
    // 2. Map
    // 3. Switches
    // 4. Methods
    // 5. Executions

    //#region ———————————————————— 0. Inputs
    G0 = 'Main Settings'
    T0 = 'Zigzag values\nDefault : 14\nMin : 2\nMax : 50'
    length = input.int( 14, 'Length', group = G0, minval = 2, maxval = 50, tooltip = T0)
    colorUp = input.color(color.lime, 'Trend', group = G0, inline = '0')
    colorDn = input.color( color.red, '', group = G0, inline = '0')

    G1 = 'Line Settings'
    T1 = 'Default\nStyle : Solid\nWidth : 4'
    showLine = input.bool( true, 'Show / hide', group = G1)
    lineType = input.string( 'solid', 'Style', group = G1, options = ['dash', 'dot', 'solid', 'arrow right', 'arrow left'])
    extendType = input.string( 'none', 'Extend', group = G1, options = ['left', 'right', 'both', 'none'])
    width = input.int( 4, 'Width', group = G1, minval = 1, maxval = 4, tooltip = T1)

    G2 = 'Label Settings'
    T2 = 'Small font size recommended for mobile app or multiple layout'
    showLabel = input.bool( true, 'Show / hide', group = G2)
    fontSize = input.string( 'normal', 'Size', group = G2, options = ['tiny', 'small', 'normal', 'large', 'huge'], tooltip = T2)

    userDate = input.time(defval = timestamp("01 Apr 2024 00:00 +0000"), title = "User Date")
    //#endregion

    //#region ———————————————————— 1. Variables and arrays
    float ph = na, ph := ta.highestbars(high, length) == 0 ? high : na
    float pl = na, pl := ta.lowestbars( low, length) == 0 ? low : na
    var dir = 0, dir := not na(ph) and na(pl) ? 1 : not na(pl) and na(ph) ? -1 : dir
    var zigzag = array.new<chart.point>(0)
    oldzigzag = zigzag.copy()
    dirchanged = dir[0] != dir[1]
    var arraySize = 10
    //#endregion

    //#region ———————————————————— 2. Map
    // Create map for label's tooltip
    tip = map.new<string, string>()
    tip.put('HH', 'HIGHER HIGH')
    tip.put('LH', 'LOWER HIGH')
    tip.put('LL', 'LOWER LOW')
    tip.put('HL', 'HIGHER LOW')
    //#endregion

    //#region ———————————————————— 3. Switches
    switchLine = switch lineType
    'dash' => line.style_dashed
    'dot' => line.style_dotted
    'solid' => line.style_solid
    'arrow right' => line.style_arrow_right
    'arrow left' => line.style_arrow_left
    switchExtend = switch extendType
    'left' => extend.left
    'right' => extend.right
    'both' => extend.both
    'none' => extend.none
    //#endregion

    //#region ———————————————————— 4. Methods
    // @function addPoint
    // @param price float value
    // @param index int value
    // @param arraySize array size for chart.point[]
    // @returns chart.point[]
    method addPoint(chart.point[] id, float price = na, int index = na, int arraySize = na) =>
    id.unshift(chart.point.new(time, index, price))
    if id.size() > arraySize
    id.pop()

    // @function updatePoints
    // @param price float value
    // @param index int value
    // @param arraySize array size for chart.point[]
    // @param dir int value
    // @returns chart.point[]
    method updatePoints(chart.point[] id, float price = na, int index = na, int arraySize = na, int dir = na) =>
    if id.size() == 0
    id.addPoint(price, index)
    else
    if dir == 1 and price > id.get(0).price or dir == -1 and price < id.get(0).price
    id.set(0, chart.point.new(time, index, price))
    chart.point.new(na, na, na)
    //#endregion

    //#region ———————————————————— 5. Executions
    //if na(ph) or na(pl)
    //if dirchanged
    //zigzag.addPoint(dir == 1 ? ph : pl, bar_index, arraySize)
    //else
    //zigzag.updatePoints(dir == 1 ? ph : pl, bar_index, arraySize, dir)

    if na(ph) or na(pl)
    if time >= userDate // Added by me
    if dirchanged
    zigzag.addPoint(dir == 1 ? ph : pl, bar_index, arraySize)
    else
    zigzag.updatePoints(dir == 1 ? ph : pl, bar_index, arraySize, dir)

    if zigzag.size() >= 3 and oldzigzag.size() >= 3
    var line linezigzag = na
    var label labelzigzag = na
    if zigzag.get(0).index != oldzigzag.get(0).index or zigzag.get(0).price != oldzigzag.get(0).price
    if zigzag.get(1).index == oldzigzag.get(1).index and zigzag.get(1).price == oldzigzag.get(1).price
    linezigzag.delete()
    labelzigzag.delete()
    if showLine
    linezigzag := line.new(
    first_point = zigzag.get(0),
    second_point = zigzag.get(1),
    xloc = xloc.bar_index,
    extend = switchExtend,
    color = dir == 1 ? colorUp : colorDn,
    style = switchLine,
    width = width)
    if showLabel
    textzigzag = dir == 1 ? zigzag.get(0).price > zigzag.get(2).price ? 'HH' : 'LH' :
    zigzag.get(0).price < zigzag.get(2).price ? 'LL' : 'HL'
    colorzigzag = dir == 1 ? zigzag.get(0).price > zigzag.get(2).price ? colorDn : colorUp :
    zigzag.get(0).price < zigzag.get(2).price ? colorUp : colorDn
    currentRes = timeframe.isintraday ? 'dd-MMM-yyyy HH:mm' : 'dd-MMM-yyyy'
    labelzigzag := label.new(
    point = zigzag.get(0),
    text = textzigzag,
    xloc = xloc.bar_index,
    style = dir == 1 ? label.style_label_down : label.style_label_up,
    color = color.new(color.blue, 100),
    textcolor = colorzigzag,
    size = fontSize,
    tooltip = tip.get(textzigzag) + '\n' +
    'Time : ' + str.format_time(zigzag.get(0).time, currentRes, syminfo.timezone)+ '\n' +
    'Price : ' + str.tostring(zigzag.get(0).price))

    //Calculate avg range
    rangeArray = array.new_float(0)
    for i = 1 to zigzag.size() - 1
    if zigzag.get(i).time >= userDate
    segmentRange = math.abs(zigzag.get(i).price - zigzag.get(i - 1).price)
    array.push(rangeArray, segmentRange)

    averageRange = array.avg(rangeArray)

    //plot(averageRange, title="Average Range", color=color.blue, linewidth=1, style=plot.style_line)
    //#endregion
     
  2. maxinger

    maxinger

    [​IMG]

    I copied the zigzag thing from somewhere in Esignal.

    Sorry can't help; I am no programmer.

    Seems like no programmer here.
    Perhaps ask the AI bot.
     
    Last edited: Apr 15, 2024
  3. MarkBrown

    MarkBrown

    ai

    The script you've provided seems to be encountering an issue when trying to calculate the average segment height (range) of the ZigZag indicator from a user-defined start date in Pine Script. The issue might be stemming from a couple of areas related to how segments are calculated and added to the range array. Here are some steps and modifications to help debug and potentially fix the issue:

    1. Initializing the Array Correctly
    Ensure that the array used to store the heights (ranges) of the ZigZag segments is being correctly managed. Since you're using an array to store these values, it's good practice to make sure it's cleared or properly initialized each time there's a need to recalculate these values.

    2. Condition Checks for Valid Segment Calculation
    It appears you're attempting to calculate segment heights and then pushing these heights into an array. You should add more rigorous checks to ensure the segments are valid before performing calculations. This includes ensuring that your ZigZag points are correctly identified and that the time condition for the segments being after the userDate is properly enforced.

    3. Handling na Values
    Since Pine Script uses na to represent undefined or unavailable values, make sure that your calculations explicitly handle these cases to avoid unintentional errors or "blocking."

    Proposed Modifications:
    Here is a modified segment of your script focusing on the segment range calculation and average range computation. This modification includes checks for na values and ensures only valid segments after the userDate are considered:

    pinescript
    // Calculate avg range
    rangeArray = array.new_float(0)
    for i = 1 to array.size(zigzag) - 1
    if not na(zigzag.get(i).time) and not na(zigzag.get(i-1).time)
    if zigzag.get(i).time >= userDate and zigzag.get(i-1).time >= userDate
    segmentRange = math.abs(zigzag.get(i).price - zigzag.get(i-1).price)
    array.push(rangeArray, segmentRange)

    if array.size(rangeArray) > 0
    averageRange = array.avg(rangeArray)
    plot(averageRange, title="Average Range", color=color.blue, linewidth=1, style=plot.style_line)
    else
    plot(na, title="Average Range")

    Additional Suggestions:
    • Debugging Output: Use label.new or line.new to visually debug the points and segments being considered for your calculation.
    • Variable Initialization: Make sure all required variables (like zigzag) are correctly initialized and managed throughout the script.
    • Check for Empty Conditions: Add conditions to handle cases when your range array might end up empty to avoid plotting or calculations on empty data.
    If you continue to experience issues, consider simplifying the script by temporarily removing conditions and gradually adding them back to isolate the problem. Additionally, using a debugging tool or logging intermediate values can greatly help understand the flow and state of your script at runtime.
     
    williamblake72 likes this.
  4. Thank you very much, which kind of ai are u using? I was using chatGPT 3.5 butthe problem is that whe n having error on arrays and index out of boundI am not able to correct the mistake :) I will try with the piece of code you posted, thanks!
     
  5. What is Esegnal? Exactly, i have a similar indicator and i wouldlike the range of each of the segment, and then making an average of these values.
     
  6. MarkBrown

    MarkBrown

    GPT 4 enterprise it's 25. a month