Gradient Money Flow Divergence Detector
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © JohannCoffee
// Credit HALDRO for the Divergence and Pivot - Detector For Any Indicator


//@version=5
indicator(title = "Gradient Money Flow Divergence Detector", shorttitle = "MF with Divs", overlay = false)

//Moneyflow
length = input.int(14, title="Length", minval=1, group = "---- Money Flow ----")


mfisrc = close
typical_price = hlc3
money_flow = typical_price * volume

positive_flow = math.sum(money_flow * (typical_price > typical_price[1] ? 1 : 0), length)
negative_flow = math.sum(money_flow * (typical_price < typical_price[1] ? 1 : 0), length)
money_flow_ratio = positive_flow / negative_flow

mfi = 100 - (100 / (1 + money_flow_ratio))


// Plot Gradient

red1 = 58, green1 = 80, blue1 = 107  // Color: 3a506b
red2 = 111, green2 = 255, blue2 = 233  // Color: 6fffe9

max_mfi = ta.highest(mfi, length) // max value in the last "length" periods
min_mfi = ta.lowest(mfi, length) // min value in the last "length" periods

mfi_range = max_mfi - min_mfi
mfi_normalized = (mfi - min_mfi) / mfi_range

red = red1 + mfi_normalized * (red2 - red1)
green = green1 + mfi_normalized * (green2 - green1)
blue = blue1 + mfi_normalized * (blue2 - blue1)

mfi_gradient_color = color.new(color.rgb(math.floor(red), math.floor(green), math.floor(blue)), transp=0)


plotchar(mfi, 'Money Flow Line', location = location.bottom, color=mfi_gradient_color, size = size.large, char = '-')
plot(mfi, 'Money Flow', color=mfi_gradient_color, linewidth=3)


// Plotting additional lines
hline(20, "Line 1", color=color.rgb(68,70,81), linewidth=1, linestyle=hline.style_dashed)
hline(50, "Line 2", color=color.rgb(68,70,81), linewidth=1, linestyle=hline.style_solid)
hline(80, "Line 3", color=color.rgb(68,70,81), linewidth=1, linestyle=hline.style_dashed)

// div detector 1 - Micro Div

// Inputs
groupdiv       = '---- Micro Div Lookback ----'
pivR           = 1
pivL           = 21
lbR            = 1
lbL            = input.int (5,   ' '                                 , group = groupdiv, inline = '1')
rangeUpper     = 100
rangeLower     = 6

plotBull       = true
plotBear       = true

//------------------------------------------------------------------------------

PHCond = ta.pivothigh(mfi, pivL, pivR), h3 = +1.1
PLCond = ta.pivotlow (mfi, pivL, pivR), l3 = -0.9

highestHighPoint = ta.highest(PHCond and mfi > 0 ? mfi : na, rangeUpper)
lowestLowPoint = ta.lowest(PLCond and mfi < 0 ? mfi : na, rangeLower)


// Divergence Detect:
osc    = mfi 
plFound = na(ta.pivotlow(mfi, lbL, lbR)) ? false : true
phFound = na(ta.pivothigh(mfi, lbL, lbR)) ? false : true
_inRange1(cond1) =>
    bars = ta.barssince(cond1 == true)
    rangeLower <= bars and bars <= rangeUpper


// Regular Bullish
// Osc: Higher Low
oscHL1 = osc[lbR] > ta.valuewhen(plFound, osc[lbR], 1) and _inRange1(plFound[1]) and mfi != close
// Price: Lower Low
priceLL1 = low[lbR] < ta.valuewhen(plFound, low[lbR], 1)
bullCond = plotBull and priceLL1 and oscHL1 and plFound
plot(plFound ? osc[lbR] : na, offset=-lbR, title='Micro Bullish Div', linewidth=1, color=bullCond ? color.rgb(0, 255, 8) : na)

// Regular Bearish
// Osc: Lower High
oscLH1 = osc[lbR] < ta.valuewhen(phFound, osc[lbR], 1) and _inRange1(phFound[1]) and mfi != close
// Price: Higher High
priceHH = high[lbR] > ta.valuewhen(phFound, high[lbR], 1)
bearCond = plotBear and priceHH and oscLH1 and phFound
plot(phFound ? osc[lbR] : na, offset=-lbR, title='Micro Bearish Div', linewidth=1, color=bearCond ? color.rgb(255, 0, 0) : na)


//------------------------------------------------------------------------------
// div detector 2 - Sub Mid Div

// Inputs
groupdiv2       = '---- Sub-Mid Div Lookback ----'
pivR2           = 1
pivL2           = 21
lbR2            = 1
lbL2            = input.int (15,   ' '                                 , group = groupdiv2, inline = '1')
rangeUpper2     = 100
rangeLower2     = 6

plotBull2       = true
plotBear2       = true

//------------------------------------------------------------------------------


PHCond2 = ta.pivothigh(mfi, pivL2, pivR2), h32 = +1.1
PLCond2 = ta.pivotlow (mfi, pivL2, pivR2), l32 = -0.9

highestHighPoint2 = ta.highest(PHCond2 and mfi > 0 ? mfi : na, rangeUpper2)
lowestLowPoint2 = ta.lowest(PLCond2 and mfi < 0 ? mfi : na, rangeLower2)


// Divergence Detect:
osc2    = mfi 
plFound2 = na(ta.pivotlow(mfi, lbL2, lbR2)) ? false : true
phFound2 = na(ta.pivothigh(mfi, lbL2, lbR2)) ? false : true
_inRange2(cond2) =>
    bars2 = ta.barssince(cond2 == true)
    rangeLower2 <= bars2 and bars2 <= rangeUpper2


// Regular Bullish
// Osc: Higher Low
oscHL2 = osc2[lbR2] > ta.valuewhen(plFound2, osc2[lbR2], 1) and _inRange2(plFound2[1]) and mfi != close
// Price: Lower Low
priceLL2 = low[lbR] < ta.valuewhen(plFound2, low[lbR2], 1)
bullCond2 = plotBull2 and priceLL2 and oscHL2 and plFound2
plot(plFound2 ? osc[lbR2] : na, offset=-lbR, title='Sub-Mid Bullish Div', linewidth=1, color=bullCond2 ? color.rgb(0, 255, 8) : na)

// Regular Bearish
// Osc: Lower High
oscLH2 = osc2[lbR2] < ta.valuewhen(phFound2, osc2[lbR2], 1) and _inRange2(phFound2[1]) and mfi != close
// Price: Higher High
priceHH2 = high[lbR2] > ta.valuewhen(phFound2, high[lbR2], 1)
bearCond2 = plotBear2 and priceHH2 and oscLH2 and phFound2
plot(phFound2 ? osc2[lbR2] : na, offset=-lbR, title='Sub=Mid Bearish Div', linewidth=1, color=bearCond2 ? color.rgb(255, 0, 0) : na)


//------------------------------------------------------------------------------
// div detector 3 - Mid Div //

// Inputs
groupdiv3       = '---- Mid Div Lookback ----'
pivR3           = 1
pivL3           = 21
lbR3            = 1
lbL3            = input.int (55,   ' '                                 , group = groupdiv3, inline = '1')
rangeUpper3     = 100
rangeLower3     = 6

plotBull3       = true
plotBear3       = true

//------------------------------------------------------------------------------


PHCond3 = ta.pivothigh(mfi, pivL3, pivR3), h33 = +1.1
PLCond3 = ta.pivotlow (mfi, pivL3, pivR3), l33 = -0.9

highestHighPoint3 = ta.highest(PHCond3 and mfi > 0 ? mfi : na, rangeUpper3)
lowestLowPoint3 = ta.lowest(PLCond3 and mfi < 0 ? mfi : na, rangeLower3)


// Divergence Detect:
osc3    = mfi 
plFound3 = na(ta.pivotlow(mfi, lbL3, lbR3)) ? false : true
phFound3 = na(ta.pivothigh(mfi, lbL3, lbR3)) ? false : true
_inRange3(cond3) =>
    bars3 = ta.barssince(cond3 == true)
    rangeLower3 <= bars3 and bars3 <= rangeUpper3


// Regular Bullish
// Osc: Higher Low
oscHL3 = osc[lbR3] > ta.valuewhen(plFound3, osc3[lbR3], 1) and _inRange3(plFound3[1]) and mfi != close
// Price: Lower Low
priceLL3 = low[lbR3] < ta.valuewhen(plFound3, low[lbR3], 1)
bullCond3 = plotBull3 and priceLL3 and oscHL3 and plFound3
plot(plFound3 ? osc[lbR3] : na, offset=-lbR, title='Mid Bullish Div', linewidth=1, color=bullCond3 ? color.rgb(0, 255, 8) : na)

// Regular Bearish
// Osc: Lower High
oscLH3 = osc3[lbR3] < ta.valuewhen(phFound3, osc3[lbR3], 1) and _inRange3(phFound3[1]) and mfi != close
// Price: Higher High
priceHH3 = high[lbR3] > ta.valuewhen(phFound3, high[lbR3], 1)
bearCond3 = plotBear3 and priceHH3 and oscLH3 and phFound3
plot(phFound3 ? osc3[lbR3] : na, offset=-lbR, title='Mid Bearish Div', linewidth=1, color=bearCond3 ? color.rgb(255, 0, 0) : na)



//------------------------------------------------------------------------------
// div detector 4 - Macro Div

// Inputs
groupdiv4       = '---- Macro Div Lookback ----'
pivR4           = 1
pivL4           = 21
lbR4            = 1
lbL4            = input.int (70,   ' '                                 , group = groupdiv4, inline = '2')
rangeUpper4     = 100
rangeLower4     = 6

plotBull4       = true
plotBear4       = true

//------------------------------------------------------------------------------

PHCond4 = ta.pivothigh(mfi, pivL4, pivR4), h44 = +1.1
PLCond4 = ta.pivotlow (mfi, pivL4, pivR4), l44 = -0.9

highestHighPoint4 = ta.highest(PHCond4 and mfi > 0 ? mfi : na, rangeUpper4)
lowestLowPoint4 = ta.lowest(PLCond4 and mfi < 0 ? mfi : na, rangeLower4)


// Divergence Detect:
osc4    = mfi 
plFound4 = na(ta.pivotlow(mfi, lbL4, lbR4)) ? false : true
phFound4 = na(ta.pivothigh(mfi, lbL4, lbR4)) ? false : true
_inRange4(cond4) =>
    bars4 = ta.barssince(cond4 == true)
    rangeLower4 <= bars4 and bars4 <= rangeUpper4


// Regular Bullish
// Osc: Higher Low
oscHL4 = osc[lbR4] > ta.valuewhen(plFound4, osc4[lbR4], 1) and _inRange4(plFound4[1]) and mfi != close
// Price: Lower Low
priceLL4 = low[lbR4] < ta.valuewhen(plFound4, low[lbR4], 1)
bullCond4 = plotBull4 and priceLL4 and oscHL4 and plFound4
plot(plFound4 ? osc[lbR4] : na, offset=-lbR, title='Macro Bullish Div', linewidth=1, color=bullCond4 ? color.rgb(0, 255, 8) : na)

// Regular Bearish
// Osc: Lower High
oscLH4 = osc4[lbR4] < ta.valuewhen(phFound4, osc4[lbR4], 1) and _inRange4(phFound4[1]) and mfi != close
// Price: Higher High
priceHH4 = high[lbR4] > ta.valuewhen(phFound4, high[lbR4], 1)
bearCond4 = plotBear4 and priceHH4 and oscLH4 and phFound4
plot(phFound4 ? osc4[lbR4] : na, offset=-lbR, title='Macro Bearish Div', linewidth=1, color=bearCond4 ? color.rgb(255, 0, 0) : na)

//

Bearishdivalert = bearCond or bearCond2 or bearCond3 or bearCond4
Bullishdivalert = bullCond or bullCond2 or bullCond3 or bullCond4

alertcondition(Bearishdivalert, title = "Bearish Divergence Alert", message = "Bearish Divergence Detected")
alertcondition(Bullishdivalert, title = "Bullish Divergence Alert", message = "Bullish Divergence Detected")

