Heikin Ashi Oscillator
    // This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/

// © TraderHalai

//@version=5
indicator("Smoothed Heikin Ashi Oscillator - TraderHalai", " SHA Oscillator - TraderHalai", overlay=false)
//Inputs

i_useSmooth =       input ( true, "Use smoothing Heikin Ashi")
i_smoothingMethod = input.string("SMA", "Method", options=["SMA", "EMA", "HMA", "VWMA", "RMA"])
i_smoothingPeriod = input ( 10, "Smoothing period")

i_infoBox   =       input ( true, "Show Info Box"        )
i_decimalP  =       input ( 2,    "Prices Decimal Places") 
i_boxOffSet =       input ( 5,    "Info Box Offset"      )
i_repaint   =       input (true,  "Repaint -  Keep on for live / Off for backtest")

i_col_grow_above = input(#26A69A, "Above   Grow", group="Histogram", inline="Above")
i_col_fall_above = input(#B2DFDB, "Fall", group="Histogram", inline="Above")
i_col_grow_below = input(#FFCDD2, "Below Grow", group="Histogram", inline="Below")
i_col_fall_below = input(#FF5252, "Fall", group="Histogram", inline="Below")


timeperiod = timeframe.period


//Security functions to avoid repaint, as per PineCoders
f_secureSecurity(_symbol, _res, _src) => request.security(_symbol, _res, _src[1], lookahead = barmerge.lookahead_on)
f_security(_symbol, _res, _src, _repaint) => request.security(_symbol, _res, _src[_repaint ? 0 : barstate.isrealtime ? 1 : 0])[_repaint ? 0 : barstate.isrealtime ? 0 : 1]
f_secSecurity2(_symbol, _res, _src) => request.security(_symbol, _res, _src[1])


candleClose = f_security(syminfo.tickerid, timeperiod, close, i_repaint)
candleOpen = f_security(syminfo.tickerid, timeperiod, open, i_repaint)
candleLow = f_security(syminfo.tickerid, timeperiod, low, i_repaint)
candleHigh = f_security(syminfo.tickerid, timeperiod, high, i_repaint)

haTicker = ticker.heikinashi(syminfo.tickerid)
haClose = f_security(haTicker, timeperiod, close, i_repaint)
haOpen = f_security(haTicker, timeperiod, open, i_repaint)
haLow = f_security(haTicker, timeperiod, low, i_repaint)
haHigh= f_security(haTicker, timeperiod, high, i_repaint)


reverseClose = (2 * (haOpen[1] + haClose[1])) - candleHigh - candleLow - candleOpen

if(reverseClose < candleLow)
    reverseClose := (candleLow + reverseClose) / 2

if(reverseClose > candleHigh)
    reverseClose := (candleHigh + reverseClose) / 2
    

//Smoothing
    
smaSmoothed = ta.sma(reverseClose, i_smoothingPeriod)
emaSmoothed = ta.ema(reverseClose, i_smoothingPeriod)
hmaSmoothed = ta.hma(reverseClose, i_smoothingPeriod)
vwmaSmoothed = ta.vwma(reverseClose, i_smoothingPeriod)
rmaSmoothed = ta.rma(reverseClose, i_smoothingPeriod)

shouldApplySmoothing = i_useSmooth and i_smoothingPeriod > 1 

smoothedReverseClose = reverseClose

if(shouldApplySmoothing)
    if(i_smoothingMethod == "SMA")
        smoothedReverseClose := smaSmoothed
    else if(i_smoothingMethod == "EMA")
        smoothedReverseClose := emaSmoothed
    else if(i_smoothingMethod == "HMA")
        smoothedReverseClose := hmaSmoothed
    else if(i_smoothingMethod == "VWMA")
        smoothedReverseClose := vwmaSmoothed
    else if(i_smoothingMethod == "RMA")
        smoothedReverseClose := rmaSmoothed
    else 
        smoothedReverseClose := reverseClose // Default to non-smoothed for invalid smoothing type
    
    
haBull = candleClose >= smoothedReverseClose

delta = candleClose - smoothedReverseClose

haPivotPrice = smoothedReverseClose + delta[1]



haDirectionText = haBull ? 'BULLISH Above: ' + '\t\t\t\t\t\t\t\t' : 'BEARISH Below: ' + '\t\t\t\t\t\t\t\t'
haPivotText = (haBull and delta > delta[1]) ? 'EXPANDING above: ' + '\t\t\t\t': (not(haBull) and delta < delta[1]) ? 'EXPANDING below: ' + '\t\t\t\t' : (haBull and delta <= delta[1]) ? 'CONTRACTING below: ' : (not(haBull and delta >= delta[1])) ? 'CONTRACTING above: ' : 'Currently equals'


haCol = haBull and delta > delta[1] ? i_col_grow_above : haBull and delta < delta[1] ? i_col_fall_above : not(haBull) and delta < delta[1] ? i_col_fall_below : not(haBull) and delta > delta[1] ? i_col_grow_below : color.gray


f_truncdNum ( Val, DecPl ) => 
    Fact = math.pow (10, DecPl)
    int( Val * Fact) / Fact

// Compute Info Label
var label  Infobox      = na

labelXLoc       = time_close + ( i_boxOffSet * ( time_close - time_close[1] ) )
infoBoxText     =  haDirectionText + str.tostring(f_truncdNum(smoothedReverseClose, i_decimalP)) + '\n' + haPivotText + + str.tostring(f_truncdNum(haPivotPrice, i_decimalP))

///////////////////////////////////////////////////////////////////////////////
// InfoBox Plot

if i_infoBox
    Infobox := label.new ( labelXLoc, 0, infoBoxText, xloc.bar_time, yloc.price, color.new(#00000f, 50), label.style_label_left, color.white )

label.delete ( Infobox[1] )

plot(delta, color=haCol, style=plot.style_columns)
hline(0)


