Overlay - HARSI + Divergences 
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © LordKaan
// All credit to © geneclash & VuManChu & Arty & TheThirdFloor for their original Scripts
// TTF Based on the TMA Overlay by Arty 
// Many thanks to the original script where I've extracted some code lines : Arty and TheThirdFloor 
//https://www.tradingview.com/v/admGhVz7/
//https://www.tradingview.com/v/zX3fvduH/
//
// This is a trimmed down version of the OG TMA Overlay with a focus on highlighting a couple specific candlestick patterns.
// This script is organized in a way that allows each pattern to be commented-out (disabled) or uncommented (enabled) pretty easily.
//
// The original request was for 3-Line-Strike only, so that is what will be enabled/uncommented by default,
// but the engulfing code will be left in as well so that it can be turned on easily if desired.
//
// TODO: Add in a trend filter based on the trend identification method Arty discusses in his video on this candle pattern. 
//
// NOTE: As-written, the symbols and 'alert()' functions are subject to repainting (firing without a confirmed signal at bar close).
//       This was done deliberately as a way to give people early-warning on live charts to help give them time to prepare for an entry,
//       which can be especially significant when scalping on low timeframe (1-5m) charts.



// This is open-source and open code, not to be private

//@version=5
indicator('Overlay - HARSI + Divergences + TTF ', 'Overlay - HARSI + Divergences + TTF',  format=format.price, precision=0, overlay=true)



////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// ====== ABOUT THIS INDICATOR                                                //
//                                                                            //
//  - RSI based Heikin Ashi candle oscillator                                 //  
//  - Divergence based on the VuManChu Cipher B                               //
//                                                                            //
// ====== ARTICLES and FURTHER READING                                        //
//                                                                            //
//  - https://www.investopedia.com/terms/h/heikinashi.asp                     //
//                                                                            //
//    "Heikin-Ashi is a candlestick pattern technique that aims to reduce     //
//    some of the market noise, creating a chart that highlights trend        //
//    direction better than typical candlestick charts"                       //
//                                                                            //
// ====== IDEA AND USE                                                        //  
//     - The use of the HA RSI indicator when in the OverSold and OverBought  //  
//       area combined to a Divergence & a OB/OS buy/sell                     //  
//       on the Cipher B by VuManChu.                                         //  
//       Can be usefull as a confluence at S/R levels.                        //  
//  Tip = 1 minute timeframe seems to work the best on FOREX                  //  
//                                                                            //  
//   Contributions :                                                          //  
//  -->  Total conditions for an alert and a dot to display, resumed :        //  
//   - Buy/Sell in OB/OS                                                      //  
//   - Divergence Buy/Sell                                                    //  
//   - RSI Overlay is in OB/OS on current bar (or was the bar before)         //  
//     when both Buy/Sell dots from VMC appears.                              //  
//                                                                            //  
// ====== DISCLAIMER                                                          //
//    For Tradingview & Pinescript moderators =                               //  
//    This follow a strategy where RSI Overlay from @JayRogers script shall be //
//    in OB/OS zone, while combining it with the VuManChu Cipher B Divergences //
//    Buy&Sell + Buy/sell alerts In OB/OS areas.                              //                                          
//    Any trade decisions you make are entirely your own responsibility.      //
//                                                                             //
//  Thanks to dynausmaux for the code
//  Thanks to falconCoin for https://www.tradingview.com/script/KVfgBvDd-Market-Cipher-B-Free-version-with-Buy-and-sell/ inspired me to start this.
//  Thanks to LazyBear for WaveTrend Oscillator https://www.tradingview.com/script/2KE8wTuF-Indicator-WaveTrend-Oscillator-WT/
//  Thanks to RicardoSantos for https://www.tradingview.com/script/3oeDh0Yq-RS-Price-Divergence-Detector-V2/                                                                     //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
//                           ====== TOOLTIPS ======                           //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

string TT_HARSI = 'Period for the RSI calculations used to generate the' + 'candles. This seperate from the RSI plot/histogram length.'

string TT_PBIAS = 'Smoothing feature for the OPEN of the HARSI candles.' + '\n\nIncreases bias toward the prior open value which can' + ' help provide better visualisation of trend strength.' + '\n\n** By changing the Open values, High and Low can also' + ' be distorted - however Close will remain unchanged.'

string TT_SMRSI = 'This option smoothes the RSI in a manner similar to HA' + ' open, but uses the realtime rsi rather than the prior' + ' close value.'

string TT_STOCH = 'Uses the RSI generated by the above settings, and as such' + ' will be affected by the smoothing option.'

string TT_STFIT = 'Adjusts the vertical scaling of the stochastic, can help' + ' to prevent distortion of other data in the channel.' + '\n\nHas no impact cross conditions.'

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
//                            ====== INPUTS ======                            //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////


// -- RSI plot config

string GROUP_PLOT = 'Config » RSI Plot'
i_source = ohlc4, group=GROUP_PLOT
i_lenRSI = 7
i_mode = true
i_showPlot = true
i_showHist = true


// -- Channel OB/OS config

string GROUP_CHAN = 'Config » OB/OS Boundaries'
i_upper = 50
i_upperx = 30

i_lower = -50
i_lowerx = -30

// Settings


// WaveTrend
wtShow = true
wtBuyShow = true
wtGoldShow = true
wtSellShow =true
wtDivShow = true
vwapShow = true
wtChannelLen = 9
wtAverageLen = 12
wtMASource = hlc3
wtMALen = 3

// WaveTrend Overbought & Oversold lines
obLevel = 53
obLevel2 = 60
obLevel3 = 100
osLevel = -53
osLevel2 = -60
osLevel3 = -75

// Divergence WT
wtShowDiv = true
wtShowHiddenDiv = false
showHiddenDiv_nl = true
wtDivOBLevel = 45
wtDivOSLevel = -65

// Divergence extra range
wtDivOBLevel_addshow = true
wtDivOBLevel_add = 15
wtDivOSLevel_add = -40

// RSI
rsiShow = false
rsiSRC = close
rsiLen = 14
rsiOversold = 30
rsiOverbought = 60

// Divergence RSI
rsiShowDiv = false
rsiShowHiddenDiv = false
rsiDivOBLevel = 60
rsiDivOSLevel = 30

// Colors
colorRed = #ff0000
colorPurple = #e600e6
colorGreen = #3fff00
colorOrange = #e2a400
colorYellow = #ffe500
colorWhite = #ffffff
colorPink = #ff00f0
colorBluelight = #31c0ff

colorWT1 = #49536151
colorWT2 = #7b9fd596

colorWT2_ = #131722


// FUNCTIONS 

// Divergences 
f_top_fractal(src) =>
    src[4] < src[2] and src[3] < src[2] and src[2] > src[1] and src[2] > src[0]
f_bot_fractal(src) =>
    src[4] > src[2] and src[3] > src[2] and src[2] < src[1] and src[2] < src[0]
f_fractalize(src) =>
    f_top_fractal(src) ? 1 : f_bot_fractal(src) ? -1 : 0

f_findDivs(src, topLimit, botLimit, useLimits) =>
    fractalTop = f_fractalize(src) > 0 and (useLimits ? src[2] >= topLimit : true) ? src[2] : na
    fractalBot = f_fractalize(src) < 0 and (useLimits ? src[2] <= botLimit : true) ? src[2] : na
    highPrev = ta.valuewhen(fractalTop, src[2], 0)[2]
    highPrice = ta.valuewhen(fractalTop, high[2], 0)[2]
    lowPrev = ta.valuewhen(fractalBot, src[2], 0)[2]
    lowPrice = ta.valuewhen(fractalBot, low[2], 0)[2]
    bearSignal = fractalTop and high[2] > highPrice and src[2] < highPrev
    bullSignal = fractalBot and low[2] < lowPrice and src[2] > lowPrev
    bearDivHidden = fractalTop and high[2] < highPrice and src[2] > highPrev
    bullDivHidden = fractalBot and low[2] > lowPrice and src[2] < lowPrev
    [fractalTop, fractalBot, lowPrev, bearSignal, bullSignal, bearDivHidden, bullDivHidden]


// WaveTrend
f_wavetrend(src, chlen, avg, malen, tf) =>
    tfsrc = request.security(syminfo.tickerid, tf, src)
    esa = ta.ema(tfsrc, chlen)
    de = ta.ema(math.abs(tfsrc - esa), chlen)
    ci = (tfsrc - esa) / (0.015 * de)
    wt1 = request.security(syminfo.tickerid, tf, ta.ema(ci, avg))
    wt2 = request.security(syminfo.tickerid, tf, ta.sma(wt1, malen))
    wtVwap = wt1 - wt2
    wtOversold = wt2 <= osLevel
    wtOverbought = wt2 >= obLevel
    wtCross = ta.cross(wt1, wt2)
    wtCrossUp = wt2 - wt1 <= 0
    wtCrossDown = wt2 - wt1 >= 0
    wtCrosslast = ta.cross(wt1[2], wt2[2])
    wtCrossUplast = wt2[2] - wt1[2] <= 0
    wtCrossDownlast = wt2[2] - wt1[2] >= 0
    [wt1, wt2, wtOversold, wtOverbought, wtCross, wtCrossUp, wtCrossDown, wtCrosslast, wtCrossUplast, wtCrossDownlast, wtVwap]


// Get higher timeframe candle
f_getTFCandle(_tf) =>
    _open = request.security(ticker.heikinashi(syminfo.tickerid), _tf, open, barmerge.gaps_off, barmerge.lookahead_on)
    _close = request.security(ticker.heikinashi(syminfo.tickerid), _tf, close, barmerge.gaps_off, barmerge.lookahead_on)
    _high = request.security(ticker.heikinashi(syminfo.tickerid), _tf, high, barmerge.gaps_off, barmerge.lookahead_on)
    _low = request.security(ticker.heikinashi(syminfo.tickerid), _tf, low, barmerge.gaps_off, barmerge.lookahead_on)
    hl2 = (_high + _low) / 2.0
    newBar = ta.change(_open)
    candleBodyDir = _close > _open
    [candleBodyDir, newBar]


//  zero median rsi helper function, just subtracts 50.
f_zrsi(_source, _length) =>
    ta.rsi(_source, _length) - 50

//  zero median stoch helper function, subtracts 50 and includes % scaling
f_zstoch(_source, _length, _smooth, _scale) =>
    float _zstoch = ta.stoch(_source, _source, _source, _length) - 50
    float _smoothed = ta.sma(_zstoch, _smooth)
    float _scaled = _smoothed / 100 * _scale
    _scaled

//  mode selectable rsi function for standard, or smoothed output
f_rsi(_source, _length, _mode) =>

    //  get base rsi
    float _zrsi = f_zrsi(_source, _length)

    //  smoothing in a manner similar to HA open, but rather using the realtime
    //  rsi in place of the prior close value.
    var float _smoothed = na
    _smoothed := na(_smoothed[1]) ? _zrsi : (_smoothed[1] + _zrsi) / 2

    //  return the requested mode
    _mode ? _smoothed : _zrsi

//  RSI Heikin-Ashi generation function
f_rsiHeikinAshi(_length) =>

    //  get close rsi
    float _closeRSI = f_zrsi(close, _length)

    //  emulate "open" simply by taking the previous close rsi value
    float _openRSI = nz(_closeRSI[1], _closeRSI)

    //  the high and low are tricky, because unlike "high" and "low" by
    //  themselves, the RSI results can overlap each other. So first we just go
    //  ahead and get the raw results for high and low, and then..
    float _highRSI_raw = f_zrsi(high, _length)
    float _lowRSI_raw = f_zrsi(low, _length)
    //  ..make sure we use the highest for high, and lowest for low
    float _highRSI = math.max(_highRSI_raw, _lowRSI_raw)
    float _lowRSI = math.min(_highRSI_raw, _lowRSI_raw)

    //  ha calculation for close
    float _close = (_openRSI + _highRSI + _lowRSI + _closeRSI) / 4

   

// Indicators
// ### 3 Line Strike
//
showBear3LS = true
showBull3LS = true

// RSI
rsi = ta.rsi(rsiSRC, rsiLen)
rsiColor = rsi <= rsiOversold ? colorGreen : rsi >= rsiOverbought ? colorRed : colorPurple


// Calculates WaveTrend
[wt1, wt2, wtOversold, wtOverbought, wtCross, wtCrossUp, wtCrossDown, wtCross_last, wtCrossUp_last, wtCrossDown_last, wtVwap] = f_wavetrend(wtMASource, wtChannelLen, wtAverageLen, wtMALen, timeframe.period)

// WT Divergences
[wtFractalTop, wtFractalBot, wtLow_prev, wtBearDiv, wtBullDiv, wtBearDivHidden, wtBullDivHidden] = f_findDivs(wt2, wtDivOBLevel, wtDivOSLevel, true)

[wtFractalTop_add, wtFractalBot_add, wtLow_prev_add, wtBearDiv_add, wtBullDiv_add, wtBearDivHidden_add, wtBullDivHidden_add] = f_findDivs(wt2, wtDivOBLevel_add, wtDivOSLevel_add, true)
[wtFractalTop_nl, wtFractalBot_nl, wtLow_prev_nl, wtBearDiv_nl, wtBullDiv_nl, wtBearDivHidden_nl, wtBullDivHidden_nl] = f_findDivs(wt2, 0, 0, false)

wtBearDivHidden_ = showHiddenDiv_nl ? wtBearDivHidden_nl : wtBearDivHidden
wtBullDivHidden_ = showHiddenDiv_nl ? wtBullDivHidden_nl : wtBullDivHidden

wtBearDivColor = wtShowDiv and wtBearDiv or wtShowHiddenDiv and wtBearDivHidden_ ? colorRed : na
wtBullDivColor = wtShowDiv and wtBullDiv or wtShowHiddenDiv and wtBullDivHidden_ ? colorGreen : na

wtBearDivColor_add = wtShowDiv and wtDivOBLevel_addshow and wtBearDiv_add or wtShowHiddenDiv and wtDivOBLevel_addshow and wtBearDivHidden_add ? #9a0202 : na
wtBullDivColor_add = wtShowDiv and wtDivOBLevel_addshow and wtBullDiv_add or wtShowHiddenDiv and wtDivOBLevel_addshow and wtBullDivHidden_add ? #1b5e20 : na

// RSI Divergences
[rsiFractalTop, rsiFractalBot, rsiLow_prev, rsiBearDiv, rsiBullDiv, rsiBearDivHidden, rsiBullDivHidden] = f_findDivs(rsi, rsiDivOBLevel, rsiDivOSLevel, true)
[rsiFractalTop_nl, rsiFractalBot_nl, rsiLow_prev_nl, rsiBearDiv_nl, rsiBullDiv_nl, rsiBearDivHidden_nl, rsiBullDivHidden_nl] = f_findDivs(rsi, 0, 0, false)

rsiBearDivHidden_ = showHiddenDiv_nl ? rsiBearDivHidden_nl : rsiBearDivHidden
rsiBullDivHidden_ = showHiddenDiv_nl ? rsiBullDivHidden_nl : rsiBullDivHidden

rsiBearDivColor = rsiShowDiv and rsiBearDiv or rsiShowHiddenDiv and rsiBearDivHidden_ ? colorRed : na
rsiBullDivColor = rsiShowDiv and rsiBullDiv or rsiShowHiddenDiv and rsiBullDivHidden_ ? colorGreen : na

// Buy signal.
buySignal = wtCross and wtCrossUp and wtOversold

buySignalDiv = wtShowDiv and wtBullDiv or wtShowDiv and wtBullDiv_add or rsiShowDiv and rsiBullDiv

buySignalDiv_color = wtBullDiv ? colorGreen : wtBullDiv_add ? color.new(colorGreen, 10) : rsiShowDiv ? colorGreen : na

// Sell signal
sellSignal = wtCross and wtCrossDown and wtOverbought

sellSignalDiv = wtShowDiv and wtBearDiv or wtShowDiv and wtBearDiv_add or rsiShowDiv and rsiBearDiv

sellSignalDiv_color = wtBearDiv ? colorRed : wtBearDiv_add ? color.new(colorRed, 10) : rsiBearDiv ? colorRed : na

// Indicators

//  standard, or ha smoothed rsi for the line plot and/or histogram
float RSI = f_rsi(i_source, i_lenRSI, i_mode)

//  shadow, invisible
color colShadow = color.rgb(0, 0, 0, 20)
color colNone = color.rgb(0, 0, 0, 100)

//  rsi color
//color colRSI        = RSI >=30 ? color.red : color.gray
color colRSI = RSI < -31 ? #00e6774a : RSI > 31 ? #ff52521a : #ffffff

//Crosses
cross_up = RSI[1] > 30
cross_down = RSI[1] < -30
crossd_up = RSI > 30
crossd_down = RSI < -30

getCandleColorIndex(barIndex) =>
    int ret = na
    if (close[barIndex] > open[barIndex])
        ret := 1
    else if (close[barIndex] < open[barIndex])
        ret := -1
    else
        ret := 0
    ret

//
// Check for engulfing candles
isEngulfing(checkBearish) =>
    // In an effort to try and make this a bit more consistent, we're going to calculate and compare the candle body sizes
    // to inform the engulfing or not decision, and only use the open vs close comparisons to identify the candle "color"
    ret = false
    sizePrevCandle = close[1] - open[1] // negative numbers = red, positive numbers = green, 0 = doji
    sizeCurrentCandle = close - open    // negative numbers = red, positive numbers = green, 0 = doji
    isCurrentLagerThanPrevious = (math.abs(sizeCurrentCandle) > math.abs(sizePrevCandle)) ? true : false
    // We now have the core info to evaluate engulfing candles
    switch checkBearish
        true => 
            // Check for bearish engulfing (green candle followed by a larger red candle)
            isGreenToRed = ((getCandleColorIndex(0) < 0) and (getCandleColorIndex(1) > 0)) ? true : false
            ret := (isCurrentLagerThanPrevious and isGreenToRed) ? true : false
        false => 
            // Check for bullish engulfing (red candle followed by a larger green candle)
            isRedToGreen = ((getCandleColorIndex(0) > 0) and (getCandleColorIndex(1) < 0)) ? true : false
            ret := (isCurrentLagerThanPrevious and isRedToGreen) ? true : false
        => ret := false // This should be impossible to trigger...
    ret
//
// Helper functions that wraps the isEngulfing above...
isBearishEngulfuing() =>
    ret = isEngulfing(true)
    ret
//
isBullishEngulfuing() =>
    ret = isEngulfing(false)
    ret
//
// Functions to check for 3 consecutive candles of one color, followed by an engulfing candle of the opposite color
//
// Bearish 3LS = 3 green candles immediately followed by a bearish engulfing candle
is3LSBear() =>
    ret = false
    is3LineSetup = ((getCandleColorIndex(1) > 0) and (getCandleColorIndex(2) > 0) and (getCandleColorIndex(3) > 0)) ? true : false
    ret := (is3LineSetup and isBearishEngulfuing()) ? true : false
    ret
//
// Bullish 3LS = 3 red candles immediately followed by a bullish engulfing candle
is3LSBull() =>
    ret = false
    is3LineSetup = ((getCandleColorIndex(1) < 0) and (getCandleColorIndex(2) < 0) and (getCandleColorIndex(3) < 0)) ? true : false
    ret := (is3LineSetup and isBullishEngulfuing()) ? true : false
    ret


// ### 3 Line Strike
is3LSBearSig = is3LSBear() and crossd_up
is3LSBullSig = is3LSBull() and crossd_down
/// Plots


// Standard plots for the 3LS signal
plotshape(showBull3LS  ? is3LSBullSig : na, style=shape.triangleup, color=color.rgb(0, 255, 0, 0), location=location.belowbar, size=size.small, text='3LS-Bull', title='3 Line Strike Up')
plotshape(showBear3LS  ? is3LSBearSig : na, style=shape.triangledown, color=color.rgb(255, 0, 0, 0), location=location.abovebar, size=size.small, text='3LS-Bear', title='3 Line Strike Down')



plotchar(cross_down[1] and wtBuyShow and buySignal[2] and wtDivShow and buySignalDiv ? -20 : na, title='Divergence buy circle + Buy + RSI OS', char='·', color=color.new(colorGreen, 0), location=location.belowbar, size=size.large, offset=-2)
plotchar(cross_up[1] and wtSellShow and sellSignal[2] and wtDivShow and sellSignalDiv ? 20 : na, title='Divergence sell circle + Sell + RSI OB', char='·', color=color.new(colorRed, 0), location=location.abovebar, size=size.large, offset=-2)
plotchar(cross_down[1] and wtBuyShow and buySignal[2] ? -20 : na, title='Buy + RSI OS', char='·', color=color.new(colorGreen, 70), location=location.belowbar, size=size.normal, offset=-2)
plotchar(cross_up[1] and wtSellShow and sellSignal[2] ? 20 : na, title='Sell + RSI OB', char='·', color=color.new(colorRed, 70), location=location.abovebar, size=size.normal, offset=-2)

/// Alerts
alertcondition((cross_down[1] and wtBuyShow and buySignal[2] and wtDivShow and buySignalDiv) or (cross_up[1] and wtSellShow and sellSignal[2] and wtDivShow and sellSignalDiv), title='Buy/Sell Signal Triggered', message='Buy/Sell Signal {{exchange}}:{{ticker}}')
alertcondition(is3LSBear() and crossd_up or is3LSBull() and crossd_down, title='3LineStrike Buy/Sell alert', message='3Line Strike Buy or Sell triggered on {{exchange}}:{{ticker}}'  )