MA Directional Table
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// Written by © angelh584
// idea by @Cooladoola

//@version=5
indicator("MA Directional Table", overlay=true)

//===== VARIABLES =====\\
var float histSeries = na
var color cloudColor = na
var int yellowCount = 0
var int greenCount = 0
var int redCount = 0

//===== GROUPS =====\\
g1="▶─────────  MA Settings  ─────────◀"
g2="▶─────────  Table Settings  ─────────◀"
g4="▶─────────  Cloud Settings  ─────────◀"
g5="▶─────────  Extra MA  ─────────◀"
g3="▶─────────  Customize Table  ─────────◀"

//===== INPUTS =====\\
//MA Cross
maType = input.string("EMA", title="Moving Average Type", options=["SMA", "EMA", "VWMA"], tooltip="MA type & lengths are calculated for table", group=g1)
shortTermLength = input.int(9, title="MA 1", group=g1, inline="1")
ma1Color = input.color(color.blue, title="ㅤ", group=g1, inline="1")
longTermLength = input.int(21, title="MA 2", group=g1, inline="2")
ma2Color = input.color(color.red, title="ㅤ", group=g1, inline="2")

//Table
position = input.string("top_right", title="Table Position", options=["top_left", "top_right", "bottom_left", "bottom_right"], group=g2)
orientation = input.string("horizontal", title="Table Orientation", options=["horizontal", "vertical"], group=g2)
usePriceCondition = input.bool(false, title="Use Price Condition", tooltip="The table color changes to yellow if the current price differs from the MA trend & crosses MA1.", group=g2)

//Cloud
showCloud = input.bool(false, title="Show MA Cloud", tooltip="Toggle to show or hide the moving average cloud.", group=g4)
cloudBullishColor = input.color(color.new(color.green, 90), title="Bullish Cloud Color", group=g4)
cloudBearishColor = input.color(color.new(color.red, 90), title="Bearish Cloud Color", group=g4)

//Extra MA
extraMAToggle = input.bool(false, title="Add Extra MAㅤ", inline ="4", group=g5)
includeExtraMATable = input.bool(false, title="Include In Table", group=g5, inline="4", tooltip="Value for Extra MA will be displayed on Table. Price Condition will still be displayed with background color")
extraMAType = input.string("SMA", title="Extra MA Type", options=["SMA", "EMA", "VWMA"], group=g5)
extraMALength = input.int(200, title="Extra MA Length", group=g5, inline="3")
extraMAColor = input.color(color.purple, title="ㅤ", group=g5, inline="3")

//Table Customize
bullishBackgroundColor = input.color(color.green, title="Bullish Status Color", tooltip="Choose the status color for bullish status in the table.", group=g3)
bearishBackgroundColor = input.color(color.red, title="Bearish Status Color", tooltip="Choose the status color for bearish status in the table.", group=g3)
neutralBackgroundColor = input.color(color.gray, title="Neutral Status Color", tooltip="Choose the status color for neutral status in the table.", group=g3)
priceConditionBackgroundColor = input.color(color.yellow, title="Price Condition Status Color", tooltip="Choose the status color for when the price condition is met.", group=g3)
tableHeaderColor = input.color(#c8e6c9, title="Table Header Color", tooltip="Sets the status color for the header row in the table. This color will be applied to cells like 'Timeframe' and 'Status'.", group=g3)
textColor = input.color(color.black, title="Table Text Color", group=g3, tooltip="Sets text color for table")
textSize = input.string("normal", title="Table Text Size", options=["small", "normal", "large"], group=g3)

//===== FUNCTIONS =====\\
calcMA(src, length) =>
    ma = 0.0
    if maType == "SMA"
        ma := ta.sma(src, length)
    else if maType == "EMA"
        ma := ta.ema(src, length)
    else if maType == "VWMA"
        ma := ta.vwma(src, length)
    ma

//===== CALCULATIONS =====\\
calcExtraMA(src, length) =>
    ma = 0.0
    if extraMAType == "SMA"
        ma := ta.sma(src, length)
    else if extraMAType == "EMA"
        ma := ta.ema(src, length)
    else if extraMAType == "VWMA"
        ma := ta.vwma(src, length)
    ma

maStatus(timeframe) =>
    shortMA = request.security(syminfo.tickerid, timeframe, calcMA(close, shortTermLength), lookahead=barmerge.lookahead_off)
    longMA = request.security(syminfo.tickerid, timeframe, calcMA(close, longTermLength), lookahead=barmerge.lookahead_off)
    extraMAValue = request.security(syminfo.tickerid, timeframe, calcExtraMA(close, extraMALength), lookahead=barmerge.lookahead_off)
    closePrice = request.security(syminfo.tickerid, timeframe, close, lookahead=barmerge.lookahead_off)
    status = "neutral"
    bgColor = neutralBackgroundColor
    if shortMA > longMA
        status := "bullish"
        bgColor := usePriceCondition ? (closePrice < shortMA ? priceConditionBackgroundColor : bullishBackgroundColor) : bullishBackgroundColor
    else if shortMA < longMA
        status := "bearish"
        bgColor := usePriceCondition ? (closePrice > shortMA ? priceConditionBackgroundColor : bearishBackgroundColor) : bearishBackgroundColor
    if includeExtraMATable and extraMAToggle
        status := str.tostring(math.round(extraMAValue * 100) / 100)
    [status, bgColor]

isBullishTimeframe(tf) =>
    [status, _] = maStatus(tf)
    status == "bullish"

isBearishTimeframe(tf) =>
    [status, _] = maStatus(tf)
    status == "bearish"

//===== TABLE CREATION =====\\
rows = orientation == "horizontal" ? 7 : 1
cols = orientation == "horizontal" ? 2 : 14
var table panel = table.new(position, rows, cols)
table.cell(panel, 0, 0, "Timeframe", bgcolor=tableHeaderColor, text_size=textSize)
table.cell(panel, 0, 1, "Status", bgcolor=tableHeaderColor, text_size=textSize)

createTableCell(timeframe, row, col, label) =>
    [status, colorCode] = maStatus(timeframe)
    table.cell(panel, row, col, label, bgcolor=tableHeaderColor, text_color=textColor, text_size=textSize)
    table.cell(panel, row, col + 1, status, bgcolor=colorCode, text_color=textColor, text_size=textSize)

if orientation == "horizontal"
    createTableCell("1", 1, 0, "1 min")
    createTableCell("5", 2, 0, "5 mins")
    createTableCell("15", 3, 0, "15 mins")
    createTableCell("60", 4, 0, "1 hour")
    createTableCell("240", 5, 0, "4 hours")
    createTableCell("D", 6, 0, "1 day")
else
    createTableCell("1", 0, 2, "1 min")
    createTableCell("5", 0, 4, "5 mins")
    createTableCell("15", 0, 6, "15 mins")
    createTableCell("60", 0, 8, "1 hour")
    createTableCell("240", 0, 10, "4 hours")
    createTableCell("D", 0, 12, "1 day")

//===== MAIN CALCULATIONS =====\\
shortMA_current = calcMA(close, shortTermLength)
longMA_current = calcMA(close, longTermLength)
cloudColor := shortMA_current > longMA_current ? cloudBullishColor : cloudBearishColor

allBullish = isBullishTimeframe("1") and isBullishTimeframe("5") and isBullishTimeframe("15") and isBullishTimeframe("60") and isBullishTimeframe("240") and isBullishTimeframe("D")
allBearish = isBearishTimeframe("1") and isBearishTimeframe("5") and isBearishTimeframe("15") and isBearishTimeframe("60") and isBearishTimeframe("240") and isBearishTimeframe("D")

bullishCount = (isBullishTimeframe("1") ? 1 : 0) + (isBullishTimeframe("5") ? 1 : 0) + (isBullishTimeframe("15") ? 1 : 0) + (isBullishTimeframe("60") ? 1 : 0) + (isBullishTimeframe("240") ? 1 : 0) + (isBullishTimeframe("D") ? 1 : 0)
bearishCount = 6 - bullishCount

//===== PLOT MA =====\\
plot1 = plot(shortMA_current, color=ma1Color, title="MA Length 1")
plot2 = plot(longMA_current, color=ma2Color, title="MA Length 2")

//===== FILL MA CLOUD =====\\
fillCondition = showCloud ? cloudColor : na
fill(plot1, plot2, color=fillCondition, title="MA Cloud")

//===== PLOT EXTRA MA =====\\
extraMA_current = extraMAToggle ? calcExtraMA(close, extraMALength) : na
plot(extraMA_current, color=extraMAColor, title="Extra MA")

//===== ALERT CONDITIONS =====\\
// Check for bullish or bearish crossover
crossAboveCondition = ta.crossover(shortMA_current, longMA_current)
crossBelowCondition = ta.crossunder(shortMA_current, longMA_current)

alertcondition(crossAboveCondition, title="Bullish Crossover", message="Bullish Cross!")
alertcondition(crossBelowCondition, title="Bearish Crossover", message="Bearish Cross!")

alertcondition(allBullish, title="All Timeframes Bullish", message="All timeframes are showing a bullish trend!")
alertcondition(allBearish, title="All Timeframes Bearish", message="All timeframes are showing a bearish trend!")

alertcondition(bullishCount >= 4, title="Most Timeframes Bullish", message="4 or more timeframes are bullish.")
alertcondition(bearishCount >= 4, title="Most Timeframes Bearish", message="4 or more timeframes are bearish.")

alertcondition(greenCount == 2 and redCount == 2 and yellowCount == 2, title="Coherence", message="Exactly 2 green, 2 red, and 2 yellow statuses across timeframes.")