Price Clouds Oscillator (PCO)
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © peacefulLizard50262
//@version=5
indicator("PCO","PCO", false, precision=3, explicit_plot_zorder = true)
//FUNCTIONS //{
//Derivative
//© tbiktag
diff(src, N) => //{
    float derivative = 0.0
    if N == 2
        derivative := (src - src[2]) / 2
        derivative
    else if N == 3
        derivative := (src + src[1] - src[2] - src[3]) / 4
        derivative
    else if N == 4
        derivative := (src + 2 * src[1] - 2 * src[3] - src[4]) / 8
        derivative
    else if N == 5
        derivative := (src + 3 * src[1] + 2 * src[2] - 2 * src[3] - 3 * src[4] - src[5]) / 16
        derivative
//}
//EMA Function (Fk)
ema(src, len) => //{
    alpha = 2 / (len + 1)
    sum   = 0.0
    sum  := na(sum[1]) ? src : alpha * src + (1 - alpha) * nz(sum[1])
//}
//Tripple EMA
tma(src, int len) => //{
    //src is an input.source
    //len is an input.int
    ema1 = ema(src, len)
    ema2 = ema(ema1, len)
    ema3 = ema(ema2, len)
    tma  = 3 * (ema1 - ema2) + ema3
//}
//Normalization Function
norm(src, min, max, bool pass = true) => //{
    //src is an input.source
    //min is an input.float
    //max is an input.float
    //offset is an input.float
    //scale is an input.int
    //pass bypasses the normalization function
    num  = src - min
    den  = max - min
    norm = num / den
    out  = pass == true ? (norm - 0.5) * 2 : src
//}
//Full Standard Deviation Function
stdev(src, avg, float dev, int len, bool pol) => //{
    //src is an input.source
        //source of the avg
    //avg is the global series average
    //dev is an input.float
    //len is an input.int
        //use the global length
    //pol is an input.bool
        //this changes the polarity
        //true is positive
    stdev = dev * ta.stdev(src, len)
    out   = pol == true ? avg + stdev : avg - stdev
//}
//Band Lines Function
band_line(src, int len, int globallen, float dev, float globaldev, string avginput, string globalinput, bool pol, bool pos, bool preset, string presetinput, bool global, bool smooth, int smoothlen) => //{
    //src is an input.source
        //should be high for the top band for instance
    //len is an input.int
        //band length
    //globallen is an input.int
        //input for the global lenght
    //dev is an input.float
        //the stdev for the line
    //globaldev is an input.float
        //this is the input for the global dev
    //avginput is an input.string
        //"SMA", "EMA", "TMA"
    //globalinput is an input.string
        //"SMA", "EMA", "TMA"
    //pol is an inputbool
        //polarity of the stdev
        //True is Positive
        //False is Negitive
    //pos is an input.bool
        //set this flag to determine its position in the band
        //true is top while false is bottom
    //preset is an input.bool
        //if true it will use the preset values
    //presetinput is an input.string
        //"Fast", "Slow", "Super Slow"
    //global is an input.bool
        //toggle globals
    //smooth is an input.bool
        //turn smoothing on and off
    //smoothlen is an input.int
        //smoothing length
    pstlen  = switch presetinput
        "Fast" => int(10)
        "Slow" => int(48)
        "Super Slow" => int(200)
    pstdev  = switch presetinput
        "Fast" => pos == true ? float(0.75) : float(0)
        "Slow" => pos == true ? float(2) : float(1)
        "Super Slow" => pos == true ? float(2) : float(1)
    pstavg  = switch presetinput
        "Fast" => string("SMA")
        "Slow" => string("SMA")
        "Super Slow" => string("SMA")
    intlen  = preset == true ? pstlen : global == true ? globallen : len
    intdev  = preset == true ? pstdev : global == true ? globaldev : dev
    average = switch global == true ? globalinput : preset == true ? pstavg : avginput
        "SMA" => ta.sma(src, intlen)
        "EMA" => ema(src, intlen)
        "TMA" => tma(src, intlen)      
    //stdev(src, avg, float dev, int len, bool pol)
    out       = stdev(src, average, intdev, intlen, pol)
    outsmooth = smooth == true ? ta.sma(out, smoothlen) : out
//}
//Signal Lines Function
signal(src, len, preset, presetinput, spd, smooth, smoothlen) => //{
    //src is an input.source
        //float
        //should be hl2
    //len is an input.int
        //length
    //preset is an input.bool
        //if true it will use the preset values
    //presetinput is an input.string
        //"Fast", "Slow", "Super Slow"
    //spd is an input.bool
        //TRUE is FAST line FALSE is SLOW line
    //smooth is an input.bool
        //turn smoothing on and off
    //smoothlen is an input.int
        //smoothing length
    pstlen = switch presetinput
        "Fast" => spd == true ? int(7) : int(14)
        "Slow" => spd == true ? int(14) : int(26)
        "Super Slow" => spd == true ? int(50) : int(100)
    out = tma(src, preset == true ? pstlen : len)
    outsmooth = smooth == true ? ta.sma(out, smoothlen) : out
//}
//Band Width Function
width(upper, lower, top, bot) => //{
    //upper is the series for the top of the band
    //lower is the series for the bottom of the band
    //avg is the mean
    dev = upper - lower
    hl  = top - bot
    out = math.avg(dev, hl) 
//}
//}
//CONSTANTS //{
//color

//}
//INPUTS //{
//presets//{
flag_preset       = input.bool(true, "Enable Presets", "This enables the presets found in the preset dropdown.", group = 'Presets', inline = "set")
preset_string     = input.string("Slow", "                   ", ["Fast", "Slow", "Super Slow"], "Select a Preset", group = "Presets", inline = "set")//}
//normalize //{
flag_normalize    = input.bool(false, "Normalize", "Enable Normalization", group = "Features")//}
flag_candle       = input.bool(false, "Candle View", group = "Features")
flag_can_col      = input.bool(false, "Candle Color", "When this is enabled it will color the candles on ma cross. When it is dissabled it will color on open close.", group = "Features")
//cross color
cross_enable      = input.bool(false, "Color Cross", "Enable this to highlite MACD crosses.", "cross", "Features") //////////////////////////////////////
cross_up          = input.color(color.new(color.blue , 50), "", inline = "cross", group = "Features")
cross_down        = input.color(color.new(color.orange , 50), "", inline = "cross", group = "Features")
cross_high        = input.color(color.new(color.green , 80), "", inline = "cross", group = "Features")
cross_low         = input.color(color.new(color.red , 80), "", inline = "cross", group = "Features")
//width //{
width_enable      = input.bool(false, "Bandwidth ", "Enable this when normalizing to see bandwidth", group = "Features", inline = "width")
width_low_color   = input.color(color.new(#311b92, 100), "", group = "Features", inline = "width")
width_high_color  = input.color(color.new(#311b92, 0), "", group = "Features", inline = "width")
width_len         = input.int(500, "", tooltip = "Bandwidth Normalization Lookback Period", group = "Features", inline = "width")
//}
//smoothing //{
flag_smoothing    = input.bool(false, "Smoothing", "Toggle Signal Smoothing", group = "Features", inline = "smoothing")
signal_smoothing  = input.int(3, "                         ", 1, 10, 1, "Set the level of smoothing", group = "Features", inline = "smoothing")//}
//histogram //{
flag_histogram    = input.bool(true, "", "Enable Histogram.", group = "Features", inline = "hist")
histogram_diff    = input.bool(false, "Delta MACD", "Change the histogram color to the delta.", group = "Features")////////////////////
delta_back        = input.int(20, "Delta Lookback", 1, 3000, group = "Features")
histogram_input   = input.string("MACD", "Histogram Toggle               ", ["MACD","Derivative"], group = "Features", inline = "hist")
derivative_input  = input.string("Fast", "Derivative      ", ["Fast","Slow"], group = "Features", inline = "derivative")
N                 = input.int(title='', tooltip = "Select the input for the Derivative. Bandwidth from 2 - 5", defval=4, minval=2, maxval=5, group = "Features", inline = "derivative")//}
//global //{
flag_global       = input.bool(true, "Global Control Switch", "Toggle Global Control", group = "Global Controls")
global_avg_input  = input.string("SMA", "Global MA Type", ["SMA","EMA", "TMA"], group = "Global Controls")
global_len        = input.int(10, "Global Band Length", 1, 9999, 1, tooltip = "Set the Global Band Lenth.", group = "Global Controls")
global_dev_top    = input.float(0.75, "Global Band Stdev Top", -10, 10, 0.05, "Set the Global Band Stdev.", group = "Global Controls")
global_dev_bot    = input.float(0, "Global Band Stdev Mid", -10, 10, 0.05, "Set the Global Mid Band Stdev.", group = "Global Controls") //}
//signals//{
signal_fast_len   = input.int(7, "Signal Fast Line Length", 1, 9999, 1, "Set the period of the moving average associated with the Signal Fast Line.", group = "Signal Lines")
signal_slow_len   = input.int(14, "Signal Slow Line Length", 1, 9999, 1, "Set the period of the moving average associated with the Signal Slow Line Length.", group = "Signal Lines") //}
//band
//top of the high band//{
band_high_top_avg_input = input.string("SMA", "Top of High Band MA Type", ["SMA","EMA","TMA"], "Select the Moving Average type", group = "Top High Band" )
band_high_top_len = input.int(10, "Top of High Band Length", 1, 9999, 1, "Top of High Band MA Length", group = "Top High Band")
band_high_top_dev = input.float(0.75, "Top of the High Band Stdev", -10, 10, 0.05, "Set the Top of the High Band Standard Deviation", group = "Top High Band") //}
//mid of the high band//{
band_high_bot_avg_input = input.string("SMA", "Bottom of High Band MA Type", ["SMA","EMA","TMA"], "Select the Moving Average type", group = "Bottom High Band" )
band_high_bot_len = input.int(10, "Bottom of High Band Length", 1, 9999, 1, "Set the Bottom of High Band MA Length", group = "Bottom High Band")
band_high_bot_dev = input.float(0, "Bottom of the High Band Stdev", -10, 10, 0.05, "Set the Bottom of the High Band Standard Deviation", group = "Bottom High Band") //}
//mid of low band//{
band_low_top_avg_input = input.string("SMA", "Top of Low Band MA Type", ["SMA","EMA","TMA"], "Select the Moving Average type", group = "Top Low Band" )
band_low_top_len  = input.int(10, "Top of Low Band Length", 1, 9999, 1, "Top of Low Band MA Length", group = "Top Low Band")
band_low_top_dev  = input.float(0.75, "Top of the Low Band Stdev", -10, 10, 0.05, "Set the Top of the Low Band Standard Deviation", group = "Top Low Band") //}
//bottom of the low band //{
band_low_bot_avg_input = input.string("SMA", "Bottom of Low Band MA Type", ["SMA","EMA","TMA"], "Select the Moving Average type", group = "Bottom Low Band" )
band_low_bot_len  = input.int(10, "Bottom of Low Band Length", 1, 9999, 1, "Set the Bottom of Low Band MA Length", group = "Bottom Low Band")
band_low_bot_dev  = input.float(0, "Bottom of the Low Band Stdev", -10, 10, 0.05, "Set the Bottom of the Low Band Standard Deviation", group = "Bottom Low Band") //}

colour_fast = input.color(color.new(color.blue, 0), "Signal Fast Line Color", group = "Color")
colour_slow = input.color(color.new(color.orange, 0), "Signal Slow Line Color", group = "Color")

colour_band_top = input.color(color.new(color.green, 50), "High Band Color", group = "Color")
colour_band_mid_top = input.color(color.new(color.green, 100), "High Mid Band Color", group = "Color")
colour_cloud_top = input.color(color.new(color.green, 80), "High Cloud Color", group = "Color")

colour_band_bot = input.color(color.new(color.red, 50), "Low Band Color", group = "Color")
colour_band_mid_bot = input.color(color.new(color.red, 100), "Low Mid Band Color", group = "Color")
colour_cloud_bot = input.color(color.new(color.red, 80), "Low Cloud Color", group = "Color")

colour_center = input.color(color.new(color.gray, 100), "Center Line Color", group = "Color")

colour_candle_up = input.color(color.new(#26a69a, 8), "Candle Bullish Color", group = "Color")
colour_candle_down = input.color(color.new(#ef5350, 8), "Candle Bearish Color", group = "Color")

col_grow_above = input.color(color.new(#26A69A, 50), "MACD Grow Above Color", group = "Color")
col_fall_above = input.color(color.new(#B2DFDB, 50), "MACD Fall Above Color", group = "Color")
col_grow_below = input.color(color.new(#FFCDD2, 50), "MACD Grow Below Color", group = "Color")
col_fall_below = input.color(color.new(#FF5252, 50), "MACD Fall Below Color", group = "Color" )//}


//MAIN //{
//signals raw //{
//signal(_src, _len, _preset, _preset_input, _spd, _smooth, _smooth_len)
raw_signal_fast = signal(hl2, signal_fast_len, flag_preset, preset_string, true,  flag_smoothing, signal_smoothing)
raw_signal_slow = signal(hl2, signal_slow_len, flag_preset, preset_string, false, flag_smoothing, signal_smoothing) //}

//bands raw //{
//band_line(_src, _len, _global_len, _dev, _global_dev, _avg_input, _global_input, _pol, _pos, _preset, _preset_input, _global, _smooth, _smooth_len)
raw_band_high_top = band_line(high, band_high_top_len, global_len, band_high_top_dev, global_dev_top, band_high_top_avg_input, global_avg_input,
 true,  true,  flag_preset, preset_string, flag_global, flag_smoothing, signal_smoothing)
raw_band_high_bot = band_line(high, band_high_bot_len, global_len, band_high_bot_dev, global_dev_bot, band_high_bot_avg_input, global_avg_input,
 true,  false, flag_preset, preset_string, flag_global, flag_smoothing, signal_smoothing)
raw_band_low_top  = band_line(low,  band_low_top_len,  global_len, band_low_top_dev,  global_dev_top, band_low_top_avg_input,  global_avg_input,
 false, true, flag_preset, preset_string, flag_global, flag_smoothing, signal_smoothing)
raw_band_low_bot  = band_line(low,  band_low_bot_len,  global_len, band_low_bot_dev,  global_dev_bot, band_low_bot_avg_input,  global_avg_input,
 false, false,  flag_preset, preset_string, flag_global, flag_smoothing, signal_smoothing) //}
//mean calculation //{
mean = math.avg(raw_band_high_bot, raw_band_high_top, raw_band_low_bot, raw_band_low_top)  //}
//signals centered //{
cen_signal_fast = raw_signal_fast - mean
cen_signal_slow = raw_signal_slow - mean


//}
//bands centered //{
cen_band_high_top = raw_band_high_top - mean
cen_band_high_bot = raw_band_high_bot - mean
cen_band_low_top  = raw_band_low_top - mean
cen_band_low_bot  = raw_band_low_bot - mean

open_fast = norm(signal(open , signal_fast_len, flag_preset, preset_string, true,  flag_smoothing, signal_smoothing) - mean, cen_band_low_top, cen_band_high_top, flag_normalize)
high_fast = norm(signal(high , signal_fast_len, flag_preset, preset_string, true,  flag_smoothing, signal_smoothing) - mean, cen_band_low_top, cen_band_high_top, flag_normalize)
low_fast = norm(signal(low , signal_fast_len, flag_preset, preset_string, true,  flag_smoothing, signal_smoothing) - mean, cen_band_low_top, cen_band_high_top, flag_normalize)
close_fast = norm(signal(close , signal_fast_len, flag_preset, preset_string, true,  flag_smoothing, signal_smoothing) - mean, cen_band_low_top, cen_band_high_top, flag_normalize)

//}
//normalized signal //{
//norm(_src, _min, _max, _offset, _scale, _pass)
Signal_Fast = norm(cen_signal_fast, cen_band_low_top, cen_band_high_top, flag_normalize)
Signal_Slow = norm(cen_signal_slow, cen_band_low_top, cen_band_high_top, flag_normalize) 
//}
//darivative input source //{
derivative_src = derivative_input == "Fast" ? Signal_Fast : Signal_Slow //}
//normalized bands //{
Band_High_Top = norm(cen_band_high_top, cen_band_low_top, cen_band_high_top, flag_normalize)
Band_High_Bot = norm(cen_band_high_bot, cen_band_low_top, cen_band_high_top, flag_normalize)
Band_Low_Top  = norm(cen_band_low_top, cen_band_low_top, cen_band_high_top, flag_normalize)
Band_Low_Bot  = norm(cen_band_low_bot, cen_band_low_top, cen_band_high_top, flag_normalize) //}
//MACD //{
MACD       = flag_histogram == true ? Signal_Fast - Signal_Slow : na
macd_color = (MACD>=0 ? (MACD[1] < MACD ? col_grow_above : col_fall_above) : (MACD[1] < MACD ? col_grow_below : col_fall_below)) //}
//derivitive //{
Derivative       = flag_histogram == true ? diff(derivative_src, N) : na
derivative_color = (Derivative>=0 ? (Derivative[1] < Derivative ? col_grow_above : col_fall_above) : (Derivative[1] < Derivative ? col_grow_below : col_fall_below)) //}
//Histogram //{
histogram_color = histogram_input == "MACD" ? macd_color : derivative_color
Histogram       = histogram_input == "MACD" ? MACD : Derivative //}
//Band Width //{
//TODO: Pack into function 
width_dev  = width(cen_band_high_top, cen_band_low_top, cen_band_high_bot, cen_band_low_bot)
width_high = ta.highest(width_dev, width_len)
width_low  = ta.lowest(width_dev, width_len)
width_norm = (norm(width_dev, width_low, width_high) / 2) + 0.5
wide = width_enable == true ? color.from_gradient(width_norm, 0, 1, width_low_color, width_high_color) : na

up   = ta.crossover(Signal_Fast, Signal_Slow) ////////////////////////////////
down = ta.crossunder(Signal_Fast, Signal_Slow)

high_out = ta.cross(Signal_Fast, Band_High_Top)
low_out  = ta.cross(Signal_Fast, Band_Low_Top)


color cross   = na
color cross_2 = na
cross_2 := not low_out and not high_out ? na : high_out ? cross_high : low_out ? cross_low : na
cross := not up and not down ? na : up ? cross_up : down ? cross_down : na

Histogram_Delta = ((Histogram - Histogram[2])/2 - ta.lowest((Histogram - Histogram[2])/2, delta_back)) / (ta.highest((Histogram - Histogram[2])/2, delta_back) - ta.lowest((Histogram - Histogram[2])/2, delta_back))
delta_col     = color.from_gradient(Histogram_Delta, 0, 1, col_fall_below, col_grow_above)

//}
//}
//PLOT and FIll //{
//high top
Plot_Band_High_Top = plot(Band_High_Top, "Top of High Band", colour_band_top)
//high mid
Plot_Band_High_Bot = plot(Band_High_Bot, "Bottom of High Band", colour_band_mid_top)
//low mid
Plot_Band_Low_Top  = plot(Band_Low_Top, "Top of Low Band", colour_band_bot)
Plot_Band_Low_Bot  = plot(Band_Low_Bot, "Bottom of Low Band", colour_band_mid_bot)
//top
fill(Plot_Band_High_Top, Plot_Band_High_Bot, colour_cloud_top, "High Cloud")
//bot
fill(Plot_Band_Low_Top, Plot_Band_Low_Bot, colour_cloud_bot, "Low Cloud")
//width
fill(Plot_Band_High_Bot, Plot_Band_Low_Bot, wide)
//histogram
plot(Histogram, title="Histogram", style = plot.style_columns, color = histogram_diff ? delta_col : histogram_color)
//band lines
//center line
Plot_center = plot(0, "Center Line", colour_center, style=plot.style_line)
//fast line
Plot_Fast   = plot(flag_candle ? na : Signal_Fast, "Signal Fast Line", colour_fast)
//slow line
Plot_Slow   = plot(flag_candle ? na : Signal_Slow, "Signal Slow Line", colour_slow)
//}
candle_color = flag_candle ? not flag_can_col ?  open_fast < close_fast ? colour_candle_up : colour_candle_down : Signal_Fast > Signal_Slow ? colour_candle_up : colour_candle_down : na
plotcandle(open_fast, high_fast, low_fast, close_fast, "Candles", candle_color, candle_color, true, bordercolor = candle_color)

fill(Plot_Band_High_Bot, Plot_Band_Low_Bot, cross_enable ? cross : na)

fill(Plot_Band_High_Bot, Plot_Band_Low_Bot, cross_enable ? cross_2 : na)

signal_cross_under_bottom  = ta.crossunder(Signal_Fast, Band_Low_Bot)
signal_cross_over_bottom   = ta.crossover(Signal_Fast, Band_Low_Bot)
signal_cross_over_top      = ta.crossover(Signal_Fast, Band_High_Bot)
signal_cross_under_top     = ta.crossunder(Signal_Fast, Band_High_Bot)
signal_cross_bullish       = ta.crossover(Signal_Fast, Signal_Slow)
signal_cross_bearish       = ta.crossunder(Signal_Fast, Signal_Slow)
signal_cross_bullish_under = ta.crossover(Signal_Fast, Signal_Slow) and (Signal_Fast <= Band_Low_Bot)
signal_cross_bearish_over  = ta.crossunder(Signal_Fast, Signal_Slow) and (Signal_Fast >= Band_High_Top)

alertcondition(signal_cross_under_bottom , "Signal Cross Under Bottom")
alertcondition(signal_cross_over_bottom , "Signal Cross Over Bottom")
alertcondition(signal_cross_over_top , "Signal Cross Over Top")
alertcondition(signal_cross_under_top , "Signal Cross Under Top")
alertcondition(signal_cross_bullish , "Signal Fast Cross Over Signal Slow")
alertcondition(signal_cross_bearish , "Signal Fast Cross Under Signal Slow")
alertcondition(signal_cross_bullish_under ,"Signal Fast Cross Over Signal Slow Outside of Range" )
alertcondition(signal_cross_bearish_over , "Signal Fast Cross Under Signal Slow Outside of Range")