//@version=6
indicator("Indicator: Activation Scores", scale=scale.right, overlay=false)

import TradingView/ta/10
import NiceOrbit/LibraryUtility/18 as utils
import NiceOrbit/LibraryRSIDivergence/1 as rsiDiv
import NiceOrbit/LibraryGaussianChannel/1 as gcl
import NiceOrbit/LibraryMACD/10 as macdLib
import NiceOrbit/LibraryMoneySupply/9 as libMoneySupply
import NiceOrbit/LibraryStochasticDivergence/9 as libStochDiv
import NiceOrbit/LibraryMoneySupplyDivergence/1 as libM3Div
import NiceOrbit/LibraryVWAPDivergence/4 as libVwapDiv
import NiceOrbit/LibraryRealizedPrice/4 as libRealizedPrice
import NiceOrbit/LibraryTradeLogger/8 as tradeLogger
import NiceOrbit/LibraryLongExit/8 as libLongExit
import NiceOrbit/LibraryLongEntry/46 as libLongEntry

group_date_range                        = "Back Testing Date Range"
startDate                               = input.time(timestamp("1 January 2018"), "Start", group=group_date_range, inline="date", display=display.none)
endDate                                 = input.time(timestamp("1 July 2024 23:59 +0000"), "End ", group=group_date_range, inline="date", display=display.none)
timeCondition                           = time >= startDate and time <= endDate

group_neural_activation_thresholds = "Neural Activation Thresholds"
i_long_entry_activation_threshold   = input.float(-4.0, step=0.5, title="Long Entry Activation Threshold", group=group_neural_activation_thresholds, display = display.none)
i_long_exit_activation_threshold    = input.float(4.0, step=0.5, title="Long Exit Activation Threshold", group=group_neural_activation_thresholds, display = display.none)


group_neural_activation_weights = "Neural Activation Weights"
i_w_stoch               = input.float(1.0, step=0.2, title="Stochastic Weight", group=group_neural_activation_weights, display = display.none)
i_w_macd_pred           = input.float(0.05, step=0.05, title="MACD Prediction Weight", group=group_neural_activation_weights, display = display.none)
i_w_osc                 = input.float(0.4, step=0.15, title="OSC Weight", group=group_neural_activation_weights, display = display.none)
i_w_macd_bullish        = input.float(0.1, step=0.05, title="MACD Bullish Weight", group=group_neural_activation_weights, display = display.none)
i_w_m3_momentum         = input.float(-0.45, step=0.1, title="M3 Momentum Weight", group=group_neural_activation_weights, display = display.none)
i_m3_momentum_period    = input.int(1, "M3 Momentum Period", minval=1, group=group_neural_activation_weights, display = display.none)
i_w_m2_tiny             = input.float(1.0, step=0.05, title="M2 Tiny Momentum Weight", group=group_neural_activation_weights, display=display.none)
i_w_rsid_osc            = input.float(-3.0, step=0.5, title="RSID OSC Weight", group=group_neural_activation_weights, display=display.none)
i_w_stoch_div_osc       = input.float(-1.0, step=0.1, title="Stoch Div OSC Weight", group=group_neural_activation_weights, display=display.none)
i_w_vwap_div_osc        = input.float(0.2, step=0.05, title="VWAP Div OSC Weight", group=group_neural_activation_weights, display=display.none)
i_w_stoch_peaking       = input.float(0.5, step=0.1, title="Stoch Peaking Weight", group=group_neural_activation_weights, display=display.none)
i_w_stoch_bottoming     = input.float(-1.0, step=0.1, title="Stoch Bottoming Weight", group=group_neural_activation_weights, display=display.none)
i_w_m3_div_osc          = input.float(-2.0, step=0.05, title="M3 Div OSC Weight", group=group_neural_activation_weights, display=display.none)
i_w_m2_div_osc          = input.float(2, step=0.05, title="M2 Div OSC Weight", group=group_neural_activation_weights, display=display.none)

i_delta_sensitivity = input.float(0.5, title="Delta Intensity Sensitivity", step=0.05, tooltip="Controls how sensitive the color intensity is to changes in the activation score. Higher values mean the color becomes intense more quickly.", display = display.none)

groupM3          = "M3 Settings"
m3_growth_rate_period_1D        = input.int(92, "Growth Rate Period (1D)", group=groupM3,display=display.none)
m3_growth_rate_period_12H       = input.int(92, "Growth Rate Period (12H)", group=groupM3,display=display.none)

// New smoothing inputs (add these)
m3_globalSmoothingMethod          = input.string(title="Money Supply Smoothing Method", options=["None", "Simple Moving Average", "Exponential Moving Average", "Hull Moving Average"],  defval="None", group=groupM3, display=display.none)
m3_globalSmoothingPeriod_1D       = input.int(14, title="Global Smoothing Period (1D)", minval=1, group=groupM3, display=display.none)
m3_globalSmoothingPeriod_12H      = input.int(14, title="Global Smoothing Period (12H)", minval=1, group=groupM3, display=display.none)

smoothM3SmoothingMethod           = input.string(title="Smooth M3 Moving Average", options=["None", "Simple Moving Average", "Exponential Moving Average", "Hull Moving Average"], defval="Exponential Moving Average", group=groupM3, display=display.none)
smoothM3SmoothingPeriod_1D        = input.int(5, title="Smooth M3 Smoothing Period (1D)", minval=1, group=groupM3, display=display.none)
smoothM3SmoothingPeriod_12H       = input.int(5, title="Smooth M3 Smoothing Period (12H)", minval=1, group=groupM3, display=display.none)

// Create timeframe-aware series variables
timeframe_divisor = utils.f_resInDays()
var int m3_growth_rate_period_tf      = na
var int m3_globalSmoothingPeriod_tf   = na
var int smoothM3SmoothingPeriod_tf    = na
m3_growth_rate_period_tf    := utils.f_getParamForTimeframe_int(m3_growth_rate_period_1D, m3_growth_rate_period_12H, m3_growth_rate_period_1D)
m3_globalSmoothingPeriod_tf := utils.f_getParamForTimeframe_int(m3_globalSmoothingPeriod_1D, m3_globalSmoothingPeriod_12H, m3_globalSmoothingPeriod_1D)
smoothM3SmoothingPeriod_tf  := utils.f_getParamForTimeframe_int(smoothM3SmoothingPeriod_1D, smoothM3SmoothingPeriod_12H, smoothM3SmoothingPeriod_1D)

// Create and populate MoneySupplyInputs
moneySupplyInputs = libMoneySupply.MoneySupplySettings.new()
moneySupplyInputs.m3_growth_rate_period := m3_growth_rate_period_tf
moneySupplyInputs.m3_globalSmoothingMethod := m3_globalSmoothingMethod
moneySupplyInputs.m3_globalSmoothingPeriod := m3_globalSmoothingPeriod_tf
moneySupplyInputs.smoothM3SmoothingMethod := smoothM3SmoothingMethod
moneySupplyInputs.smoothM3SmoothingPeriod := smoothM3SmoothingPeriod_tf

// Calculate money supply data
moneySupplyData = libMoneySupply.calculate_money_supply(moneySupplyInputs)
m2_US_EU_CN = moneySupplyData.m2_US_EU_CN
m3_global_smoothed = moneySupplyData.m3_global_smoothed

// M3 Divergence Oscillator Calculation
m3_div_osc = libM3Div.f_calc_oscillator(m3_global_smoothed, close)

//{ MACD Setup }
// Create settings object
macd_settings = macdLib.MACDSettings.new()
fast_length_1D                      = input.int(12,"Fast Length (1D)", group="MACD", display=display.none)
fast_length_12H                     = input.int(15,"Fast Length (12H)", group="MACD", display=display.none) // Tuned from 12
macd_settings.fast_length           := utils.f_getParamForTimeframe_int(fast_length_1D, fast_length_12H, fast_length_1D)
slow_length_1D                      = input.int(26,"Slow Length (1D)", group="MACD", display=display.none)
slow_length_12H                     = input.int(35,"Slow Length (12H)", group="MACD", display=display.none) // Tuned from 26
macd_settings.slow_length           := utils.f_getParamForTimeframe_int(slow_length_1D, slow_length_12H, slow_length_1D)
signal_length_1D                    = input.int(9,"Signal Smoothing (1D)",minval=1,maxval=50,group="MACD", display=display.none)
signal_length_12H                   = input.int(9,"Signal Smoothing (12H)",minval=1,maxval=50,group="MACD", display=display.none)
macd_settings.signal_length         := utils.f_getParamForTimeframe_int(signal_length_1D, signal_length_12H, signal_length_1D)
macd_settings.sma_source            := input.string("EMA","Oscillator MA Type",options=["SMA","EMA"],group="MACD", display=display.none)
macd_settings.sma_signal            := input.string("EMA","Signal Line MA Type",options=["SMA","EMA"],group="MACD", display=display.none)
macd_settings.i_macd_slope_threshold_percent := input(-9.0, "MACD Slope Threshold (%)", group="MACD", display=display.none)

// Timeframe-aware inputs for MACD reversal and prediction
bullishFlipSignalBars_1D            = input.int(1, "Bullish Flip Stability (1D)",group="MACD", display=display.none)
bullishFlipSignalBars_12H           = input.int(1, "Bullish Flip Stability (12H)",group="MACD", display=display.none)
bearishFlipSignalBars_1D            = input.int(2, "Bearish Flip Stability (1D)",group="MACD", display=display.none)
bearishFlipSignalBars_12H           = input.int(2, "Bearish Flip Stability (12H)",group="MACD", display=display.none)
nBarsOut_1D                         = input.int(5,"N Bars Out for Prediction (1D)",group="MACD", display=display.none)
nBarsOut_12H                        = input.int(10,"N Bars Out for Prediction (12H)",group="MACD", display=display.none)
macd_settings.bullishFlipSignalBars := utils.f_getParamForTimeframe_int(bullishFlipSignalBars_1D, bullishFlipSignalBars_12H, bullishFlipSignalBars_1D)
macd_settings.bearishFlipSignalBars := utils.f_getParamForTimeframe_int(bearishFlipSignalBars_1D, bearishFlipSignalBars_12H, bearishFlipSignalBars_1D)
macd_settings.nBarsOut              := utils.f_getParamForTimeframe_int(nBarsOut_1D, nBarsOut_12H, nBarsOut_1D)

macd_source  = input(title="Source",defval=close, group="MACD", display=display.none)
macd_results = macdLib.calculate_macd(macd_source, macd_settings)

// Unpack results
macd = macd_results.macd
signal = macd_results.signal
hist = macd_results.hist
isMacdHistRising = macd_results.isMacdHistRising
isMacdHistFalling = macd_results.isMacdHistFalling
macd_slope_above_threshold = macd_results.macd_slope_above_threshold
macd_is_increasing = macd_results.macd_is_increasing
macd_is_decreasing = macd_results.macd_is_decreasing
macd_prediction = macd_results.macd_prediction
macd_flipped_bullish = macd_results.macd_flipped_bullish
macd_flipped_bearish = macd_results.macd_flipped_bearish
macdLongEntryCondition = macd_results.macdLongEntryCondition
macdLongExitCondition = macd_results.macdLongExitCondition
macd_slope_current = macd_results.macd_slope_current
isMacdMinusMacdOneRising = macd_results.isMacdMinusMacdOneRising
macd_signal_difference_percentage = macd_results.macd_signal_difference_percentage
isMacdRising_len2 = macd_results.isMacdRising_len2 
//} ========================

//{ Stochastic RSI Calculation }

groupStochRSI       = "Stochastic RSI Settings"
stochMasterSwitch   = input.string("Enabled", title="Stochastic RSI Master Switch", options=["Enabled","Disabled"], group= groupStochRSI, display=display.none)
smoothK_1D          = input.int(4,  "K (1D)", minval=1, group= groupStochRSI, display=display.none)
smoothK_12H         = input.int(2,  "K (12H)", minval=1, group= groupStochRSI, display=display.none)
smoothK             = utils.f_getParamForTimeframe_int(smoothK_1D, smoothK_12H, smoothK_1D)
smoothD             = input.int(3,  "D", minval=1, group= groupStochRSI, display=display.none)
lengthRSI           = input.int(10, "RSI Length", minval=1, group= groupStochRSI, display=display.none) // This is intentionally NOT timeframe-aware to match v36 baseline
lengthStoch_1D      = input.int(17, "Stochastic Length (1D)", minval=1, group= groupStochRSI, display=display.none)
lengthStoch_12H     = input.int(32, "Stochastic Length (12H)", minval=1, group= groupStochRSI, display=display.none)
src_stoch           = input(close,  title="RSI Source", group= groupStochRSI, display=display.none)
stoch_tf            = input.timeframe("", "Stoch RSI Timeframe", group= groupStochRSI, display=display.none)
stoch_high_limit    = input.int(87, title="Stochastic High Limit", group= groupStochRSI, display=display.none)
stoch_low_limit     = input.int(20, title="Stochastic Low Limit", group= groupStochRSI, display=display.none)

calcStoch() =>
    // The RSI for Stoch RSI uses a fixed length, matching the v36 baseline.
    rsi_val = ta.rsi(src_stoch, lengthRSI)

    // Multi-call pattern for Stochastic
    stoch_1D = ta.stoch(rsi_val, rsi_val, rsi_val, lengthStoch_1D)
    stoch_12H = utils.f_dynamic_stoch(rsi_val, rsi_val, rsi_val, utils.f_getParamForTimeframe_int(lengthStoch_1D, lengthStoch_12H, lengthStoch_1D)) // _high and _low are the same as source (rsi_val)
    stoch_val = timeframe.period == "D" ? stoch_1D : stoch_12H

    ta.sma(stoch_val, smoothK)


stoch_value         = stoch_tf == "" ? calcStoch() : request.security(syminfo.tickerid, stoch_tf, calcStoch(), gaps=barmerge.gaps_off, lookahead=barmerge.lookahead_off)
bool stochCondition = stochMasterSwitch == "Enabled" ? (stoch_value > stoch_high_limit or stoch_value < stoch_low_limit) : true
osc_high_limit      = input.int(67, title="Maximum RSI allowed on regular long entry condition(67)", group= groupStochRSI, display=display.none)
osc_src             = input(low, "OSC source(low)", group= groupStochRSI, display=display.none)

//{ Stochastic Divergence }
groupStochDiv = "Stochastic Divergence"
stochDiv_stochLength_1D      = input.int(14, title="Stochastic Length (1D)", minval=1, group=groupStochDiv, display=display.none)
stochDiv_stochLength_12H     = input.int(14, title="Stochastic Length (12H)", minval=1, group=groupStochDiv, display=display.none) // 2 * 1D
stochDiv_pivotLookback_1D    = input.int(5, title="Pivot Lookback Bars (1D)", minval=1, group=groupStochDiv, display=display.none)
stochDiv_pivotLookback_12H   = input.int(20, title="Pivot Lookback Bars (12H)", minval=1, group=groupStochDiv, display=display.none) // 2 * 1D

stochDivSettings = libStochDiv.StochasticDivergenceSettings.new()
stochDivSettings.smoothK := input.int(3, title="K Smoothing", minval=1, group=groupStochDiv, display=display.none)
stochDivSettings.smoothD := input.int(3, title="D Smoothing", minval=1, group=groupStochDiv, display=display.none)
stochDivSettings.maTypeK := input.string("Simple Moving Average", "MA Type K", options=["Simple Moving Average", "Exponential Moving Average", "Weighted Moving Average", "Hull Moving Average", "Volume Weighted Moving Average", "Volume Weighted Average Price", "None"], group=groupStochDiv, display=display.none)
stochDivSettings.maTypeD := input.string("Exponential Moving Average", "MA Type D", options=["Simple Moving Average", "Exponential Moving Average", "Weighted Moving Average", "Hull Moving Average", "Volume Weighted Moving Average", "Volume Weighted Average Price", "None"], group=groupStochDiv, display=display.none)
stochDivSettings.divergenceStrength := input.int(2, title="Divergence Strength (bars away)", minval=1, group=groupStochDiv, display=display.none)

stochDivSettings.stochLength   := utils.f_getParamForTimeframe_int(stochDiv_stochLength_1D, stochDiv_stochLength_12H, stochDiv_stochLength_1D)
stochDivSettings.pivotLookback := utils.f_getParamForTimeframe_int(stochDiv_pivotLookback_1D, stochDiv_pivotLookback_12H, stochDiv_pivotLookback_1D)

var float stoch_div_k_val = na
var bool stoch_bullishDivergence = false, stoch_bearishDivergence = false
var bool stoch_is_peaking = false, stoch_is_bottoming = false
// Use temporary variables for the tuple assignment to avoid compiler errors with 'var' declared variables.
[temp_bull, temp_bear, temp_k, temp_peaking, temp_bottoming] = libStochDiv.f_calc(stoch_value, stochDivSettings)
stoch_bullishDivergence := temp_bull
stoch_bearishDivergence := temp_bear
stoch_div_k_val := temp_k
stoch_is_peaking := temp_peaking
stoch_is_bottoming := temp_bottoming

stoch_roc = ta.roc(stoch_div_k_val, 1)
price_roc = ta.roc(close, 1)
stoch_div_osc = price_roc - stoch_roc
stoch_div_osc_hist = stoch_div_osc - stoch_div_osc[1]
//} ========================

//{ VWAP Divergence }
groupVwapDiv = "VWAP Divergence"
vwapDiv_pivotLookbackLeft_1D  = input.int(1, title="Pivot Lookback Left (1D)", minval=1, group=groupVwapDiv, display=display.none)
vwapDiv_pivotLookbackLeft_12H = input.int(1, title="Pivot Lookback Left (12H)", minval=1, group=groupVwapDiv, display=display.none)
vwapDiv_pivotLookbackRight_1D = input.int(1, title="Pivot Lookback Right (1D)", minval=1, group=groupVwapDiv, display=display.none)
vwapDiv_pivotLookbackRight_12H= input.int(1, title="Pivot Lookback Right (12H)", minval=1, group=groupVwapDiv, display=display.none)

vwapDivSettings = libVwapDiv.VWAPDivergenceSettings.new()
vwapDivSettings.pivotLookbackLeft := utils.f_getParamForTimeframe_int(vwapDiv_pivotLookbackLeft_1D, vwapDiv_pivotLookbackLeft_12H, vwapDiv_pivotLookbackLeft_1D)
vwapDivSettings.pivotLookbackRight := utils.f_getParamForTimeframe_int(vwapDiv_pivotLookbackRight_1D, vwapDiv_pivotLookbackRight_12H, vwapDiv_pivotLookbackRight_1D)
vwapDivSettings.divergenceStrength := input.int(2, title="Divergence Strength (bars away)", minval=1, group=groupVwapDiv, display=display.none)

var float vwap_value = na
var bool vwap_bullishDivergence = false, vwap_bearishDivergence = false
[temp_vwap_bull, temp_vwap_bear, temp_vwap_val] = libVwapDiv.f_calc(vwapDivSettings)
vwap_bullishDivergence := temp_vwap_bull
vwap_bearishDivergence := temp_vwap_bear
vwap_value := temp_vwap_val
vwap_div_osc = price_roc - ta.roc(vwap_value, 1)

//{ Stoch and RSI range filter }
groupStochAndRSI               = "Stoch and RSI range filter Long Entry"
stochRSI_len_1D                = input.int(14, "Stoch and RSI length (1D)", minval=1, group=groupStochAndRSI, display=display.none)
stochRSI_len_12H               = input.int(14, "Stoch and RSI length (12H)", minval=1, group=groupStochAndRSI, display=display.none)
rsi_lowpass_filter             = input.int(30, "RSI Threshold for Low(30)", minval=1, group=groupStochAndRSI, display=display.none)
rsi_highpass_filter            = input.int(60, "RSI Threshold for High(60)", minval=1, group=groupStochAndRSI, display=display.none)
stochvalue_lowpass_filter      = input.int(37, "Stoch Value Threshold for Low(?)", minval=1, group=groupStochAndRSI, display=display.none)
stochvalue_highpass_filter     = input.int(70, "Stoch Value Threshold for High(?)", minval=1, group=groupStochAndRSI, display=display.none)

rsi_low_range_cond          = false
rsi_medium_range_cond       = false
rsi_high_range_cond         = false

// Calculate OSC for all supported timeframes unconditionally.
osc_1D = ta.rsi(osc_src, stochRSI_len_1D)
osc_12H = utils.f_dynamic_rsi(osc_src, utils.f_getParamForTimeframe_int(stochRSI_len_1D, stochRSI_len_12H, stochRSI_len_1D))

// Select the appropriate OSC value for the current timeframe.
osc = timeframe.period == "D" ? osc_1D : osc_12H

//{ RSI Divergence }
rsid_label = "RSI Divergence"
i_rsid_src            = input(close, title="RSID Source", group=rsid_label, display=display.none)
i_rsid_lookback_1D    = input.int(14, title="Look-back (1D)",  minval=1, step=1,group=rsid_label, display=display.none)
i_rsid_lookback_12H   = input.int(9, title="Look-back (12H)",  minval=1, step=1,group=rsid_label, display=display.none)
i_rsid_lookback       = utils.f_getParamForTimeframe_int(i_rsid_lookback_1D, i_rsid_lookback_12H, i_rsid_lookback_1D)
i_rsid_overbought_1D  = input.int(70, title="Overbought (1D)", minval=1, step=1, group=rsid_label, display=display.none)
i_rsid_overbought_12H = input.int(75, title="Overbought (12H)", minval=1, step=1, group=rsid_label, display=display.none)
i_rsid_overbought     = utils.f_getParamForTimeframe_int(i_rsid_overbought_1D, i_rsid_overbought_12H, i_rsid_overbought_1D)
i_rsid_oversold_1D    = input.int(30, title="Oversold (1D)", minval=1, step=1, group=rsid_label, display=display.none)
i_rsid_oversold_12H   = input.int(20, title="Oversold (12H)", minval=1, step=1, group=rsid_label, display=display.none)
i_rsid_oversold       = utils.f_getParamForTimeframe_int(i_rsid_oversold_1D, i_rsid_oversold_12H, i_rsid_oversold_1D)
i_rsid_len_1D         = input.int(14, minval=1, title="RSI Length (1D)", group=rsid_label, display=display.none)
i_rsid_len_12H        = input.int(22, minval=1, title="RSI Length (12H)", group=rsid_label, display=display.none)
i_rsid_res            = input.timeframe("", title="Oscillator resolution", group=rsid_label, display=display.none)

var int i_rsid_len = na
i_rsid_len                := utils.f_getParamForTimeframe_int(i_rsid_len_1D, i_rsid_len_12H, i_rsid_len_1D)

// RSI calculation
// Calculate RSI for all supported timeframes unconditionally.
rsid_lenUp_1D = ta.ema(math.max(ta.change(i_rsid_src), 0), i_rsid_len_1D)
rsid_lenDn_1D = ta.ema(-math.min(ta.change(i_rsid_src), 0), i_rsid_len_1D)
rsi_1D = rsid_lenDn_1D == 0 ? 100 : rsid_lenUp_1D == 0 ? 0 : 100 - (100 / (1 + rsid_lenUp_1D / rsid_lenDn_1D))
rsi_12H = utils.f_dynamic_rsi(i_rsid_src, i_rsid_len)

// Select the appropriate RSI value for the current timeframe.
rsi = timeframe.period == "D" ? rsi_1D : rsi_12H

// Calculate RSI with resolution
rsid_osc = request.security(syminfo.tickerid, i_rsid_res, rsi)

//} ========================

group_m2LeadingIndicator_calculations  = "M2 Leading Indicator Calculations"
m2LeadingIndicator_scalingLookback     = input.int(150, title="Scaling Lookback Period(150)", minval=2, group=group_m2LeadingIndicator_calculations, tooltip="Number of bars used to find the min/max values for scaling the M2 plots.", display=display.none)
i_m2LeadingIndicator_smoothingMethod   = input.string("Hull Moving Average", title="M2 Smoothing Method", options=["None", "Simple Moving Average", "Exponential Moving Average", "Hull Moving Average"], group="M2LI", display=display.none)
i_m2LeadingIndicator_barsToRightOfShortLength = input.int(10,"Bars from short length for diff/slope calculations(10)", group="M2LI", display=display.none, tooltip = "Value used in multiple entry and exit calculations, huge effect on performance")
i_m2LeadingIndicator_tinyOffset        = input.int(48, "Tiny offset, orange line(48)", group=group_m2LeadingIndicator_calculations, display=display.none)
i_m2LeadingIndicator_tinyOffset_smoothingLength = input.int(13, "Tiny Offset Smoothing Length(13)", group=group_m2LeadingIndicator_calculations, display=display.none)
i_m2LeadingIndicator_shortOffset       = input.int(64, "Short offset, orange line(64)", group=group_m2LeadingIndicator_calculations, display=display.none)
i_m2LeadingIndicator_shortOffset_smoothingLength = input.int(13, "Short Offset Smoothing Length(13)", group=group_m2LeadingIndicator_calculations, display=display.none)
i_m2LeadingIndicator_mediumOffset      = input.int(78, "Medium offset, red line", group=group_m2LeadingIndicator_calculations, display=display.none)
i_m2LeadingIndicator_mediumOffset_smoothingLength = input.int(16, "Medium Offset Smoothing Length", group=group_m2LeadingIndicator_calculations, display=display.none)
i_m2LeadingIndicator_longOffset        = input.int(92, "Long offset, yellow line(92)", group=group_m2LeadingIndicator_calculations, display=display.none)
i_m2LeadingIndicator_longOffset_smoothingLength = input.int(20, "Long Offset Smoothing Length", group=group_m2LeadingIndicator_calculations, display=display.none)
i_m2LeadingIndicator_riseFallLength    = input.int(3, "Length to use for calculating Rise/Fall", group=group_m2LeadingIndicator_calculations, display=display.none) // TODO may later want to have different lengths for different offsets?
i_m2LeadingIndicator_oneDayOffset      = input.int(1, "Adjustment factor for one day, unclear if scaling it is needed", group=group_m2LeadingIndicator_calculations, display=display.none)  
i_enable_timeframe_adjustment           = input.bool(true, title="Enable Time Frame Adjustment", group="General Setings",display=display.none, tooltip = "For timeframes shorter than 1 Day, adjusted to use more bars to keep same range of data as 1 day would")

if i_enable_timeframe_adjustment
    m2LeadingIndicator_scalingLookback                := int(m2LeadingIndicator_scalingLookback / timeframe_divisor) > 5000 ? 5000 : int(m2LeadingIndicator_scalingLookback/ timeframe_divisor)
    i_m2LeadingIndicator_barsToRightOfShortLength     := int(i_m2LeadingIndicator_barsToRightOfShortLength / timeframe_divisor) > 5000 ? 5000 : int(i_m2LeadingIndicator_barsToRightOfShortLength/ timeframe_divisor)
    i_m2LeadingIndicator_tinyOffset                   := int(i_m2LeadingIndicator_tinyOffset / timeframe_divisor) > 5000 ? 5000 : int(i_m2LeadingIndicator_tinyOffset/ timeframe_divisor)
    i_m2LeadingIndicator_shortOffset                  := int(i_m2LeadingIndicator_shortOffset / timeframe_divisor) > 5000 ? 5000 : int(i_m2LeadingIndicator_shortOffset / timeframe_divisor)
    i_m2LeadingIndicator_shortOffset_smoothingLength  := int(i_m2LeadingIndicator_shortOffset_smoothingLength / timeframe_divisor) > 5000 ? 5000 : int(i_m2LeadingIndicator_shortOffset_smoothingLength/ timeframe_divisor)
    i_m2LeadingIndicator_mediumOffset                 := int(i_m2LeadingIndicator_mediumOffset / timeframe_divisor) > 5000 ? 5000 : int(i_m2LeadingIndicator_mediumOffset / timeframe_divisor)
    i_m2LeadingIndicator_mediumOffset_smoothingLength := int(i_m2LeadingIndicator_mediumOffset_smoothingLength / timeframe_divisor) > 5000 ? 5000 : int(i_m2LeadingIndicator_mediumOffset_smoothingLength/ timeframe_divisor)
    i_m2LeadingIndicator_longOffset                   := int(i_m2LeadingIndicator_longOffset / timeframe_divisor) > 5000 ? 5000 : int(i_m2LeadingIndicator_longOffset / timeframe_divisor)
    i_m2LeadingIndicator_longOffset_smoothingLength   := int(i_m2LeadingIndicator_longOffset_smoothingLength / timeframe_divisor) > 5000 ? 5000 : int(i_m2LeadingIndicator_longOffset_smoothingLength/ timeframe_divisor)
    i_m2LeadingIndicator_riseFallLength               := int(i_m2LeadingIndicator_riseFallLength  / timeframe_divisor) > 5000 ? 5000 : int(i_m2LeadingIndicator_riseFallLength / timeframe_divisor)
    i_m2LeadingIndicator_oneDayOffset                 := int(i_m2LeadingIndicator_oneDayOffset  / timeframe_divisor) > 5000 ? 5000 : int(i_m2LeadingIndicator_oneDayOffset / timeframe_divisor)

m2_smoothed_tinyOffset = utils.f_ma(m2_US_EU_CN, i_m2LeadingIndicator_smoothingMethod, i_m2LeadingIndicator_tinyOffset_smoothingLength)
m2_smoothed_shortOffset     = utils.f_ma(m2_US_EU_CN, i_m2LeadingIndicator_smoothingMethod, i_m2LeadingIndicator_shortOffset_smoothingLength)

// Ensure scaling lookback is at least 2
valid_scaling_lookback = m2LeadingIndicator_scalingLookback < 2 ? 2 : m2LeadingIndicator_scalingLookback
m2_smoothed_tinyOffset_scaled   = utils.f_scale_ToRange(m2_smoothed_tinyOffset,  m2LeadingIndicator_scalingLookback, m2LeadingIndicator_scalingLookback)
m2_smoothed_shortOffset_scaled  = utils.f_scale_ToRange(m2_smoothed_shortOffset,  m2LeadingIndicator_scalingLookback, m2LeadingIndicator_scalingLookback)

// M2 Divergence Oscillator Calculation
m2_div_osc = libM3Div.f_calc_oscillator(m2_smoothed_tinyOffset_scaled, close)

m2_smoothedTiny_N_bars_out = m2_smoothed_tinyOffset_scaled[i_m2LeadingIndicator_tinyOffset - i_m2LeadingIndicator_barsToRightOfShortLength] // This value is from the past
m2_diff_abs_tinyOffset_to_future = m2_smoothedTiny_N_bars_out - m2_smoothed_tinyOffset_scaled[i_m2LeadingIndicator_tinyOffset] // This is the final value, no further offset needed.

activationPocWeights = libLongEntry.ActivationPocWeights.new()
activationPocWeights.w_stoch := i_w_stoch
activationPocWeights.w_macd_pred := i_w_macd_pred
activationPocWeights.w_osc := i_w_osc
activationPocWeights.w_macd_bullish := i_w_macd_bullish
activationPocWeights.w_m3_momentum := i_w_m3_momentum
activationPocWeights.w_m2_tiny := i_w_m2_tiny
activationPocWeights.w_rsid_osc := i_w_rsid_osc
activationPocWeights.w_stoch_div_osc := i_w_stoch_div_osc
activationPocWeights.w_vwap_div_osc := i_w_vwap_div_osc
activationPocWeights.w_stoch_peaking := i_w_stoch_peaking
activationPocWeights.w_stoch_bottoming := i_w_stoch_bottoming
activationPocWeights.w_m3_div_osc := i_w_m3_div_osc
activationPocWeights.w_m2_div_osc := i_w_m2_div_osc

// Calculate M3 Momentum
m3_momentum = m3_global_smoothed - m3_global_smoothed[i_m3_momentum_period]

activation_score_poc = libLongEntry.f_calculateActivation_poc(stoch_value, macd_prediction, osc, macd_flipped_bullish, m3_momentum, m2_diff_abs_tinyOffset_to_future, rsid_osc, stoch_div_osc, vwap_div_osc, stoch_is_peaking, stoch_is_bottoming, m3_div_osc, m2_div_osc, activationPocWeights)

activation_score_delta = activation_score_poc - activation_score_poc[1]

hline(0, "Zero Line", color=color.new(color.gray, 20), linestyle=hline.style_dashed)
hline(i_long_exit_activation_threshold, title="long_exit_threshold", color=color.new(color.fuchsia, 20), linestyle=hline.style_dashed, linewidth=1)
plot_activation_score = plot(activation_score_poc, title="activation_score_poc", color=color.new(color.blue, 0), linewidth=2)
hline(i_long_entry_activation_threshold, title="long_entry_threshold", color=color.new(color.blue, 20), linestyle=hline.style_dashed, linewidth=1)
plot(activation_score_delta, title="Activation Score Delta", color=color.new(color.orange, 0), linewidth=1, display=display.data_window)

// Plot component values to the data window for debugging
plot(macd_prediction, "Component: macd_prediction",display=display.data_window)
plot(macd_flipped_bullish ? 1.0 : 0.0, "Component: macd_flipped_bullish",display=display.data_window)

plot(osc, "Component: osc",display=display.data_window)
plot(rsid_osc, "Component: rsid_osc",display=display.data_window)

plot(m3_momentum, "Component: m3_momentum",display=display.data_window)
plot(m2_diff_abs_tinyOffset_to_future, "Component: m2_diff_abs_tinyOffset_to_future",display=display.data_window)

plot(stoch_value, "Component: stoch_value", color=color.fuchsia, display=display.data_window)
plot(stoch_div_osc, "Component: stoch_div_osc", color=color.fuchsia, linewidth=2, display=display.data_window) // hard to interpret what this signal is doing, maybe when it sticks around zero is a sell?
plot(stoch_div_osc_hist, "Component: stoch_div_osc_hist", display=display.data_window)

plot(stoch_is_peaking ? 1.0 : 0.0, "Component: stoch_is_peaking", display=display.data_window)
plot(stoch_is_bottoming ? 1.0 : 0.0, "Component: stoch_is_bottoming", display=display.data_window)
plot(vwap_div_osc, "Component: vwap_div_osc", color=color.purple, display=display.data_window)
plot(m3_div_osc, "Component: m3_div_osc", color=color.green, display=display.data_window)
plot(m2_div_osc, "Component: m2_div_osc", color=color.orange, display=display.data_window)

// Create plots for the thresholds to be used in the fill.
plot_long_exit_threshold = plot(i_long_exit_activation_threshold, display=display.none)
plot_long_entry_threshold = plot(i_long_entry_activation_threshold, display=display.none)

// Fill the area above the positive threshold.
fill(plot_activation_score, plot_long_exit_threshold, color = activation_score_poc > i_long_exit_activation_threshold ? color.new(color.fuchsia, 80) : na, title="Bullish Threshold Fill")

// Fill the area below the negative threshold.
fill(plot_activation_score, plot_long_entry_threshold, color = activation_score_poc < i_long_entry_activation_threshold ? color.new(color.blue, 80) : na, title="Bearish Threshold Fill")
