// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © julzen2

//@version=5
indicator(title="TMA+CG", shorttitle="TMA+CG", overlay=true)

// --- Price Mode Constants ---
int PRICE_MODE_CLOSE = 0
int PRICE_MODE_OPEN = 1
int PRICE_MODE_HIGH = 2
int PRICE_MODE_LOW = 3
int PRICE_MODE_HL2 = 4  // (High + Low) / 2
int PRICE_MODE_HLC3 = 5 // (High + Low + Close) / 3
int PRICE_MODE_OHLC4 = 6 // (Open + High + Low + Close) / 4
int PRICE_MODE_WEIGHTED = 7 // (High + Low + Close * 2) / 4 - This matches MQL4's PRICE_WEIGHTED

// --- Inputs ---
string i_timeframe = input.timeframe("0", "Time Frame (0 for chart TF)")
int    i_halfLength = input.int(56, "Half Length", minval=1)
int    i_price = input.int(PRICE_MODE_WEIGHTED, "Price", options=[
     PRICE_MODE_CLOSE,
     PRICE_MODE_OPEN,
     PRICE_MODE_HIGH,
     PRICE_MODE_LOW,
     PRICE_MODE_HL2,
     PRICE_MODE_HLC3,
     PRICE_MODE_OHLC4,
     PRICE_MODE_WEIGHTED
     ])
float  i_bandsDeviations = input.float(2.5, "Bands Deviations", minval=0.0)
bool   i_interpolate = input.bool(true, "Interpolate")
bool   i_alertsOn = input.bool(false, "Enable Alerts")
bool   i_alertsOnCurrent = input.bool(false, "Alerts on Current Bar")
bool   i_alertsOnHighLow = input.bool(true, "Alerts on High/Low Penetration")
bool   i_alertsMessage = input.bool(true, "Show Alert Message")
bool   i_alertsSound = input.bool(false, "Play Alert Sound")
bool   i_alertsEmail = input.bool(false, "Send Alert Email")

// --- Global Variables (for alert suppression within the main loop) ---
var string g_previousAlert_msg = ""
var int g_previousAlert_time = 0    

// --- Helper Function: Get Price Series ---
f_get_price_series(mode, o, h, l, c) =>
    float price_val = switch mode
        PRICE_MODE_CLOSE    => c
        PRICE_MODE_OPEN     => o
        PRICE_MODE_HIGH     => h
        PRICE_MODE_LOW      => l
        PRICE_MODE_HL2      => (h + l) / 2
        PRICE_MODE_HLC3     => (h + l + c) / 3
        PRICE_MODE_OHLC4    => (o + h + l + c) / 4
        PRICE_MODE_WEIGHTED => (h + l + c * 2) / 4
        => c
    price_val

// --- Helper Function: Calculate TMA and Bands ---
// IMPORTANT: This calculation results in a centered TMA, which will cause repainting in Pine Script.
f_calculate_tma(price_series, halfLength, bandsDeviations) =>
    int hl = math.max(1, halfLength)
    int fullLength = 2 * hl + 1 // Total bars for calculation

    float tma_val = na
    float up_band = na
    float dn_band = na

    // We need enough bars in history to calculate the TMA
    // If not enough history, TMA will be 'na'
    if bar_index >= fullLength - 1 // Ensure we have at least 'fullLength' bars
        float current_tma_sum = 0.0
        float current_tma_sumw = 0.0

        // The TMA is now calculated considering data from 'fullLength - 1' bars back
        // to the current bar [0], effectively making it a lagging average.
        // The original formula looked into the "future" with price_series[-j].
        // To make it non-repainting, we must only use past data.
        // A common way to get a "Triangular" average in Pine is to smooth an SMA twice.
        // For a true "lagging" TMA as an approximation of the centered one without lookahead bias,
        // we can take a `2 * hl + 1` simple moving average and then average that result.

        // Approach 1: Double smoothed SMA (common approximation for non-repainting TMA)
        // Adjust the lengths slightly to match the original TMA concept as much as possible
        float sma1 = ta.sma(price_series, hl + 1) // First SMA
        tma_val := ta.sma(sma1, hl + 1) // Second SMA of the first SMA

        // For bands, we can use standard deviation of the current price around this lagging TMA
        float diff_sum_sq_up = 0.0
        float diff_sum_sq_dn = 0.0
        
        for i = 0 to fullLength - 1 // Iterate over the data points for standard deviation
            float price_diff = price_series[i] - tma_val
            if price_diff >= 0
                diff_sum_sq_up += math.pow(price_diff, 2)
            else
                diff_sum_sq_dn += math.pow(price_diff, 2)
        
        up_band := tma_val + bandsDeviations * math.sqrt(diff_sum_sq_up / fullLength)
        dn_band := tma_val - bandsDeviations * math.sqrt(diff_sum_sq_dn / fullLength)


    [tma_val, up_band, dn_band]

//---
//## Main Calculation and Plotting Logic
//---

string actual_tf = i_timeframe == "0" ? timeframe.period : i_timeframe

[o_tf, h_tf, l_tf, c_tf] = request.security(syminfo.tickerid, actual_tf, [open, high, low, close], lookahead=barmerge.lookahead_on)

float current_price_tf = f_get_price_series(i_price, o_tf, h_tf, l_tf, c_tf)

var float tmBuffer_val = na
var float upBuffer_val = na
var float dnBuffer_val = na

// Corrected: Use := for assignment to existing 'var' variables
if bar_index >= 0
    // Declare temporary variables on separate lines
    float _tma = na // Initialize with na, or 0.0 if you prefer
    float _up = na
    float _dn = na
    
    // Declare temporary variables on separate lines, as Pine Script requires
    
    
    // Assign the results from the function call to these temporary variables using tuple assignment with '='
    [temp_tma, temp_up, temp_dn] = f_calculate_tma(current_price_tf, i_halfLength, i_bandsDeviations)
    
    // Then assign them individually to the 'var' variables using the ':=' operator.
    tmBuffer_val := temp_tma
    upBuffer_val := temp_up
    dnBuffer_val := temp_dn

// Corrected plotting colors
plot(tmBuffer_val, title="TMA", color=color.new(color.gray, 0), linewidth=2, style=plot.style_line) // Using color.gray for DimGray
plot(upBuffer_val, title="Upper Band", color=color.new(color.red, 0), linewidth=1, style=plot.style_line)
plot(dnBuffer_val, title= "Lower Band", color=color.new(color.green, 0), linewidth=1, style=plot.style_line) // Using color.lime for LimeGreen

//---
//## Arrow Logic
//---

float prev_high_tf = h_tf[1]
float prev_low_tf = l_tf[1]
float prev_close_tf = c_tf[1]
float prev_open_tf = o_tf[1]
float prev_upBuffer = upBuffer_val[1]
float prev_dnBuffer = dnBuffer_val[1]

float atr_val = ta.atr(20)

bool up_arrow_fire = prev_high_tf > prev_upBuffer and prev_close_tf > prev_open_tf and c_tf[0] < o_tf[0]
//plotshape(up_arrow_fire ? h_tf[0] + atr_val : na,
     //title="Up Arrow", location=location.abovebar, color=color.new(color.blue, 0), style=shape.arrowup, size=size.small)

bool dn_arrow_fire = prev_low_tf < prev_dnBuffer and prev_close_tf < prev_open_tf and c_tf[0] > o_tf[0]
//plotshape(dn_arrow_fire ? l_tf[0] - atr_val : na,
     //title="Down Arrow", location=location.belowbar, color=color.new(color.red, 0), style=shape.arrowdown, size=size.small)

//---
//## Alert Logic
//---

// --- Main Calculation ---
// Get actual timeframe string for request.security
// This is the correct and only block for main calculations and plotting.
//actual_tf = i_timeframe == "0" ? timeframe.period : i_timeframe

// Request OHLC data from the specified timeframe unconditionally.
// This is valid because `request.security` is called once per bar in this function.
// `lookahead=barmerge.lookahead_on` is crucial for centered TMA calculations, but implies repainting.
//[o_tf, h_tf, l_tf, c_tf] = request.security(syminfo.tickerid, actual_tf, [open, high, low, close], lookahead=barmerge.lookahead_on)

// Get the price series for the selected Price Mode
//float current_price_tf = f_get_price_series(i_price, o_tf, h_tf, l_tf, c_tf)

// Declare the var variables to hold TMA and band values
//var float tmBuffer_val = na
//var float upBuffer_val = na
//var float dnBuffer_val = na

// Calculate TMA and Bands and assign to the var variables
// Note: Due to the centered nature of the MQL4 TMA, this will repaint.
//[tmBuffer_val, upBuffer_val, dnBuffer_val] = f_calculate_tma(current_price_tf, i_halfLength, i_bandsDeviations)

// --- Plotting ---
//plot(tmBuffer_val, title="TMA", color=color.new(color.gray, 0), linewidth=2, style=plot.style_line)
//plot(upBuffer_val, title="Upper Band", color=color.new(color.red, 0), linewidth=1, style=plot.style_line)
//plot(dnBuffer_val, title="Lower Band", color=color.new(color.green, 0), linewidth=1, style=plot.style_line)

// --- Arrows ---
// MQL4 arrows conditions use `i+1` (previous bar on current chart) and `i` (current bar on current chart).
// We need to use `[1]` for previous bar values and `[0]` (or no index) for current bar values.
// Ensure we have enough historical data for these lookbacks.

// Values from the previous bar on the requested timeframe (tf)
// These come from the `request.security` calls, so they are already aligned to `actual_tf`.
//float prev_high_tf = h_tf[1]
//float prev_low_tf = l_tf[1]
//float prev_close_tf = c_tf[1]
//float prev_open_tf = o_tf[1]
//float prev_upBuffer = upBuffer_val[1] // Get previous value of the var series
//float prev_dnBuffer = dnBuffer_val[1] // Get previous value of the var series

// ATR calculation for arrow offset. MQL4 used iATR(NULL,0,20,i) which usually means the current chart's ATR.
// If the selected timeframe `actual_tf` is different from the chart's timeframe,
// using `ta.atr` directly would compute ATR on the chart's timeframe.
// To compute ATR on `actual_tf`, we must request its OHLC series *again* for `ta.atr`.
//float atr_val = ta.atr(20) // Use chart's ATR for simplicity and typical usage.
// If actual_tf's ATR is needed:
// [o_atr_tf, h_atr_tf, l_atr_tf, c_atr_tf] = request.security(syminfo.tickerid, actual_tf, [open, high, low, close], lookahead=barmerge.lookahead_on)
// float atr_val = ta.atr(20, high=h_atr_tf, low=l_atr_tf, close=c_atr_tf)


// Corrected Arrow Plotting Logic
//bool up_arrow_fire = prev_high_tf > prev_upBuffer and prev_close_tf > prev_open_tf and c_tf[0] < o_tf[0]
//plotshape(up_arrow_fire ? h_tf[0] + atr_val : na,
  //   title="Up Arrow", location=location.abovebar, color=color.new(color.blue, 0), style=shape.arrowup, size=size.small)

//bool dn_arrow_fire = prev_low_tf < prev_dnBuffer and prev_close_tf < prev_open_tf and c_tf[0] > o_tf[0]
//plotshape(dn_arrow_fire ? l_tf[0] - atr_val : na,
  //   title="Down Arrow", location=location.belowbar, color=color.new(color.red, 0), style=shape.arrowdown, size=size.small)

