Volume Divergence Indicator
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © cyatophilum

//@version=5
indicator("Volume Divergence Indicator",overlay= true)

// Inputs {
displayMode = input.string('Overlay', 'Choose overlay mode',options=['Overlay','Non Overlay'])
overlay = displayMode == 'Overlay'

groupDivergences = '📈 Divergences Signals 📉'
priceLookBack = input.int(20, 'Price and volume Lookback', group = groupDivergences)
bullSensitivity =   input.int(3,  'Bull Sensitivity',minval=1, group = groupDivergences) + 1
bearSensitivity =   input.int(4,  'Bear Sensitivity',minval=1, group = groupDivergences) + 1

groupSpikes = 'Volume Spike 💥 & Contraction Signals ⤵'
maLength =      input.int(20, 'Volume MA length', group = groupSpikes)
mult =          input.float(3,'Sensitivity of Spikes',        step=0.1, minval = 0.1, group = groupSpikes)
mult2 =          input.float(1,'Sensitivity of Contractions', step=0.1, minval = 0.1, group = groupSpikes)

groupTrend = 'Volume Trend'
trendSensitivity = input.int(5,'Trend sensitivity',minval = 1, group = groupTrend)


// }

// Algorithm {

// Bullish Divergence: generate an alert when prices are making lower lows but volume is making higher lows. This would suggest that the selling pressure is weakening, and a bullish reversal may be imminent.
priceLowerLows    = ta.lowest(low, priceLookBack) == ta.lowest(low, priceLookBack * bullSensitivity)
lowVol1 = ta.lowest(volume, priceLookBack)
lowVol2 = ta.lowest(volume, priceLookBack * bullSensitivity)
volumeHigherLows  = lowVol1 > lowVol2
bullishDivergence = priceLowerLows and volumeHigherLows and not (priceLowerLows and volumeHigherLows)[1]

// Bearish Divergence: generate an alert when prices are making higher highs but volume is making lower highs. This would suggest that the buying pressure is weakening, and a bearish reversal may be imminent.
priceHigherHighs  = ta.highest(high, priceLookBack) == ta.highest(high, priceLookBack * bearSensitivity)
highVol1 = ta.highest(volume, priceLookBack) 
highVol2 = ta.highest(volume, priceLookBack * bearSensitivity)
volumeLowerHighs  = highVol1 < highVol2
bearishDivergence = priceHigherHighs and volumeLowerHighs and not (priceHigherHighs and volumeLowerHighs)[1]

// Volume Spike: generate an alert when volume spikes above a certain threshold, such as two standard deviations above the moving average. 
// This would suggest that there is unusual buying or selling activity in the market, and traders may want to pay attention to the price movements that follow.
volMA = ta.sma(volume, maLength)
volDev = mult * ta.stdev(volume,maLength)
volDev2 = mult2 * ta.stdev(volume,maLength)
upperDevVol1 =  volMA + volDev
volumeSpike = ta.crossover(volume,upperDevVol1)

// Volume Contraction:  generate an alert when volume contracts to a certain level, such as two standard deviations below the moving average.
// This would suggest that there is little buying or selling activity in the market, and traders may want to be cautious until volume picks up again.
lowerDevVol1 =  volMA - volDev2
volumeContraction = ta.crossunder(volume,lowerDevVol1) and barstate.isconfirmed


// Volume Trend: an alert when volume trends above or below the moving average for a certain number of periods, such as five or ten.
// This would suggest that there is a sustained increase or decrease in buying or selling pressure, and traders may want to adjust their trading strategy accordingly.
increasingTrend = ta.barssince(volume < volMA) > trendSensitivity
decreasingTrend = ta.barssince(volume > volMA) > trendSensitivity

// }

// Rendering {
plotshape(bullishDivergence,'Bullish Divergence',shape.labelup,location.belowbar,color.lime,text='Bull', textcolor=#000000,size=size.normal, display=not(overlay) ? display.none : display.all)
plotshape(bearishDivergence,'Bearish Divergence',shape.labeldown,location.abovebar,color.red,text='Bear', textcolor=#FFFFFF,size=size.normal, display=not(overlay) ? display.none : display.all)

plotchar(volumeSpike,       'Volume Spike', '💥',       size=size.small, display=not(overlay) ? display.none : display.all)
plotchar(volumeContraction, 'Volume Contraction', '⤵',  size=size.small, display=not(overlay) ? display.none : display.all, color=color.aqua)

plotshape(increasingTrend and not increasingTrend[1],'Increasing Trend',shape.labelup,location.belowbar,  color.rgb(0,0,0,100),text='Strong Trend',textcolor= color.rgb(77, 160, 255),size=size.small, display=not(overlay) ? display.none : display.all)
plotshape(decreasingTrend and not decreasingTrend[1],'Decreasing Trend',shape.labeldown,location.abovebar,color.rgb(0,0,0,100),text='Weak Trend',textcolor=color.orange,size=size.small, display=not(overlay) ? display.none : display.all)

plot(volume,'Volume',color= bullishDivergence ? color.lime : bearishDivergence ? color.red : volumeSpike ? color.yellow : volumeContraction ? color.aqua : color.rgb(119, 119, 119, 50),style=plot.style_columns, display=overlay ? display.none : display.all, linewidth = 2)

pvolMA = plot(volMA, 'Volume MA',color=increasingTrend ? color.lime : decreasingTrend ? color.red : chart.fg_color, linewidth = 2, display=overlay ? display.none : display.all)

pdevVol1 = plot(upperDevVol1, 'stdevVol1',color.rgb(0, 230, 119, 50), display=overlay ? display.none : display.all,linewidth = 2)
pdevVol2 = plot(lowerDevVol1, 'stdevVol2',color.rgb(255, 82, 82, 50), display=overlay ? display.none : display.all,linewidth = 2)

fill(pvolMA,pdevVol1,color.rgb(0, 230, 119, 85), display=overlay ? display.none : display.all)
fill(pvolMA,pdevVol2,color.rgb(230, 0, 0, 85),   display=overlay ? display.none : display.all)
// }

// Alerts {
alertcondition(bullishDivergence,'Bullish Divergence')
alertcondition(bearishDivergence,'Bearish Divergence')
alertcondition(volumeSpike,      'Volume Spike')
alertcondition(volumeContraction,'Volume Contraction')
alertcondition(increasingTrend and not increasingTrend[1],'Increasing Trend')
alertcondition(decreasingTrend and not decreasingTrend[1],'Decreasing Trend')
//}