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

//@version=5
library("Touched")

export type Zone
    float High
    float Low
    int BaseTime

export type Touch
    bool Up
    bool Down

// @function Tells if the zone has been broken on the current bar.
// @param zone The definitiin of the zone.
// @param lookback How many bars to look back.
// @returns a Touch object that tells if the zone has been broken up or down.
export Breakout(Zone zone, int lookback) =>
    breakout = Touch.new()
    // /
    if low > zone.High
      and low[1] < zone.High
        for i = 1 to lookback
            if zone.BaseTime > time[i]
                break

            if low[i] > zone.High
                break

            if high[i] < zone.Low
                breakout.Up := true
                break
    // \
    if high < zone.Low
      and high[1] > zone.Low
        for i = 1 to lookback
            if zone.BaseTime > time[i]
                break

            if high[i] < zone.Low
                break

            if low[i] > zone.High
                breakout.Down := true
                break

    breakout
// @function Tells if the zone has a false breakout on the current bar.
// @param zone The definitiin of the zone.
// @param lookback How many bars to look back.
// @returns a Touch object that tells if the zone has had a false breakout up or down.
export FalseBreakout(Zone zone, int lookback) =>
    falseBreakout = Touch.new()
    //   /'\    \
    //  /   \    \  /'\
    // /      or  \/   \
    if high < zone.Low
      and high[1] > zone.Low
        higher = false
        for i = 0 to lookback
            if zone.BaseTime > time[i]
                break

            if low[i] > zone.High
                higher := true

            if higher
              and high[i] < zone.Low
                falseBreakout.Up := true
                break
    // \          /\   /
    //  \   /    /  \./
    //   \./ or /
    if low > zone.High
      and low[1] < zone.High
        lower = false
        for i = 0 to lookback
            if zone.BaseTime > time[i]
                break

            if high[i] < zone.Low
                lower := true

            if lower
              and low[i] > zone.High
                falseBreakout.Down := true
                break

    falseBreakout
// @function Tells if the zone has been retested on the current bar.
// @param zone The definitiin of the zone.
// @param lookback How many bars to look back.
// @returns a Touch object that tells if the zone has been retested up or down.
export Retest(Zone zone, int lookback) =>
    retest = Touch.new()
    // \/
    if low > zone.High
      and low[1] < zone.High
        for i = 1 to lookback
            if zone.BaseTime > time[i]
                break

            if low[i] > zone.High
                retest.Up := true
                break
    // /\
    if high < zone.Low
      and high[1] > zone.Low
        for i = 1 to lookback
            if zone.BaseTime > time[i]
                break

            if high[i] < zone.Low
                retest.Down := true
                break

    retest