MACDh with divergences & impulse system (overlayed on prices)
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © jorgelg93
//@version=5
indicator(title="MACDh with divergences & impulse system (overlayed on prices)", max_lines_count = 500, max_bars_back = 5000, overlay=true)



//================= DIVERGENCE INDICATOR =========== { ========

buysignaltemp_divergencias = false
sellsignaltemp_divergencias = false
buysignalconfirmed = false
sellsignalconfirmed = false

var float dev_threshold_lows_def = 0
var float dev_threshold_highs_def = 0

var line lineLast_HistH = na //this is one of the lines we see on the chart
var line lineLast_HistL = na //this is one of the lines we see on the chart
var label labelLast_HistH = na //this is one of the lines we see on the chart
var label labelLast_HistL = na //this is one of the lines we see on the chart
var int histcruzodesdeabajoIndex_inmediato = 0
var int histcruzodesdearribaIndex_inmediato = 0
//variables to calculate Highs
var int indexHistHighUltimo = 0
var int indexHistHighPenultimo = 0
var int indexHistHighAntepenultimo = 0
var int indexPriceHighUltimo = 0
var int indexPriceHighPenultimo = 0
var int indexPriceHighAntepenultimo = 0
//variables to calculate index Highs
var float histHighUltimo = 0
var float histHighPenultimo = 0
var float histHighAntepenultimo = 0
var float priceHighUltimo = 0
var float priceHighPenultimo = 0
var float priceHighAntepenultimo = 0
//variables to calculate index Lows
var int indexHistLowUltimo = 0
var int indexHistLowPenultimo = 0
var int indexHistLowAntepenultimo = 0
var int indexPriceLowUltimo = 0
var int indexPriceLowPenultimo = 0
var int indexPriceLowAntepenultimo = 0
//variables to calculate Lows
var float histLowUltimo = 0
var float histLowPenultimo = 0
var float histLowAntepenultimo = 0
var float priceLowUltimo = 0
var float priceLowPenultimo = 0
var float priceLowAntepenultimo = 0


plotimpulse = input.bool(true, title="Show Impulse System over prices?")

// Getting inputs
fast_length = input(title="Fast Length", group="MACD", defval=12)
slow_length = input(title="Slow Length", group="MACD", defval=26)
signal_length = input.int(title="Signal Smoothing", group="MACD",  minval = 1, maxval = 50, defval = 9)

threshold_multiplier = input.float(title="Vertical deviation on Price peaks", group="MACD Histogram Divergences Criteria", defval=25, minval=0, tooltip = "Deviation refers to the difference/relation/vertical distance between the PRICE peaks involved in the divergence")
hist_peaks_diff = input.float(title="Vertical deviation on MACD Histogram peaks", group="MACD Histogram Divergences Criteria", defval = 0, tooltip = "Refers to the difference/relation/vertical distance between the MACH HISTOGRAM peaks involved in the divergence: 1st Histogram Peak is X times the 2nd")
minDivWidth = input.int(title="Divergence min width",  group="MACD Histogram Divergences Criteria", defval = 0, tooltip = "Refers to the minimum horizontal distance between the MACH histogram peaks involved in the divergence") // minima_cantidad_de_barras_entre_los_picos
maxDivWidth = input.int(title="Divergence max width", group="MACD Histogram Divergences Criteria", defval = 200, tooltip = "Refers to the maximum horizontal distance between the MACH histogram peaks involved in the divergence") // maxima_cantidad_de_barras_entre_los_picos
plotBullDivergences = input.bool(true, title="Plot regular Bullish divergences?")
plotBearDivergences = input.bool(true, title="Plot regular Bearish divergences?")
deleteLastLines = input.bool(false, title="Delete Previous Cancelled Divergences?")
plottempsignals = input.bool(true, title="Plot Temporary Buy/Sell Signals?")
plotconfirmedsignals = input.bool(true, title="Plot Buy/Sell Confirmed Signals?")

[macdLine, signalLine, hist] = ta.macd(close, fast_length,slow_length,signal_length)


//================== impulse system =========================//

[macdLine_impulse_div, signalLine_impulse_div, histline_impulse_div] = ta.macd(close, 12, 26, 9)


ema_impulse_div = ta.ema(close, 13)

greenimpulse_div = close > ema_impulse_div and histline_impulse_div > histline_impulse_div[1]
redimpulse_div = close < ema_impulse_div and histline_impulse_div < histline_impulse_div[1]
blueimpulse_div = 
             (close > ema_impulse_div and histline_impulse_div < histline_impulse_div[1]) 
             or (close < ema_impulse_div and histline_impulse_div > histline_impulse_div[1])

barcolor(plotimpulse and greenimpulse_div ? color.green : plotimpulse and redimpulse_div ? color.red : plotimpulse and blueimpulse_div ? color.blue : na)

//===========================================//




//This verifies if the MACD histogram crossed over or under the 0 axis during the previous bar/candle
histcruzoover = ta.crossover(hist[1],0)
histcruzounder = ta.crossunder(hist[1],0)
//This verifies if the MACD histogram crossed over or under the 0 axis during the current bar/candle
histcruzoover_inmediato = ta.crossover(hist,0)
histcruzounder_inmediato = ta.crossunder(hist,0)


//=======================

//calculate the deviation of prices
calc_dev(base_price, price) => 100 * (price - base_price) / price

//Calculate deviation threshold for identifying major swings
dev_threshold_high = ta.atr(10) / high * 100 * threshold_multiplier
dev_threshold_low = ta.atr(10) / low * 100 * threshold_multiplier


//=======================
//these lines save the bar_index if the histogram bar in this tick is crossing over or under

if histcruzoover_inmediato
    histcruzodesdeabajoIndex_inmediato := bar_index

if histcruzounder_inmediato
    histcruzodesdearribaIndex_inmediato := bar_index

//=======================


//the Bear cycle is officially closed in the previous bar and we have to analize and see if during that cycle there was some bullish divergence and rewrite the variables
if histcruzoover
// if histcruzoover and barstate.isconfirmed
    //it saves the penultimate high of the histogram 
    histLowAntepenultimo := histLowPenultimo
    histLowPenultimo := histLowUltimo
    //it saves the price Lows
    priceLowAntepenultimo := priceLowPenultimo
    priceLowPenultimo := priceLowUltimo
    //it saves the "histogram indexes"
    indexHistLowAntepenultimo := indexHistLowPenultimo
    indexHistLowPenultimo := indexHistLowUltimo
    //it saves the "price indexes"
    indexPriceLowAntepenultimo := indexPriceLowPenultimo
    indexPriceLowPenultimo := indexPriceLowUltimo
    label.delete(labelLast_HistH) 
    label.delete(labelLast_HistL)
    line.delete(lineLast_HistH)
    line.delete(lineLast_HistL)



    //for BULLISH DIVERGENCES
    dev2 = calc_dev(priceLowPenultimo, priceLowAntepenultimo)
    dev3 = priceLowAntepenultimo/priceLowPenultimo

    if ( plotBullDivergences and
         math.abs(dev2) < dev_threshold_lows_def and priceLowPenultimo < priceLowAntepenultimo and histLowPenultimo  > histLowAntepenultimo 
         and indexPriceLowPenultimo - indexPriceLowAntepenultimo >= minDivWidth 
         and indexPriceLowPenultimo - indexPriceLowAntepenultimo <= maxDivWidth 
         and indexHistLowPenultimo - indexHistLowAntepenultimo >= minDivWidth 
         and indexHistLowPenultimo - indexHistLowAntepenultimo <= maxDivWidth
         and histLowAntepenultimo / histLowPenultimo >= hist_peaks_diff
         )

        buysignalconfirmed := true

        top1 = line.new(indexPriceLowAntepenultimo, priceLowAntepenultimo, indexPriceLowPenultimo, priceLowPenultimo, color=color.green, width=2)
  
plotshape(plotconfirmedsignals and buysignalconfirmed ? low : na , style=shape.triangleup, text = "Bull \n confirmed", location=location.belowbar, color=color.green, size=size.small)


//the Bull cycle officially ended during the last bar and we have to analize and see if during that cycle there was some bearish divergence and rewrite the variables
if histcruzounder
// if histcruzounder and barstate.isconfirmed
    //it saves the penultimate high of the histogram
    histHighAntepenultimo := histHighPenultimo
    histHighPenultimo := histHighUltimo
    //it saves the price highs
    priceHighAntepenultimo := priceHighPenultimo
    priceHighPenultimo := priceHighUltimo
    //it saves the "histogram indexes"
    indexHistHighAntepenultimo := indexHistHighPenultimo
    indexHistHighPenultimo := indexHistHighUltimo
    //it saves the "price indexes"
    indexPriceHighAntepenultimo := indexPriceHighPenultimo
    indexPriceHighPenultimo := indexPriceHighUltimo
    label.delete(labelLast_HistH) 
    label.delete(labelLast_HistL)
    line.delete(lineLast_HistH)
    line.delete(lineLast_HistL)



    //for BEARISH DIVERGENCES
    dev2 = calc_dev(priceHighPenultimo, priceHighAntepenultimo)
    dev3 = priceHighPenultimo/priceHighAntepenultimo

    if ( plotBearDivergences and
         math.abs(dev2) < dev_threshold_highs_def and priceHighPenultimo > priceHighAntepenultimo and histHighPenultimo < histHighAntepenultimo 
         and indexPriceHighPenultimo - indexPriceHighAntepenultimo >= minDivWidth 
         and indexPriceHighPenultimo - indexPriceHighAntepenultimo <= maxDivWidth
         and indexHistHighPenultimo - indexHistHighAntepenultimo >= minDivWidth 
         and indexHistHighPenultimo - indexHistHighAntepenultimo <= maxDivWidth
         and histHighAntepenultimo / histHighPenultimo >= hist_peaks_diff
         )

        sellsignalconfirmed := true
        
        top1 = line.new(indexPriceHighAntepenultimo, priceHighAntepenultimo, indexPriceHighPenultimo, priceHighPenultimo, color=color.red, width=2)

plotshape(plotconfirmedsignals and sellsignalconfirmed ? high : na, style=shape.triangledown,text = "Bear \n confirmed", location=location.abovebar, color=color.red, size=size.small)


//=======================================
// PIVOTS highs function
pivotsH(src1, src2) =>

    c = nz(src1) // this could be the histogram, the price or any other value from any indicator
    c2 = nz(src2)

    //as long as the histogram is greater than zero I will be looking for higher highs (anyways, I believe this "if" could be redundant)
    if hist > 0

        ind = bar_index - histcruzodesdeabajoIndex_inmediato

        //OK checker
        ok = true
        for i = 0 to ind
            if src1[i] > c // IF THE CURRENT BAR IS SMALLER OR LESS POSITIVE THAN ANY OF THE OTHER PREVIOUS BARS THEN THE PIVOT HIGH REMAINS INVALIDATED
                ok := false
        if ok // If pivot is valid, return bar index + high of price values; PIVOT WILL ALWAYS BE TRUE IF ITS INDEX IS SAVED AND ITS CORRESPONDENT HIGH OR LOW AS LONG AS IT DOES NOT REMAIN INVALIDATED IN THE ABOVE LINES
            [bar_index, c, bar_index, c2]
        else
            [int(na), float(na), int(na), float(na)]
//=======================================

//=======================================
// PIVOTS lows function
pivotsL(src1, src2) =>

    c = nz(src1) // this could be the histogram, the price or any other value from any indicator
    c2 = nz(src2)

    //as long as the histogram is lower than zero I will be looking for lower lows (anyways, I believe this "if" could be redundant)
    if hist < 0

        ind = bar_index - histcruzodesdearribaIndex_inmediato

        //OK checker
        ok = true
        for i = 0 to ind

            if src1[i] < c // IF THE CURRENT BAR IS GREATER OR LESS NEGATIVE THAN ANY OF THE OTHER PREVIOUS BARS THEN THE PIVOT LOW REMAINS INVALIDATED
                ok := false
                                                                         
        if ok // If pivot is valid, return bar index + high price value; PIVOT WILL ALWAYS BE TRUE IF ITS INDEX IS SAVED AND ITS CORRESPONDENT HIGH OR LOW AS LONG AS IT DOES NOT REMAIN INVALIDATED IN THE ABOVE LINES
            [bar_index, c, bar_index, c2]
        else
            [int(na), float(na), int(na), float(na)]

//=======================================



//=======================================
// FIND BEARISH DIVERGENCES by looking for higher highs of the histogram
[iHist_H, pHist_H, indexPreciocuandoHistTieneHigherHigh, PreciocuandoHistTieneHigherHigh] = pivotsH(hist, high) //I want to know the histogram high
[iPrice_H, pPrice_H, indexHistcuandoPrecioTieneHigherHigh, HistcuandoPrecioTieneHigherHigh] = pivotsH(high, hist) //I want to know the price high

//if we have a valid pivot high, it saves the index and the value of that pivot high; this way the last pivot detected will always be saved
if not na(iHist_H)
    indexHistHighUltimo := iHist_H
    histHighUltimo := pHist_H 
    
if not na(iPrice_H)
    indexPriceHighUltimo := iPrice_H
    priceHighUltimo := pPrice_H
    dev_threshold_highs_def := dev_threshold_high //I want to save the "threshold" of that maximum

//=======================================


//=======================================
// FIND BULLISH DIVERGENCES by looking for lower lows of the histogram
[iHist_L, pHist_L, indexPreciocuandoHistTieneLowerLow, PreciocuandoHistTieneLowerLow] = pivotsL(hist, low) //I want to know the histogram low
[iPrice_L, pPrice_L, indexHistcuandoPrecioTieneLowerLow, HistcuandoPrecioTieneLowerLow] = pivotsL(low, hist) //I want to know the price low


//if we have a valid pivot low, it saves the index and the value of that pivot low; this way the last pivot detected will always be saved
if not na(iHist_L)
    indexHistLowUltimo := iHist_L
    histLowUltimo := pHist_L 

if not na(iPrice_L)
    indexPriceLowUltimo := iPrice_L
    priceLowUltimo := pPrice_L 
    dev_threshold_lows_def := dev_threshold_low //I want to save the "threshold" of that minimum
    
//=======================================

//it calculates prices deviations
dev300 = calc_dev(priceHighUltimo, priceHighPenultimo)
dev301 = calc_dev(priceLowUltimo, priceLowPenultimo)

dev33 = priceHighUltimo/priceHighPenultimo
dev34 = priceLowPenultimo/priceLowUltimo



if not na(iPrice_H) or not na(iHist_H)//it executes itself only when there is a new high of the price or a new high of the histogram
// if not na(iPrice_H) or not na(iHist_H) and barstate.isconfirmed //it executes itself only when there is a new high of the price or a new high of the histogram

    //=======================================

    // to draw possible/temporary BEARISH DIVERGENCES
    if ( plotBearDivergences and
         math.abs(dev300) < dev_threshold_highs_def and priceHighUltimo > priceHighPenultimo and histHighUltimo < histHighPenultimo 
         and indexPriceHighUltimo - indexPriceHighPenultimo >= minDivWidth 
         and indexPriceHighUltimo - indexPriceHighPenultimo <= maxDivWidth 
         and indexHistHighUltimo - indexHistHighPenultimo >= minDivWidth 
         and indexHistHighUltimo - indexHistHighPenultimo <= maxDivWidth
         and histHighPenultimo / histHighUltimo >= hist_peaks_diff

         )


        label.delete(labelLast_HistH) //it erases any previous label
        labelLast_HistH := label.new(indexPriceHighUltimo, priceHighUltimo, style= label.style_label_down, text = "Possible \n Bearish \n Div", color=color.red, size=size.small) // rewrites

        line.delete(lineLast_HistH) // this erase all the temporary/possible bearish divergences that took place in the past
        lineLast_HistH := line.new(indexPriceHighPenultimo, priceHighPenultimo, indexPriceHighUltimo, priceHighUltimo, color=color.red, width=1, style=line.style_dashed)

        //these two lines draw dotted lines everytime that a temporary/possible bearish divergence takes place
        // as long as "deleteLastLines" is unmarked in the options for the script
        if not deleteLastLines
            lineLast_HistH_temp = line.new(indexPriceHighPenultimo, priceHighPenultimo, indexPriceHighUltimo, priceHighUltimo, color=color.red, width=1, style=line.style_dashed)
        
        sellsignaltemp_divergencias := true

    else
        // ERASES THE CANCELLED DIVERGENCES
        if ( plotBearDivergences and
             math.abs(dev300) > dev_threshold_highs_def or priceHighUltimo < priceHighPenultimo or histHighUltimo > histHighPenultimo 
             or indexPriceHighUltimo - indexPriceHighPenultimo <= minDivWidth 
             or indexPriceHighUltimo - indexPriceHighPenultimo >= maxDivWidth 
             or indexHistHighUltimo - indexHistHighPenultimo <= minDivWidth 
             or indexHistHighUltimo - indexHistHighPenultimo >= maxDivWidth
             or histHighPenultimo / histHighUltimo <= hist_peaks_diff
             )

            label.delete(labelLast_HistH)
            line.delete(lineLast_HistH)

                                     
if not na(iPrice_L) or not na(iHist_L) //it executes itself only when there is a new low of the price or a new low of the histogram
// if not na(iPrice_L) or not na(iHist_L) and barstate.isconfirmed //it executes itself only when there is a new low of the price or a new low of the histogram

    //=======================================

    // to draw possible/temporary BULLISH DIVERGENCES
    if ( plotBullDivergences and
         math.abs(dev301) < dev_threshold_lows_def and priceLowUltimo < priceLowPenultimo and histLowUltimo  > histLowPenultimo 
         and indexPriceLowUltimo - indexPriceLowPenultimo >= minDivWidth 
         and indexPriceLowUltimo - indexPriceLowPenultimo <= maxDivWidth
         and indexHistLowUltimo - indexHistLowPenultimo >= minDivWidth 
         and indexHistLowUltimo - indexHistLowPenultimo <= maxDivWidth
         and histLowPenultimo / histLowUltimo >= hist_peaks_diff
         )


        label.delete(labelLast_HistL) //it erases any previous label
        labelLast_HistL := label.new(indexPriceLowUltimo, priceLowUltimo, style= label.style_label_up, text = "Possible \n Bullish \n Div", color=color.green, size=size.small) //rewrites

        line.delete(lineLast_HistL) //it erases any other temporary/possible bullish divergence that took place in the past
        lineLast_HistL := line.new(indexPriceLowPenultimo, priceLowPenultimo, indexPriceLowUltimo, priceLowUltimo, color=color.green, width=1, style=line.style_dashed)


        //these two lines draw dotted lines everytime that a temporary/possible divergence takes place
        // as long as "deleteLastLines" is unmarked in the options for the script
        if not deleteLastLines
            lineLast_HistL_temp = line.new(indexPriceLowPenultimo, priceLowPenultimo, indexPriceLowUltimo, priceLowUltimo, color=color.green, width=1, style=line.style_dashed)
        
        buysignaltemp_divergencias := true

    else
        // ERASES THE CANCELLED DIVERGENCES
        if ( plotBullDivergences and
             math.abs(dev301) > dev_threshold_lows_def or priceLowUltimo > priceLowPenultimo or histLowUltimo < histLowPenultimo 
             or indexPriceLowUltimo - indexPriceLowPenultimo <= minDivWidth 
             or indexPriceLowUltimo - indexPriceLowPenultimo >= maxDivWidth
             or indexHistLowUltimo - indexHistLowPenultimo <= minDivWidth 
             or indexHistLowUltimo - indexHistLowPenultimo >= maxDivWidth
             or histLowPenultimo / histLowUltimo <= hist_peaks_diff
             )

            label.delete(labelLast_HistL)
            line.delete(lineLast_HistL)



buy_beautiful_temp_div = (buysignaltemp_divergencias) 
     or (buysignaltemp_divergencias[1] and (low > low[1] or hist > hist[1]) and histLowUltimo > histLowPenultimo) 
     or (buysignaltemp_divergencias[2] and ((low > low[2] and low[1] > low[2]) or (hist > hist[2] and hist[1] > hist[2])) and histLowUltimo > histLowPenultimo)
     or (buysignaltemp_divergencias[3] and ((low > low[3] and low[1] > low[3] and low[2] > low[3]) or ( hist > hist[3] and hist[1] > hist[3] and hist[2] > hist[3])) and histLowUltimo > histLowPenultimo)

sell_beautiful_temp_div = (sellsignaltemp_divergencias)
     or (sellsignaltemp_divergencias[1] and (high < high[1] or hist < hist[1]) and histHighUltimo < histHighPenultimo) 
     or (sellsignaltemp_divergencias[2] and ((high < high[2] and high[1] < high[2]) or (hist < hist[2] and hist[1] < hist[2])) and histHighUltimo < histHighPenultimo)
     or (sellsignaltemp_divergencias[3] and ((high < high[3] and high[1] < high[3] and high[2] < high[3]) or (hist < hist[3] and hist[1] < hist[3] and hist[2] < hist[3])) and histHighUltimo < histHighPenultimo)



plotshape(plottempsignals and sell_beautiful_temp_div ? high : na, style=shape.triangledown, location=location.abovebar, color=color.rgb(255, 82, 82, 50), size=size.small)
plotshape(plottempsignals and buy_beautiful_temp_div ? low : na , style=shape.triangleup, location=location.belowbar, color=color.rgb(76, 175, 79, 50), size=size.small)



//END of the core divergence indicator
//======= } ================================================ 


fast_ema = input(title="Fast Ema period", group="Other", defval=12)
slow_ema = input(title="Slow Ema period", group="Other", defval=24)
plotEmas = input.bool(true, title="Plot EMAs current timeframe?", group = "Other")
plotATR1 = input.bool(true, title="Plot ATR1?", group = "Other")
plotATR15 = input.bool(false, title="Plot ATR1.5?", group = "Other")
plotATR2 = input.bool(true, title="Plot ATR2?", group = "Other")
plotATR3 = input.bool(true, title="Plot ATR3?", group = "Other")

emas12 = ta.ema(close, fast_ema)
emas24 = ta.ema(close, slow_ema)

plot(plotEmas ? ta.ema(close, 12) : na, color=color.yellow)
plot(plotEmas ? ta.ema(close, 24) : na, color=color.red)


//1 ATR Line
UpperChannelLine1ATR = ta.ema(close, 20)+(1*ta.atr(10))
LowerChannelLine1ATR = ta.ema(close, 20)-(1*ta.atr(10))

//1.5 ATR LINE
UpperChannelLine1ATR15 = ta.ema(close, 20)+(1.5*ta.atr(10))
LowerChannelLine1ATR15 = ta.ema(close, 20)-(1.5*ta.atr(10))

//2 ATR Line
UpperChannelLine2ATR = ta.ema(close, 20)+(2*ta.atr(10))
LowerChannelLine2ATR = ta.ema(close, 20)-(2*ta.atr(10))

//3 ATR Line
UpperChannelLine3ATR = ta.ema(close, 20)+(3*ta.atr(10))
LowerChannelLine3ATR = ta.ema(close, 20)-(3*ta.atr(10))


color_cond1 = (bar_index+1) % 2 == 0

color_cond2 = (bar_index+1) % 4 == 1

plot(plotATR1 ? UpperChannelLine1ATR : na, title="1ATR", color= color_cond1 ? color.rgb(120, 123, 134, 50) : #00000000, linewidth=1)
plot(plotATR1 ? LowerChannelLine1ATR : na, title="-1ATR", color= color_cond1 ? color.rgb(120, 123, 134, 50) : #00000000, linewidth=1)
plot(plotATR15 ? UpperChannelLine1ATR15 : na, title="1.5ATR", color=color.rgb(230,230,250, 80), linewidth=1)
plot(plotATR15 ? LowerChannelLine1ATR15 : na, title="-1.5ATR",  color=color.rgb(230,230,250, 80), linewidth=1)
plot(plotATR2 ? UpperChannelLine2ATR : na, title="2ATR", color= color_cond2 ? #00000000 : color.rgb(120, 123, 134, 50), linewidth=1)
plot(plotATR2 ? LowerChannelLine2ATR : na, title="-2ATR", color= color_cond2 ? #00000000 : color.rgb(120, 123, 134, 50), linewidth=1)
plot(plotATR3 ? UpperChannelLine3ATR : na, title="-3ATR", color=color.rgb(230,230,250, 80), linewidth=2)
plot(plotATR3 ? LowerChannelLine3ATR : na, title="-3ATR", color=color.rgb(230,230,250, 80), linewidth=2)


