148 lines
4.7 KiB
Plaintext
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
|