#ifndef PATTERN_HUNTER_MQH #define PATTERN_HUNTER_MQH #include "AgentBase.mqh" #define PH_BARS 50 #define PH_NUM_PATTERNS 21 // pattern codes -10 to +10 class PatternHunter : public IAgent { private: double histHurst[PH_BARS]; double histADX[PH_BARS]; double histMA[PH_BARS]; double histMom[PH_BARS]; double histConsensus[PH_BARS]; int barCount; int idx; // Distribuzioni empiriche di ogni agente RunningStats distHurst, distADX, distMA, distMom; // Distribuzioni empiriche delle differenze temporali RunningStats diffMom3, diffMA3; // Distribuzione empirica della somma MA+Mom (per normalizzazione combo) RunningStats sumMAMom; // Correlazione MA-Mom RunningCorrelation corrMAMom; // Pattern-specific win rate tracking RunningStats patternReturns[PH_NUM_PATTERNS]; int patternCounts[PH_NUM_PATTERNS]; int lastPatternCode; void Push(double &arr[], double val) { arr[idx] = val; } double Get(double &arr[], int lookback=0) const { int i = idx - lookback; if(i < 0) i += PH_BARS; if(i < 0 || i >= PH_BARS) return 0; return arr[i]; } double AgentThr(const RunningStats &ds) const { // Serve almeno 1/3 della finestra per avere una stima affidabile if(ds.Count() < PH_BARS / 3) return 1.0 / MathSqrt(MathMax(1, ds.Count())); // Minimo: SE della media (non può essere zero con dati finiti) return MathMax(1.0 / MathSqrt((double)MathMax(1, ds.Count())), ds.Std()); } double SafeDenom(double v, double fallback) const { double eps = DATA_EPS(fallback); return (MathAbs(v) > eps) ? v : fallback; } int SignCount(const double &zH, const double &zA, const double &zM, const double &zMom) { double tH = AgentThr(distHurst); double tA = AgentThr(distADX); double tM = AgentThr(distMA); double tM2 = AgentThr(distMom); int pos = 0, neg = 0; if(zH > tH) pos++; else if(zH < -tH) neg++; if(zA > tA) pos++; else if(zA < -tA) neg++; if(zM > tM) pos++; else if(zM < -tM) neg++; if(zMom > tM2) pos++; else if(zMom < -tM2) neg++; return pos - neg; } public: double patternZ; string currentPattern; double patternStrength; PatternHunter(string n="Hunter", double w=1.0) : IAgent(n, w), barCount(0), idx(0), patternZ(0), currentPattern("none"), patternStrength(0), distHurst(0.05, 30, 200), distADX(0.05, 30, 200), distMA(0.05, 30, 200), distMom(0.05, 30, 200), diffMom3(0.05, 20, 200), diffMA3(0.05, 20, 200), sumMAMom(0.05, 20, 200), corrMAMom(0.05, 10), lastPatternCode(0) { for(int i=0; i 2) { double dMom = mom - Get(histMom, 2); double dMa = ma - Get(histMA, 2); diffMom3.Update(dMom); diffMA3.Update(dMa); } sumMAMom.Update(ma + mom); corrMAMom.Update(ma, mom); // Soglie dinamiche per ogni agente double tH = AgentThr(distHurst); double tA = AgentThr(distADX); double tM = AgentThr(distMA); double tM2 = AgentThr(distMom); // Soglia prodotto basata su Std empirici double agreeThr = tM * tM2; double divergeThr = -tM * tM2; // Consensus per regime con Std empirico combinato double regimeSum = hurst + adx; double regimeThr = MathSqrt(tH * tH + tA * tA); // Variazioni temporali: Std empirico delle differenze reali double momDeltaThr = SafeDenom(diffMom3.Std(), tM2); double maDeltaThr = SafeDenom(diffMA3.Std(), tM); // Normalizzazione combo MA+Mom: Std empirico della somma double comboNorm = SafeDenom(sumMAMom.Std(), MathSqrt(tM*tM + tM2*tM2)); // Pattern detection int signScore = SignCount(hurst, adx, ma, mom); int consensusThr = activeSignals - 1; bool allBull = (signScore >= consensusThr); bool allBear = (signScore <= -consensusThr); bool maMomAgree = (ma * mom > agreeThr); bool maMomDiverge = (ma * mom < divergeThr); bool regimeTrend = regimeSum > regimeThr; bool regimeRange = regimeSum < -regimeThr; double momNow = mom; double mom3ago = Get(histMom, 2); double mom6ago = Get(histMom, 5); bool momAccel = (momNow > mom3ago + momDeltaThr && mom3ago > mom6ago + momDeltaThr); bool momDecel = (momNow < mom3ago - momDeltaThr && mom3ago < mom6ago - momDeltaThr); double maNow = ma; double ma3ago = Get(histMA, 2); bool maRising = (maNow > ma3ago + maDeltaThr); bool maFalling = (maNow < ma3ago - maDeltaThr); int pCode = 0; string pName = "none"; double pZ = 0; // Conteggio agenti attivi per la media (solo quelli che contribuiscono) double nAvg = (double)MathMax(1, activeSignals); if(allBull && maMomAgree && regimeTrend) { pCode = 10; pName = "perfect_bull"; pZ = (hurst + adx + ma + mom) / nAvg; } else if(allBear && maMomAgree && regimeTrend) { pCode = -10; pName = "perfect_bear"; pZ = (hurst + adx + ma + mom) / nAvg; } else if(maMomAgree && regimeTrend && momAccel) { pCode = 8; pName = "trend_accel"; pZ = (ma + mom) / comboNorm; } else if(maMomAgree && regimeTrend && momDecel) { pCode = 6; pName = "trend_fatigue"; double fatigueFactor = 1.0 - MathAbs(SHARED_trendStrength); pZ = (ma + mom) / comboNorm * fatigueFactor; } else if(regimeRange && maMomDiverge && MathAbs(mom) > tM2) { pCode = 7; pName = "range_reversal"; pZ = -mom; } else if(regimeRange && maMomAgree && MathAbs(mom) < tM2) { pCode = 3; pName = "range_quiet"; pZ = 0; } else if(maMomDiverge && MathAbs(mom) > tM2 && MathAbs(ma) < tM) { pCode = 5; pName = "momentum_spike"; double trust = 1.0 - MathMin(1.0, MathAbs(ma) / SafeDenom(tM, 1.0/MathSqrt(MathMax(1, (double)PH_BARS)))); pZ = mom * trust; } else if(regimeTrend && maMomDiverge && MathAbs(ma) > tM) { pCode = 4; pName = "pullback"; pZ = ma; } else if(signScore > 0) { pCode = 2; pName = "leaning_bull"; double margin = (signScore - 1) / (nAvg - 1.0); pZ = MathTanh(margin); } else if(signScore < 0) { pCode = -2; pName = "leaning_bear"; double margin = (-signScore - 1) / (nAvg - 1.0); pZ = -MathTanh(margin); } else if(barCount < PH_BARS) { pCode = 0; pName = "warming"; pZ = 0; } currentPattern = pName; patternZ = pZ; patternStrength = 1.0 - MathExp(-MathAbs(pZ)); SHARED_patternCode = pCode; SHARED_patternName = pName; lastPatternCode = pCode; lastZScore = CalibrateZ(pZ); } void Learn(double predictedZ, double actualReturnZ) override { IAgent::Learn(predictedZ, actualReturnZ); int codeIdx = lastPatternCode + 10; if(codeIdx >= 0 && codeIdx < PH_NUM_PATTERNS) { patternReturns[codeIdx].Update(actualReturnZ); patternCounts[codeIdx]++; } } void Save(int fh) const override { IAgent::Save(fh); for(int i=0; i