Files
TR_Agent/MQL5/Experts/MultiAgentTest/Agents/MomentumAgent.mqh
T

148 lines
4.7 KiB
Plaintext

#ifndef MOMENTUM_AGENT_MQH
#define MOMENTUM_AGENT_MQH
#include "AgentBase.mqh"
#include "../Core/PeriodCalculator.mqh"
class MomentumAgent : public IAgent {
private:
RunningStats accelStats;
int period;
int minPeriod, maxPeriod;
int momHandle;
int lastMomPeriod;
double lastZ1; // mom z-score
double lastZ2; // accel z-score
RunningCorrelation momCorr;
RunningCorrelation accelCorr;
// Cache per Interact (ri-calcolo con regime fresco)
int m_basePeriod;
void Recreate(int p) {
if(momHandle != INVALID_HANDLE) IndicatorRelease(momHandle);
momHandle = iMomentum(symbol, timeframe, p, PRICE_CLOSE);
lastMomPeriod = p;
}
double GetMom(int shift=0) {
double buf[];
ArraySetAsSeries(buf, true);
if(CopyBuffer(momHandle, 0, shift, 1, buf) < 1) return 0;
return buf[0];
}
public:
MomentumAgent(string n="Momentum", double w=1.0, int minP=6, int maxP=40)
: IAgent(n, w), accelStats(0.05, 30, 500),
period(14), minPeriod(minP), maxPeriod(maxP),
momHandle(INVALID_HANDLE), lastMomPeriod(0),
lastZ1(0), lastZ2(0), momCorr(0.1, 5), accelCorr(0.1, 5) { signalStats.SetR(2.0); }
void Init(string sym, ENUM_TIMEFRAMES tf) override {
IAgent::Init(sym, tf);
momHandle = INVALID_HANDLE;
lastMomPeriod = 0;
}
void Release() override {
if(momHandle != INVALID_HANDLE) IndicatorRelease(momHandle);
momHandle = INVALID_HANDLE;
}
double Analyze(const MarketData &data) override {
m_basePeriod = PeriodCalculator::AutoPeriod(data, minPeriod, maxPeriod);
RecomputeWithRegime(SHARED_regimeConsensus, SHARED_regimeAgreement);
return lastZScore;
}
void RecomputeWithRegime(double regime, double agreement) {
double trendStr = MathAbs(regime);
double maxDecrease = 1.0 - (double)minPeriod / MathMax(minPeriod, m_basePeriod);
double periodMult = 1.0 - trendStr * agreement * maxDecrease;
int newPeriod = (int)MathRound(m_basePeriod * periodMult);
if(newPeriod < minPeriod) newPeriod = minPeriod;
if(newPeriod > maxPeriod) newPeriod = maxPeriod;
if(newPeriod != period) {
period = newPeriod;
if(momHandle != INVALID_HANDLE && period != lastMomPeriod)
Recreate(period);
} else if(momHandle == INVALID_HANDLE || period != lastMomPeriod) {
Recreate(period);
}
double mom = GetMom(0) - 100.0;
double momPv = GetMom(1) - 100.0;
signalStats.Update(mom);
double accel = mom - momPv;
accelStats.Update(accel);
double z1 = signalStats.ZScore(mom);
double z2 = accelStats.ZScore(accel);
lastZ1 = z1;
lastZ2 = z2;
double wLevel, wAccel;
if(momCorr.Ready() && accelCorr.Ready()) {
double r1 = MathMax(0.0, momCorr.Correlation());
double r2 = MathMax(0.0, accelCorr.Correlation());
double sumR = r1 + r2 + DATA_EPS(r1 + r2);
wLevel = r1 / sumR;
wAccel = 1.0 - wLevel;
} else {
double s1 = signalStats.Std();
double s2 = accelStats.Std();
double epsSum = DATA_EPS(MathMax(s1, s2));
wLevel = (s1 + s2 > epsSum) ? s1 / (s1 + s2) : 1.0 / 2.0;
wAccel = 1.0 - wLevel;
}
double norm = MathSqrt(wLevel*wLevel + wAccel*wAccel);
lastZScore = (wLevel * z1 + wAccel * z2) / norm;
lastZScore = CalibrateZ(lastZScore);
lastRawSignal = mom;
}
void Interact(IAgent *&allAgents[], int count) override {
// Rilegge regime fresco (dopo Interact di Consensus) e ri-calcola
RecomputeWithRegime(SHARED_regimeConsensus, SHARED_regimeAgreement);
}
void Learn(double predictedZ, double actualReturnZ) override {
IAgent::Learn(predictedZ, actualReturnZ);
momCorr.Update(lastZ1, actualReturnZ);
accelCorr.Update(lastZ2, actualReturnZ);
}
void Save(int fh) const override {
IAgent::Save(fh);
accelStats.Save(fh);
momCorr.Save(fh);
accelCorr.Save(fh);
}
void Load(int fh) override {
IAgent::Load(fh);
accelStats.Load(fh);
momCorr.Load(fh);
accelCorr.Load(fh);
}
void Reset() override {
IAgent::Reset();
accelStats.Reset();
momCorr.Reset();
accelCorr.Reset();
lastZ1 = 0; lastZ2 = 0;
}
string SignalInfo() const override {
return name + " z=" + StringFormat("%+.3f", lastZScore)
+ " period=" + (string)period
+ " " + signalStats.ToString();
}
};
#endif