na_skip_highest
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © tartigradia

//@version=5

// @description Finds the highest historic value over len bars but skip na valued bars (eg, off days). In other words, this will ensure we find the highest or lowest value over len bars with a real value, and if there are any na bars in-between, we skip over but the loop will continue. This allows to mimic calculations on markets with off days (eg, weekends).
library("na_skip_highest")

// @function Internal function. Finds the highest or lowest historic value over len bars but skip na valued bars (eg, off days). In other words, this will ensure we find the highest value over len bars with a real value, and if there are any na bars in-between, we skip over but the loop will continue. This allows to mimic calculations on markets with off days (eg, weekends).
// @param src series float source (eg, close)
// @param len int length, number of recent bars to consider in the window to find the highest value
// @param mode int If 0 finds the highest value, if 1 finds the lowest value. Internal parameter.
// @returns highest float highest value found over the len window
export na_skip_highest_or_lowest(series float src, int len, int mode) =>
    // Finds the highest or lowest historic value over len bars but skip na valued bars (eg, off days).
    // In other words, this will ensure we find the highest or lowest value over len bars with a real value, and if there are any na bars in-between, we skip over but the loop will continue.
    // This allows to mimic calculations on markets with off days (eg, weekends).
    highest_or_lowest = src
    i = 1
    j = 1
    while i < len and j < len*2  // for the first few historic bars, there is not many previous bars, so we need to limit the maximum number of bars we walk through, here it's len*2, then we give up
        val = src[j]
        if not na(val)
            i += 1
            if (mode == 0 and highest_or_lowest < val) or (mode == 1 and highest_or_lowest > val)
                highest_or_lowest := val
        j += 1
    highest_or_lowest

// @function Finds the highest historic value over len bars but skip na valued bars (eg, off days). In other words, this will ensure we find the highest value over len bars with a real value, and if there are any na bars in-between, we skip over but the loop will continue. This allows to mimic calculations on markets with off days (eg, weekends).
// @param src series float source (eg, close)
// @param len int length, number of recent bars to consider in the window to find the highest value
// @returns highest float highest value found over the len window
export na_skip_highest(series float src, int len) =>
    // Finds the highest historic value over len bars but skip na valued bars (eg, off days).
    // In other words, this will ensure we find the highest value over len bars with a real value, and if there are any na bars in-between, we skip over but the loop will continue.
    // This allows to mimic calculations on markets with off days (eg, weekends).
    na_skip_highest_or_lowest(src, len, 0)

// @function Finds the lowest historic value over len bars but skip na valued bars (eg, off days). In other words, this will ensure we find the lowest value over len bars with a real value, and if there are any na bars in-between, we skip over but the loop will continue. This allows to mimic calculations on markets with off days (eg, weekends).
// @param src series float source (eg, close)
// @param len int length, number of recent bars to consider in the window to find the highest value
// @returns highest float highest value found over the len window
export na_skip_lowest(series float src, int len) =>
    // Finds the lowest historic value over len bars but skip na valued bars (eg, off days).
    // In other words, this will ensure we find the lowest value over len bars with a real value, and if there are any na bars in-between, we skip over but the loop will continue.
    // This allows to mimic calculations on markets with off days (eg, weekends).
    na_skip_highest_or_lowest(src, len, 1)

plot(na_skip_highest(close, 5))
