Wick-off Check Pattern [Misu]
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// Author : @Fontiramisu
// @version=5
indicator("Wickoff Check Pattern [Misu]", shorttitle="Wickoff Check Pattern [Misu]", overlay=true)

// import Fontiramisu/fontLib/80 as fontilab
import Fontiramisu/fontilab/8 as fontilab


//   -------- Find dev pivots ---------- [
// -- Var user input --
var devTooltip              = "Deviation is a multiplier that affects how much the price should deviate from the previous pivot in order for the bar to become a new pivot."
var depthTooltip            = "The minimum number of bars that will be taken into account when analyzing pivots."
thresholdMultiplier         = input.float(title="Deviation", defval=2.5, step=0.1, minval=0, tooltip=devTooltip, group="Pivot")
depth                       = input.int(title="Depth", defval=10, minval=1, tooltip=depthTooltip, group="Pivot") 

// Prepare pivot variables
var line lineLast       = na
var int iLast           = 0 // Index last
var int iPrev           = 0 // Index previous
var float pLast         = 0 // Price last
var float pLastHigh     = 0 // Price last
var float pLastLow      = 0 // Price last
var isHighLast          = false // If false then the last pivot was a pivot low
isPivotUpdate           = false


// Get pivot information from dev pivot finding function
[dupLineLast, dupIsHighLast, dupIPrev, dupILast, dupPLast, dupPLastHigh, dupPLastLow] = 
     fontilab.getDeviationPivots(thresholdMultiplier, depth, lineLast, isHighLast, iLast, pLast, true, close, high, low)

if not na(dupIsHighLast)
    lineLast        := dupLineLast
    isHighLast      := dupIsHighLast
    iPrev           := dupIPrev
    iLast           := dupILast
    pLast           := dupPLast
    pLastHigh       := dupPLastHigh
    pLastLow        := dupPLastLow
    isPivotUpdate   := true

// Plot.
// Get last Pivots.
var highP   = 0.0
var lowP    = 0.0
var midP    = 0.0
highP       := isHighLast ? pLast : highP
lowP        := not isHighLast ? pLast : lowP
midP        := (highP + lowP)/2


// ] -------- Input Vars --------------- [.
wickoffMode                 = input.string("both", title="Wickoff Mode", options=["counter pattern", "breakout pattern", "both"], group="Wickoff Mode")
lenghtSizeAvgBody           = input.int(9, title="Lenght Avg Body", group="Breakouts Settings")
firstBreakoutFactor         = input.float(0.2, step=0.1, title="First Breakout Factor", tooltip="Factor used to validate the first breakout of the V pattern", group="Breakouts Settings")
lenghtWickValidation        = input.int(10, title="Lenght Avg Wick Validation", group="Wickoff Settings")
factorWickValidation        = input.float(1.5, step=0.1, title="Factor Avg Wick Validation", group="Wickoff Settings")
maxNbBarsValidWickoff       = input.int(9, title="Max Bars Wickoff", group="Wickoff Settings")


// ] -------- Logical Vars ------------- [
// Confirm V pattern vars.
var biLastBreakHigh     = 0
var biLastBreakLow      = 0
var lastBreakHigh       = 0.0
var lastBreakLow        = 0.0
var hBreakInProgress    = false
var lBreakInProgress    = false
var indexPotWickoffH    = 0
var indexPotWickoffL    = 0
isWickoffHBull          = false
isWickoffHBear          = false
isWickoffLBull          = false
isWickoffLBear          = false


// ] -------- Util Functions ----------- [
// Cond Vars.
_bodyHi                 = math.max(close, open)
_bodyLo                 = math.min(close, open)
_body                   = _bodyHi - _bodyLo
_bodyAvg                = ta.ema(_body, lenghtSizeAvgBody)
_longBody               = _body > _bodyAvg
_upperWick              = high - _bodyHi
_greenBody              = open < close
_redBody                = open > close
_highWick               = high - _bodyHi
_lowWick                = _bodyLo - low
_avgHighWick            = ta.sma(_highWick, lenghtWickValidation)
_avgLowWick             = ta.sma(_lowWick, lenghtWickValidation)
// COND: Potential Breakout pattern.
_breakUnderLowP         = ta.crossunder(close, lowP) and _body > _bodyAvg * firstBreakoutFactor
_breakAboveHighP        = ta.crossover(close, highP) and _body > _bodyAvg * firstBreakoutFactor 

// @function detect wickoff.
isWickCrossPattern (src, isCrossUp, factor) =>
    isCross = false
    if isCrossUp
        isCross := _bodyHi < src and src < high and _highWick > _avgHighWick * factor
    else
        isCross := low < src and src < _bodyLo and _lowWick > _avgLowWick * factor
    isCross


// ] -------- Logical Script ----------- [
// Vars used to know current breaking levels.
lastBreakHigh       := _breakAboveHighP ? highP : lastBreakHigh
lastBreakLow        := _breakUnderLowP ? lowP : lastBreakLow
biLastBreakHigh     := _breakAboveHighP ? bar_index : biLastBreakHigh
biLastBreakLow      := _breakUnderLowP ? bar_index : biLastBreakLow

// Invalidate wickoff if max nb bars.
isMaxBarHigh        = bar_index - biLastBreakHigh > maxNbBarsValidWickoff
isMaxBarLow         = bar_index - biLastBreakLow > maxNbBarsValidWickoff

// Define break available.
hBreakInProgress    := _breakAboveHighP or not isMaxBarHigh
lBreakInProgress    := _breakUnderLowP or not isMaxBarLow

// Invalidate wickoff other conditions
isWickoffHBull      := hBreakInProgress and  isWickCrossPattern(lastBreakHigh, false, factorWickValidation)
isWickoffHBear      := hBreakInProgress and isWickCrossPattern(lastBreakHigh, true, factorWickValidation)
isWickoffLBull      := lBreakInProgress and isWickCrossPattern(lastBreakLow, false, factorWickValidation)
isWickoffLBear      := lBreakInProgress and isWickCrossPattern(lastBreakLow, true, factorWickValidation)


// ] -------- Plot Part & Alerts ------- [
midPPlot   = plot(midP, title='Mid Pivot', linewidth=1, color=color.yellow, display=display.none)
highPlot   = plot(highP, title='High Pivot', linewidth=1, color=color.red, display=display.none)
lowPlot    = plot(lowP, title='Low Pivot', linewidth=1, color=color.green, display=display.none)

if _breakUnderLowP 
    line.new(bar_index - 5, lowP, bar_index + maxNbBarsValidWickoff, lowP, xloc=xloc.bar_index, color=color.white, width=2)
if _breakAboveHighP
    line.new(bar_index - 5, highP, bar_index + maxNbBarsValidWickoff, highP, xloc=xloc.bar_index, color=color.white, width=2)

if isWickoffHBull and wickoffMode != "counter pattern"
    label.new(x = bar_index, y = low - (ta.atr(30) * 0.3), xloc = xloc.bar_index, text = "W", style = label.style_label_up, color = color.green, size = size.small, textcolor = color.white, textalign = text.align_center)
else if isWickoffLBull and wickoffMode != "breakout pattern"
    label.new(x = bar_index, y = low - (ta.atr(30) * 0.3), xloc = xloc.bar_index, text = "W", style = label.style_label_up, color = color.green, size = size.small, textcolor = color.white, textalign = text.align_center)
else if isWickoffHBear and wickoffMode != "breakout pattern"
    label.new(x = bar_index, y = high + (ta.atr(30) * 0.3), xloc = xloc.bar_index, text = "W", style = label.style_label_down, color = color.red, size = size.small, textcolor = color.white, textalign = text.align_center)
else if isWickoffLBear and wickoffMode != "counter pattern"
    label.new(x = bar_index, y = high + (ta.atr(30) * 0.3), xloc = xloc.bar_index, text = "W", style = label.style_label_down, color = color.red, size = size.small, textcolor = color.white, textalign = text.align_center)

// ]