I believe we have arrived to a very significate waypoint in our contribution to Zorro Project, and we are about to make a massive step forward.

This machine learning–enhanced version of the MMI indicator improves it by making it adaptive, rather than using fixed smoothing and parameters.

Here’s what it adds:

Self-learning behavior

The indicator looks at its last 5 values and uses a small neural network (perceptron) to predict the next change in MMI.

It learns as the market evolves, adapting automatically without manual parameter tuning.

Dynamic responsiveness

If the ML model predicts stable, low-noise conditions, the indicator reduces smoothing so it reacts faster to market changes.

If the model predicts choppy or manipulated conditions, the indicator smooths itself more, filtering out noise.

Better visualization of market regimes

The MMI line now responds differently to quiet vs. volatile markets, making the high and low zones (0.3/0.7) more reliable as signals.

Code
// === 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);
}

Last edited by TipmyPip; 08/08/25 19:28.