Volume Zone Oscillator (VZO)
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Beardy_Fred

//@version=5
indicator('Beardy VZO', shorttitle='VZO', precision=0, overlay=false)

// INPUTS
VZO_length      = input.int(14, 'VZO Length', minval=2, group = 'VZO')
VZO_zone_lower  = input.int(40, 'Overbought/sold Lower Limit', minval=0, group = 'VZO')
VZO_zone_upper  = input.int(60, 'Overbought/sold Upper Limit', minval=0, group = 'VZO')
VZO_zone_chop   = input.int(15, 'Chop Zone', minval=0, group = 'VZO')
VZO_Intraday    = input.bool(true, 'Enable Plot Smoothing for Intraday', group = 'VZO Intraday Setting')
VZO_noise       = input.int(4, 'Noise Filter', minval=2, group = 'VZO Intraday Setting')

// VZO CALCULATIONS
//Detailed explanation of Volume Zone Oscillator (see pages 18-25 of Journal): https://ifta.org/public/files/journal/d_ifta_journal_09.pdf

VZO(length) =>
    Volume_Direction    = close > close[1] ? volume : -volume
    VZO_volume          = ta.ema(Volume_Direction, length)
    Total_volume        = ta.ema(volume, length)
    100 * VZO_volume / Total_volume
    
VZO = VZO(VZO_length)

if VZO_Intraday
    VZO := ta.ema(VZO, VZO_noise)

//ZONE COLORS
OB_Zone     = color.new(color.red, 75)
Chop_Zone   = color.new(color.yellow, 75)
OS_Zone     = color.new(color.green, 75)

//ZONES LEVELS
Red_1       = hline(VZO_zone_upper, linestyle=hline.style_dotted, color=OB_Zone, title = 'Overbought Upper Limit')
Red_2       = hline(VZO_zone_lower, linestyle=hline.style_dotted, color=OB_Zone, title = 'Overbought Lower Limit')
fill(Red_1, Red_2, color = OB_Zone, title = 'Overbought Zone')

Yell_1      = hline(VZO_zone_chop, linestyle=hline.style_dotted, color=Chop_Zone, title = 'Chop Zone Upper Limit')
Yell_2      = hline(-VZO_zone_chop, linestyle=hline.style_dotted, color=Chop_Zone, title = 'Chop Zone Lower Limit')
fill(Yell_1, Yell_2, color = Chop_Zone, title = 'Chop Zone')

Green_1     = hline(-VZO_zone_lower, linestyle=hline.style_dotted, color=OS_Zone, title = 'Oversold Lower Limit')
Green_2     = hline(-VZO_zone_upper, linestyle=hline.style_dotted, color=OS_Zone, title = 'Oversold Upper Limit')
fill(Green_1, Green_2, color = OS_Zone, title = 'Oversold Zone')

hline(0, linestyle=hline.style_dashed, color=color.new(color.white, 50), title = 'Zero Line')

// VZO PLOT
Plot_color  = VZO > VZO_zone_chop ? color.new(color.green, 0) : VZO < -VZO_zone_chop ? color.new(color.red, 0) : color.new(color.yellow, 0)
plot(VZO, color=Plot_color, style=plot.style_line, linewidth=1)

