Volume Distribution Deviation
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © john_everist

//@version=5
indicator('Volume Distribution Deviation', overlay=true, max_bars_back = 3000)


volume_time_of_day(vol, look_back, ave_type)=>
    
    vol_array = array.new_float(look_back)
    int count = 1
    for i = 1 to 4999
        if hour[i] == hour and minute[i] == minute// and dayofweek !=  dayofweek.saturday and dayofweek != dayofweek.sunday
            array.set(vol_array, count, vol[i])
            count += 1
            if count == look_back
                break
    
    
    float average_vol = na
    if not timeframe.isintraday
        average_vol := ta.sma(vol, look_back)
    else if ave_type == "Mean Average"
        average_vol := array.sum(vol_array)/array.size(vol_array) 
    else
        average_vol := array.median(vol_array)

    average_vol




recalc = input.bool(false, title='Reload Indicator', tooltip = "Sometimes the indicator does not load. Tick/untick this to force the indicator to reload")
crash  = recalc?1:0


var core = "Core Inputs"
string currency = input.string("Automatic", title='Baseline Currency', options=['Automatic', 'AUD', 'CAD', 'CHF', 'EUR', 'GBP', 'JPY', 'NZD', 'USD'], group = core, tooltip = "Which Currency do you want investigate the deviation from typical percentage of market transactions at that time of day?\n\nIf you set to 'Automatic' the indicator will automatically chose the currency based on the currency you cross with gold.\n\nOptions are:\nOANDA:XAUNZD, OANDA:XAUAUD, OANDA:XAUJPY, OANDA:XAUCHF, OANDA:XAUEUR, OANDA:XAUGBP, OANDA:XAUCAD, OANDA:XAUUSD")


look_back = input.int(10, title = "Number of Days Bcck to Average", minval=1, maxval=20, step=1, group = core, tooltip = "How many days back do you want to average?\n\nWhen using an intraday timeframe, the indicator compares market volume at that time of day to prevous days at the same time. This migates the impact of volume fluctuations that naturally occur throughout the day (New York open verses the deadtime between New York and Asia for example")
ave_type = input.string("Median Average", title = "Method of Average Calculation",  options = ["Median Average", "Mean Average"], group = core, tooltip = "How should the volume collected over the look back period be averaged?\n\nA median average will mitigate the impact of 'one off spikes'")

sma_length = input.int(20, title = "SMA Length", minval = 2, step = 1, group = core, tooltip = "The Simple Moving Average of the current volume across the entire currency group")
tolerance_current = input.int(10, title = 'Tolerance for current volume to be highlighted', group = core, tooltip = "When should the CURRENT volume deviation be highlighted and when should it be dimmed?\n\nIs a volume that deviates 10% from its typical for that time of day mean much?")
tolerance_average = input.int(5, title = 'Tolerance for average volume to be highlighted', group = core, tooltip = "When should the AVERAGE volume deviation be highlighted and when should it be dimmed?\n\nIs a volume that deviates 10% from its typical for that time of day mean much?")
show_value = input.bool(true, title = 'Show Current Market Percent', group = core)
show_ave = input.bool(false, title = 'Show Current Market Percent SMA', group = core)
fill_ave = input.bool(true, title = 'Fill SMA', group = core)


var currencies = "Currencies to Include"
bool show_NZD = input.bool(true, title = 'include NZD', group = currencies)
bool show_AUD = input.bool(true, title = 'include AUD', group = currencies)
bool show_JPY = input.bool(true, title = 'include JPY', group = currencies)
bool show_CHF = input.bool(true, title = 'include CHF', group = currencies)
bool show_EUR = input.bool(true, title = 'include EUR', group = currencies)
bool show_GBP = input.bool(true, title = 'include GBP', group = currencies)
bool show_CAD = input.bool(true, title = 'include CAD', group = currencies)
bool show_USD = input.bool(true, title = 'include USD', group = currencies)





var colours = "Currency Colours"
color col_NZD = input.color(color.teal, title = 'NZD colour', group = colours)
color col_AUD = input.color(color.red, title = 'AUD colour', group = colours)
color col_JPY = input.color(color.purple, title = 'JPY colour', group = colours)
color col_CHF = input.color(color.yellow, title = 'CHF colour', group = colours)
color col_EUR = input.color(color.lime, title = 'EUR colour', group = colours)
color col_GBP = input.color(color.aqua, title = 'GBP colour', group = colours)
color col_CAD = input.color(color.orange, title = 'CAD colour', group = colours)
color col_USD = input.color(color.white, title = 'USD colour', group = colours)
transp_typical = input.int(50, title = "Current Value Transparency within (Specified Percent)", group = colours)

col_ave_same = input.bool(false, title = 'SMA colour same as Current Percent', group = colours, tooltip = "Overrides all other colour options for SMA colour")



color col_ave_top = input.color(color.new(#00FF00, 0), title = "SMA Color > (Specified Percent)", group = colours)
color col_ave_bottom = input.color(color.new(#FF0000, 0), title = "SMA Color < (Specified Percent)", group = colours)
color col_ave_typical = input.color(color.new(color.gray, 0), title = "SMA Color within (Specified Percent)", group = colours)

sma_transp = input.int(50, title = "SMA transparency", group = colours)

sma_transp_fill = input.int(50, title = "SMA fill transparency", group = colours)



var p_style = "Plot Style"
val_width = input.int(1, title = "Value Width", minval = 1, group = p_style)
p_style_temp = input.string("columns", title = "Value Plot Style",  options = ["area", "areabr", "circles", "columns", "cross", "histogram", "line", "linebr", "stepline"], group = p_style)
plot_style_value = p_style_temp=="area"?plot.style_area:p_style_temp=="areabr"? plot.style_areabr:p_style_temp=="circles" ?plot.style_circles:p_style_temp=="columns"? plot.style_columns:p_style_temp=="cross"? plot.style_cross:p_style_temp=="histogram"? plot.style_histogram:p_style_temp=="line" ?plot.style_line:p_style_temp=="linebr"? plot.style_linebr:p_style_temp=="stepline"? plot.style_stepline :na



sma_width = input.int(3, title = "SMA Width", minval = 1, group = p_style)
p_style_ave_temp = input.string("stepline", title = "SMA Plot Style",  options = ["area", "areabr", "circles", "columns", "cross", "histogram", "line", "linebr", "stepline"], group = p_style)
plot_style_ave = p_style_ave_temp=="area"?plot.style_area:p_style_ave_temp=="areabr"? plot.style_areabr:p_style_ave_temp=="circles" ?plot.style_circles:p_style_ave_temp=="columns"? plot.style_columns:p_style_ave_temp=="cross"? plot.style_cross:p_style_ave_temp=="histogram"? plot.style_histogram:p_style_ave_temp=="line" ?plot.style_line:p_style_ave_temp=="linebr"? plot.style_linebr:p_style_ave_temp=="stepline"? plot.style_stepline :na
















if currency == 'Automatic'
    if syminfo.ticker == 'XAUAUD'
        currency := 'AUD'
        currency
    else if syminfo.ticker == 'XAUCAD'
        currency := 'CAD'
        currency
    else if syminfo.ticker == 'XAUCHF'
        currency := 'CHF'
        currency
    else if syminfo.ticker == 'XAUEUR'
        currency := 'EUR'
        currency
    else if syminfo.ticker == 'XAUGBP'
        currency := 'GBP'
        currency
    else if syminfo.ticker == 'XAUJPY'
        currency := 'JPY'
        currency
    else if syminfo.ticker == 'XAUNZD'
        currency := 'NZD'
        currency
    else if syminfo.ticker == 'XAUUSD'
        currency := 'USD'
        currency
    else
        currency := na
        currency





var labels = "Label"
show_labs = input(title='Show Currency Label', defval=true, group = labels)
lab_size_temp = input.string(title='Label Size', options=['tiny', 'small', 'normal', 'large', 'huge'], defval='small', group = labels)
lab_size = lab_size_temp == 'tiny' ? size.tiny : lab_size_temp == 'small' ? size.small : lab_size_temp == 'normal' ? size.normal : lab_size_temp == 'large' ? size.large : lab_size_temp == 'huge' ? size.huge : size.normal

var sess = "Check Line"
show_line = input.bool(true, title = "Show Vertical Line", group = sess, tooltip = "Add a vertical line at the same time everyday")
line_col = input.color(color.new(color.white, 90), title = "Line Colour", group = sess)
line_h = input.int(7, title='Line hour', minval = 0, maxval = 23, group = sess)
line_m = input.int(0, title='Line minute', minval=0, maxval = 59, group = sess)
time_zone_dif = input.int(-6, title='Time zone difference to exchange', options=[-13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], group = sess, tooltip = "You're proberly in a different time zone to your exchange so use this setting to compensate")


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




AUDNZD_volume = request.security('FX:AUDNZD', "", volume)
NZDJPY_volume = request.security('FX:NZDJPY', "", volume)
NZDCHF_volume = request.security('FX:NZDCHF', "", volume)
EURNZD_volume = request.security('FX:EURNZD', "", volume)
GBPNZD_volume = request.security('FX:GBPNZD', "", volume)
NZDCAD_volume = request.security('FX:NZDCAD', "", volume)
NZDUSD_volume = request.security('FX:NZDUSD', "", volume)
AUDJPY_volume = request.security('FX:AUDJPY', "", volume)
AUDCHF_volume = request.security('FX:AUDCHF', "", volume)
EURAUD_volume = request.security('FX:EURAUD', "", volume)
GBPAUD_volume = request.security('FX:GBPAUD', "", volume)
AUDCAD_volume = request.security('FX:AUDCAD', "", volume)
AUDUSD_volume = request.security('FX:AUDUSD', "", volume)
CHFJPY_volume = request.security('FX:CHFJPY', "", volume)
EURJPY_volume = request.security('FX:EURJPY', "", volume)
GBPJPY_volume = request.security('FX:GBPJPY', "", volume)
CADJPY_volume = request.security('FX:CADJPY', "", volume)
USDJPY_volume = request.security('FX:USDJPY', "", volume)
EURCHF_volume = request.security('FX:EURCHF', "", volume)
GBPCHF_volume = request.security('FX:GBPCHF', "", volume)
CADCHF_volume = request.security('FX:CADCHF', "", volume)
USDCHF_volume = request.security('FX:USDCHF', "", volume)
EURGBP_volume = request.security('FX:EURGBP', "", volume)
EURCAD_volume = request.security('FX:EURCAD', "", volume)
EURUSD_volume = request.security('FX:EURUSD', "", volume)
GBPCAD_volume = request.security('FX:GBPCAD', "", volume)
GBPUSD_volume = request.security('FX:GBPUSD', "", volume)
USDCAD_volume = request.security('FX:USDCAD', "", volume)

NZD_volume = show_NZD?  array.sum(array.from(AUDNZD_volume, NZDJPY_volume, NZDCHF_volume, EURNZD_volume, GBPNZD_volume, NZDCAD_volume, NZDUSD_volume)) : na
AUD_volume = show_AUD?  array.sum(array.from(AUDNZD_volume, AUDJPY_volume, AUDCHF_volume, EURAUD_volume, GBPAUD_volume, AUDCAD_volume, AUDUSD_volume)) : na
JPY_volume = show_JPY?  array.sum(array.from(NZDJPY_volume, AUDJPY_volume, CHFJPY_volume, EURJPY_volume, GBPJPY_volume, CADJPY_volume, USDJPY_volume)) : na
CHF_volume = show_CHF?  array.sum(array.from(NZDCHF_volume, AUDCHF_volume, CHFJPY_volume, EURCHF_volume, GBPCHF_volume, CADCHF_volume, USDCHF_volume)) : na
EUR_volume = show_EUR?  array.sum(array.from(EURNZD_volume, EURAUD_volume, EURJPY_volume, EURCHF_volume, EURGBP_volume, EURCAD_volume, EURUSD_volume)) : na
GBP_volume = show_GBP?  array.sum(array.from(GBPNZD_volume, GBPAUD_volume, GBPJPY_volume, GBPCHF_volume, EURGBP_volume, GBPCAD_volume, GBPUSD_volume)) : na
CAD_volume = show_CAD?  array.sum(array.from(NZDCAD_volume, AUDCAD_volume, CADJPY_volume, CADCHF_volume, EURCAD_volume, GBPCAD_volume, USDCAD_volume)) : na
USD_volume = show_USD?  array.sum(array.from(NZDUSD_volume, AUDUSD_volume, USDJPY_volume, USDCHF_volume, EURUSD_volume, GBPUSD_volume, USDCAD_volume)) : na


total_vol = array.new_float()
if show_NZD 
    array.push(total_vol, NZD_volume)
if show_AUD 
    array.push(total_vol, AUD_volume)
if show_JPY 
    array.push(total_vol, JPY_volume)
if show_CHF 
    array.push(total_vol, CHF_volume)
if show_EUR 
    array.push(total_vol, EUR_volume)
if show_GBP 
    array.push(total_vol, GBP_volume)
if show_CAD 
    array.push(total_vol, CAD_volume)
if show_USD 
    array.push(total_vol, USD_volume)

total_volume = array.sum(total_vol)


 




color col_currency = na
float currency_percent = na
string currency_text = na
string space = "     "

if currency == 'NZD'
    currency_percent := (NZD_volume / total_volume) * 100
    col_currency := col_NZD
    currency_text := space+'NZD'
else if currency == 'AUD'
    currency_percent := (AUD_volume / total_volume) * 100
    col_currency := col_AUD
    currency_text := space+'AUD'
else if currency == 'JPY'
    currency_percent :=(JPY_volume / total_volume) * 100
    col_currency := col_JPY
    currency_text := space+'JPY'
else if currency == 'CHF'
    currency_percent := (CHF_volume / total_volume) * 100
    col_currency := col_CHF
    currency_text := space+'CHF'
else if currency == 'EUR'
    currency_percent := (EUR_volume / total_volume) * 100
    col_currency := col_EUR
    currency_text := space+'EUR'
else if currency == 'GBP'
    currency_percent := (GBP_volume / total_volume) * 100
    col_currency := col_GBP
    currency_text := space+'GBP'
else if currency == 'CAD'
    currency_percent := (CAD_volume / total_volume) * 100
    col_currency := col_CAD
    currency_text := space+'CAD'
else if currency == 'USD'
    currency_percent := (USD_volume / total_volume) * 100
    col_currency := col_USD
    currency_text := space+'USD'
    


    
    

float currency_ave = na

if timeframe.isintraday
    currency_ave := volume_time_of_day(currency_percent, look_back, ave_type)
else
    currency_ave := ta.sma(currency_percent, sma_length)


currency_percent := (currency_percent / currency_ave) * 100 - 100 





currency_deviation_ave = ta.sma(currency_percent, sma_length)







color col_ave = na
color col_sma_fill = na
if col_ave_same
    col_ave := color.new(col_currency, sma_transp)
    col_sma_fill := color.new(col_currency, sma_transp_fill)

else if currency_deviation_ave>tolerance_average
    col_ave := color.new(col_ave_top, sma_transp)
    col_sma_fill := color.new(col_ave_top, sma_transp_fill)
    
else if currency_deviation_ave<-tolerance_average
    col_ave := color.new(col_ave_bottom, sma_transp)
    col_sma_fill := color.new(col_ave_bottom, sma_transp_fill)
    
else
    col_ave := color.new(col_ave_typical, sma_transp)
    col_sma_fill := color.new(col_ave_typical, sma_transp_fill)





color middle_col = color.new(color.white,100)
ave_middle = plot(0, color = middle_col)
ave_extreme = plot(currency_deviation_ave, color = middle_col)


fill_col_percent = col_currency
fill(ave_middle, ave_extreme, color = fill_ave?col_sma_fill:na)






hline(50, color = middle_col)
hline(-50, color = middle_col)


if currency_percent < tolerance_current and currency_percent > -tolerance_current
    col_currency := color.new(col_currency, transp_typical)


plot(currency_percent, title = "Currency Percent", linewidth = val_width, color = show_value?col_currency:na, style = plot_style_value)



plot(currency_deviation_ave, title = "Average Currency Deviation", linewidth = sma_width, color = show_ave?col_ave:na, style = plot_style_ave)





if show_labs
    lab_style = label.style_label_left
    color invisible = color.new(color.gray, 100)


    
    lab = label.new(bar_index[0], 0, text=currency_text, textcolor=col_currency, color=invisible, style=lab_style, size=lab_size)
    label.delete(lab[1])



start = line_h + time_zone_dif
if start < 0
    start := 24 - math.abs(start)



finish = line_h + time_zone_dif + 1
if finish > 24
    finish := 0


start_h_str = start < 10 ? '0' + str.tostring(start) : str.tostring(start)
finish_h_str = finish < 10 ? '0' + str.tostring(finish) : str.tostring(finish)
start_m_str = line_m < 10 ? '0' + str.tostring(line_m) : str.tostring(line_m)
finish_m_str = line_m < 10 ? '0' + str.tostring(line_m) : str.tostring(line_m)


string session_str = start_h_str + start_m_str + '-' + finish_h_str + finish_m_str

session = time("", session_str)



bgcolor(show_line and not session and session[1] ? line_col:na)







