// === Config ===
#define INPUT_SIZE 5 // Number of past MMI points as ML features
#define TRAIN_BARS 500 // Training period for ML model
// === Globals ===
int PeriodMax = 0;
// === Helper Functions ===
var clamp(var value, var minv, var maxv)
{
if (value < minv) return minv;
if (value > maxv) return maxv;
return value;
}
int adaptiveWinLength()
{
var p = priceClose();
if (p == 0) return 20; // safety
var atr_val = ATR(14);
int w = round(50 * (atr_val / p));
return max(10, w);
}
var sineWave()
{
return sin(2*PI*Bar/20.); // SINE_LEN = 20
}
var spectralEnergy(int baseWin)
{
static var* lowSeries;
static var* highSeries;
var lowBand = EMA(priceClose(),34) - EMA(priceClose(),89);
var highBand = priceClose() - EMA(priceClose(),8);
lowSeries = series(lowBand);
highSeries = series(highBand);
var eLow = Variance(lowSeries, baseWin);
var eHigh = Variance(highSeries, baseWin);
var denom = eHigh + eLow + 1e-6;
var spectralRatio = eHigh / denom;
return clamp(spectralRatio,0,1);
}
var predictabilityMI(int window)
{
static var* priceSeries;
priceSeries = series(priceClose());
var x1 = priceClose(1);
var x2 = priceClose(2);
var y = priceClose();
var s_x1 = EMA(x1, window);
var s_x2 = EMA(x2, window);
var s_y = EMA(y, window);
var s_x1x1 = EMA(x1*x1, window);
var s_x2x2 = EMA(x2*x2, window);
var s_x1x2 = EMA(x1*x2, window);
var s_x1y = EMA(x1*y, window);
var s_x2y = EMA(x2*y, window);
var denom = s_x1x1*s_x2x2 - s_x1x2*s_x1x2;
var a = ifelse(denom != 0, (s_x2x2*s_x1y - s_x1x2*s_x2y)/denom, 0);
var b = ifelse(denom != 0, (s_x1x1*s_x2y - s_x1x2*s_x1y)/denom, 0);
var y_hat = a*x1 + b*x2;
var residual = y - y_hat;
var mse_pred = EMA(residual*residual, window);
var var_price = Variance(priceSeries, 50);
var ratio = ifelse(var_price > 0, mse_pred/var_price, 0);
return clamp(ratio,0,1);
}
var sineMI(int window)
{
static var* priceSeries;
priceSeries = series(priceClose());
var s = sineWave();
var price = priceClose();
var s_dev = s - EMA(s, window);
var p_dev = price - EMA(price, window);
var mse_sin = EMA((p_dev - s_dev)*(p_dev - s_dev), window);
var var_pr = Variance(priceSeries, 50);
var ratio = ifelse(var_pr > 0, mse_sin/var_pr, 0);
return clamp(ratio,0,1);
}
// === Main Indicator (Adaptive MMI) ===
function run()
{
set(PLOTNOW);
// Ensure enough history for all components and ML
LookBack = max( max(90, 50), INPUT_SIZE + 6 ); // EMA(89) & Variance(50) & features depth
BarPeriod = 60; // example; set to your actual bar size
if (Bar < max(LookBack, TRAIN_BARS)) return;
int win = adaptiveWinLength();
// --- Base MMI Components ---
var mi_sine = sineMI(win);
var mi_pred = predictabilityMI(win);
var mi_spec = spectralEnergy(50);
var cmi_raw = (mi_sine + mi_pred + mi_spec)/3;
// --- Store MMI history for ML ---
static var* mmiSeries;
mmiSeries = series(EMA(cmi_raw,5));
// Make sure series depth is sufficient
if (mmiSeries[INPUT_SIZE] == 0 && Bar < LookBack + INPUT_SIZE + 2) return;
// --- Build ML Features (past INPUT_SIZE values) ---
var features[INPUT_SIZE];
int i;
for(i=0; i<INPUT_SIZE; i++)
features[i] = mmiSeries[i+1]; // strictly past values
// --- Predict the next change in MMI using ML ---
// Train once, then reuse model each bar (Retrain=0). You can switch to Retrain=1 for rolling retrain.
var predicted_delta = adviseLong(TRAIN_BARS, 0, features, INPUT_SIZE);
// --- Normalize and control adaptivity ---
var norm_delta = clamp(predicted_delta, -1, 1); // keep it bounded
var adaptFactor = clamp(1 - fabs(norm_delta), 0.4, 0.9);
// Integer, bounded smoothing period for EMA
int adaptPeriod = (int)round(5./adaptFactor);
adaptPeriod = max(2, min(50, adaptPeriod)); // guard rails
// --- Compute the adaptive MMI (bounded 0-1) ---
var adaptiveMMI = clamp(EMA(cmi_raw, adaptPeriod), 0, 1);
// --- Plot the indicator ---
plot("Adaptive MMI", adaptiveMMI, LINE, RED);
plot("Predicted ?", norm_delta, LINE, BLUE);
plot("Low", 0.3, LINE, GREEN);
plot("High", 0.7, LINE, ORANGE);
}