Moving Averages w/Signals [CSJ7]
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © gtellezgiron2009

//@version=5
indicator("Moving Averages w/Signals [CSJ7]", shorttitle = 'CSJ7 Moving Averages', overlay = true)


//==================================
// CONSTANTS
//==================================

// Titles for input groups
string GR_MOVING_AVERAGES   = "Moving Averages ===================================="
string GR_SIGNALS           = "Buy & Sell Signals ================================="

// Define color constants for various scenarios and states
color COL_BEARGR    = color.rgb(133, 17, 17)  // Bearish Growing
color COL_BULLGR    = color.green             // Bullish Growing
color COL_BEARSH	= color.red               // Bearish Shrinking
color COL_BULLSH	= color.rgb(27, 96, 29)   // Bullish Shrinking
color COL_TRANSP    = color.new(color.blue,100) // Transparent color
color COLOR_UP      = color.green             // Color for upward movement
color COLOR_DOWN    = color.red               // Color for downward movement
color COLOR_BUY     = color.rgb(0, 255, 8)    // Buy signal color
color COLOR_SELL    = color.rgb(255, 0, 0)    // Sell signal color
color COLOR_NEUTRAL = color.gray              // Neutral color
int MA_TRANSPARENCY = 0                       // Transparency level for moving averages

// Define line widths for the moving averages
int FAST_LINE_WIDTH         = 1
int MEDIUM_LINE_WIDTH       = 3
int SLOW_LINE_WIDTH         = 5

//==================================
// INPUTS
//==================================

// User input for type of moving average
string ma_type_input = input.string('Exponential','Type of moving average',options = ['Simple', 'Exponential'], group = GR_MOVING_AVERAGES)

// User input for lengths of moving averages
int length_fast_input = input(50, "Fast: Length", group = GR_MOVING_AVERAGES)
int length_medium_input = input(100, "Medium: Length", group = GR_MOVING_AVERAGES)
int length_slow_input = input(500, "Slow: Length", group = GR_MOVING_AVERAGES)

// User input for Buy signal configuration
string buy_crosser_input = input.string('Medium MA','Buy: ',options=['Fast MA','Medium MA','Slow MA'], inline = '1', group = GR_SIGNALS)
string buy_crossType_input = input.string('Over','crosses',options = ['Over', 'Under'], inline = '1', group = GR_SIGNALS)
string buy_crossed_input = input.string('Slow MA','',options=['Fast MA','Medium MA','Slow MA'], inline = '1', group = GR_SIGNALS)

// User input for Sell signal configuration
string sell_crosser_input = input.string('Medium MA','Sell: ',options=['Fast MA','Medium MA','Slow MA'], inline = '2', group = GR_SIGNALS)
string sell_crossType_input = input.string('Under','crosses',options = ['Over', 'Under'], inline = '2', group = GR_SIGNALS)
string sell_crossed_input = input.string('Slow MA','',options=['Fast MA','Medium MA','Slow MA'], inline = '2', group = GR_SIGNALS)

// User input to decide if areas should be filled or not
bool fill_areas_input = input.bool(true, 'Fill areas')

//==================================
// FUNCTIONS
//==================================

// Function to calculate moving averages based on user's choice of type and lengths
get_mas(source, length_fast_input, length_medium_input, length_slow_input, ma_type_input) =>     
    float ma_fast = 0.0
    float ma_med = 0.0
    float ma_slow = 0.0

    if ma_type_input == "Simple"
        ma_fast := ta.sma(source, length_fast_input) 
        ma_med := ta.sma(source, length_medium_input) 
        ma_slow := ta.sma(source, length_slow_input) 
    else if ma_type_input == "Exponential"
        ma_fast := ta.ema(source, length_fast_input) 
        ma_med := ta.ema(source, length_medium_input) 
        ma_slow := ta.ema(source, length_slow_input) 

    [ma_fast, ma_med, ma_slow]

// Function to determine color based on direction of the data
get_color_by_direction(source,lookback, col_up,col_dn, transp) =>
    col_p = source > source[lookback] ? col_up : source < source[lookback] ? col_dn : COLOR_NEUTRAL
    col = color.new(col_p, transp)

// Function to determine various market scenarios based on the relationship between fast and slow signals
get_scenarios(signal_fast,signal_slow) =>                                        
    trend_bull = signal_fast > signal_slow
    trend_bear = signal_fast < signal_slow

    dif_ma = math.abs(signal_fast - signal_slow)
    signal_fast_up = signal_fast > signal_fast[1]
    signal_fast_dn = signal_fast < signal_fast[1]
    signal_slow_up = signal_slow > signal_slow[1]
    signal_slow_dn = signal_slow < signal_slow[1] 

    trend_shrinking = dif_ma < dif_ma[1] and not(trend_bull ? signal_fast_up and signal_slow_up : signal_fast_dn and signal_slow_dn)
    trend_growing = not(trend_shrinking)

    bullGr = trend_bull and trend_growing
    bullSh = trend_bull and trend_shrinking
    bearGr = trend_bear and trend_growing
    bearSh = trend_bear and trend_shrinking

    [bullGr,bullSh,bearGr,bearSh, signal_fast_up, signal_fast_dn, signal_slow_up, signal_slow_dn]

// Calculate moving averages
[ma_fast, ma_med, ma_slow] = get_mas(close, length_fast_input, length_medium_input, length_slow_input, ma_type_input)

// Determine market scenarios based on moving averages
[bullGr,bullSh,bearGr,bearSh, signal_fast_up, signal_fast_dn, signal_slow_up, signal_slow_dn] = get_scenarios(ma_fast,ma_slow)

// Define super bullish and super bearish scenarios
superBull = ma_fast > ma_med and ma_med > ma_slow
superBear = ma_fast < ma_med and ma_med < ma_slow

//==================================
// CROSSES
//==================================

// Determine crossing levels based on user input
float buy_crosser = switch buy_crosser_input
    'Fast MA' => ma_fast
    'Medium MA' => ma_med
    'Slow MA' => ma_slow
float buy_crossed = switch buy_crossed_input
    'Fast MA' => ma_fast
    'Medium MA' => ma_med
    'Slow MA' => ma_slow

float sell_crosser = switch sell_crosser_input
    'Fast MA' => ma_fast
    'Medium MA' => ma_med
    'Slow MA' => ma_slow

float sell_crossed = switch sell_crossed_input
    'Fast MA' => ma_fast
    'Medium MA' => ma_med
    'Slow MA' => ma_slow

// Determine buy and sell signals based on crossing scenarios
buy_signal = buy_crossType_input == 'Over' ? ta.crossover(buy_crosser, buy_crossed) : ta.crossunder(buy_crosser, buy_crossed)
sell_signal = sell_crossType_input == 'Over' ? ta.crossover(buy_crosser, buy_crossed) : ta.crossunder(buy_crosser, buy_crossed)

// Plot buy and sell signals on the chart
plotshape(buy_signal,'Buy Signal', shape.triangleup,location.belowbar, COLOR_BUY,0,'Buy',COLOR_BUY,true,size.small)
plotshape(sell_signal,'Sell Signal', shape.triangledown,location.abovebar, COLOR_SELL,0,'Sell',COLOR_SELL,true,size.small)

//==================================
// PLOTS
//==================================

// Configuration for plot transparency
int ma_transparency_fill = 50
int transp_superBull_fill = 40
int transp_superBear_fill = 20
int div = 5

// Determine lookback periods for moving averages
ma_slow_lookback = int(math.round(length_slow_input / div,0))
ma_medium_lookback = int(math.round(length_medium_input / div,0))
ma_fast_lookback = int(math.round(length_fast_input / div,0))

// Determine trend color based on scenarios
col_trend = bullGr ? COL_BULLGR : bullSh ? COL_BULLSH : bearGr ? COL_BEARGR : bearSh ? COL_BEARSH : color.yellow 

// Adjust transparency based on user input
if not(fill_areas_input)
    ma_transparency_fill := 100
    transp_superBull_fill := 100
    transp_superBear_fill := 100

// Plot moving averages on the chart with respective colors and widths
ln_ma_fast = plot(ma_fast, title="Fast", color=get_color_by_direction(ma_fast,ma_fast_lookback, COLOR_UP,COLOR_DOWN, MA_TRANSPARENCY), linewidth = FAST_LINE_WIDTH)
ln_ma_medium = plot(ma_med, title="Medium", color=get_color_by_direction(ma_med,ma_medium_lookback, COLOR_UP,COLOR_DOWN, MA_TRANSPARENCY), linewidth = MEDIUM_LINE_WIDTH)
ln_ma_slow = plot(ma_slow, title="Slow", color=get_color_by_direction(ma_slow,ma_slow_lookback, COLOR_UP,COLOR_DOWN, MA_TRANSPARENCY), linewidth = SLOW_LINE_WIDTH)

// Fill the area between Medium and Slow moving averages based on trend color
fill(ln_ma_medium, ln_ma_slow, color = color.new(col_trend,ma_transparency_fill), fillgaps = true)
