forked from chiki2bum2/SniperGold_ML
203 lines
6.9 KiB
MQL5
203 lines
6.9 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| AF_Engine2_Aggregator.mqh |
| |||
//| Project : Algo Forge (refactor total) |
| |||
//| Sumber inspirasi: SniperGold SMC Pro+ (c) Waseem Shahrukh |
| |||
//| https://www.mql5.com/en/code/75466 |
| |||
//+------------------------------------------------------------------+
| |||
//| Engine 2 - AGREGATOR SINYAL (terpisah dari agen) |
| |||
//| |
| |||
//| - Menggabungkan output 4 agen (N/C/E/P) menjadi sinyal final. |
| |||
//| - Agen TIDAK saling tahu; agregator adalah SATU-SATUNYA tempat |
| |||
//| output agen dipertemukan. |
| |||
//| - Bobot dinamis: bobot dasar per agen x confidence, dengan |
| |||
//| penguatan (boost) untuk agen yang searah dengan mayoritas. |
| |||
//| - Output: dir BUY/SELL/WAIT + buy/sell/bias/score/confidence + |
| |||
//| entry/SL/TP (dari bar tertutup & ATR Engine 1) + alasan. |
| |||
//| - Non-repaint: semua level dihitung dari bar tertutup Engine 1. |
| |||
//+------------------------------------------------------------------+
| |||
#ifndef AF_ENGINE2_AGGREGATOR_MQH
| |||
#define AF_ENGINE2_AGGREGATOR_MQH
| |||
| |||
#include "AF_Engine2_Agents.mqh"
| |||
| |||
//------------------------------------------------------------------
| |||
// Output agregator (untuk Engine 3 display / konsumen sinyal)
| |||
//------------------------------------------------------------------
| |||
struct AFAggOut
| |||
{
| |||
int dir; // +1 buy / -1 sell / 0 wait
| |||
double buy; // dukungan buy agregat [0,1]
| |||
double sell; // dukungan sell agregat [0,1]
| |||
double bias; // buy-sell [-1,1]
| |||
double score; // |bias| kekuatan sinyal [0,1]
| |||
double confidence; // [0,1] (dukungan + kesepakatan)
| |||
double entry; // level entry (close bar tertutup)
| |||
double sl; // stop loss (ATR-based)
| |||
double tp; // take profit (ATR-based)
| |||
bool hasLevels; // true bila entry/sl/tp terhitung
| |||
int activeAgents; // jumlah agen dengan confidence>0.05
| |||
double weights[4]; // bobot efektif per agen (N,C,E,P)
| |||
int agentDir[4]; // arah tiap agen
| |||
string agentReason[4]; // alasan tiap agen (untuk display)
| |||
string reason; // ringkasan
| |||
};
| |||
| |||
//------------------------------------------------------------------
| |||
// AFAggregator - penggabung output 4 agen (bobot dinamis 2-pass)
| |||
//------------------------------------------------------------------
| |||
class AFAggregator
| |||
{
| |||
public:
| |||
void Compute(const AFEngine1MTF &e1,int slotE,
| |||
const AFSignalOut &n,const AFSignalOut &c,
| |||
const AFSignalOut &e,const AFSignalOut &p,
| |||
AFAggOut &out) const;
| |||
};
| |||
| |||
void AFAggregator::Compute(const AFEngine1MTF &e1,int slotE,
| |||
const AFSignalOut &n,const AFSignalOut &c,
| |||
const AFSignalOut &e,const AFSignalOut &p,
| |||
AFAggOut &out) const
| |||
{
| |||
AFSignalOut ag[4];
| |||
ag[0]=n; ag[1]=c; ag[2]=e; ag[3]=p;
| |||
double baseW[4];
| |||
baseW[0]=AF_AGG_W_N;
| |||
baseW[1]=AF_AGG_W_C;
| |||
baseW[2]=AF_AGG_W_E;
| |||
baseW[3]=AF_AGG_W_P;
| |||
| |||
// pass 1: bias awal (bobot dasar x confidence)
| |||
double w1[4];
| |||
double W1=0.0;
| |||
for(int i=0;i<4;i++)
| |||
{
| |||
w1[i]=baseW[i]*MathMax(ag[i].confidence,0.0);
| |||
W1+=w1[i];
| |||
}
| |||
double bias1=0.0;
| |||
if(W1>0.0)
| |||
{
| |||
for(int i=0;i<4;i++) bias1+=w1[i]*ag[i].bias;
| |||
bias1/=W1;
| |||
}
| |||
int majDir=(bias1> AF_E2_DIR_TOL)? 1 : (bias1< -AF_E2_DIR_TOL)? -1 : 0;
| |||
| |||
// pass 2: bobot dinamis dengan penguatan kesepakatan (agreement)
| |||
double w2[4];
| |||
double W2=0.0;
| |||
for(int i=0;i<4;i++)
| |||
{
| |||
double boost=1.0;
| |||
if(majDir!=0 && ag[i].dir==majDir) boost=1.5;
| |||
w2[i]=baseW[i]*MathMax(ag[i].confidence,0.0)*boost;
| |||
W2+=w2[i];
| |||
}
| |||
double buy=0.0, sell=0.0;
| |||
if(W2>0.0)
| |||
{
| |||
for(int i=0;i<4;i++)
| |||
{
| |||
buy +=w2[i]*ag[i].buy;
| |||
sell+=w2[i]*ag[i].sell;
| |||
}
| |||
buy/=W2; sell/=W2;
| |||
}
| |||
out.buy =AF_Clamp01(buy);
| |||
out.sell=AF_Clamp01(sell);
| |||
out.bias=out.buy-out.sell;
| |||
out.score=MathAbs(out.bias);
| |||
out.dir=0;
| |||
if(out.bias>=AF_AGG_BUY_TH && out.buy>=AF_AGG_MIN_SUP) out.dir=1;
| |||
else if(out.bias<=-AF_AGG_BUY_TH && out.sell>=AF_AGG_MIN_SUP) out.dir=-1;
| |||
| |||
int agree=0;
| |||
for(int i=0;i<4;i++) if(out.dir!=0 && ag[i].dir==out.dir) agree++;
| |||
double confBase=MathMax(out.buy,out.sell);
| |||
out.confidence=(out.dir==0)? confBase : MathMin(1.0,confBase*(0.7+0.1*agree));
| |||
| |||
out.activeAgents=0;
| |||
for(int i=0;i<4;i++)
| |||
{
| |||
out.agentDir[i]=ag[i].dir;
| |||
out.agentReason[i]=ag[i].reason;
| |||
out.weights[i]=w2[i];
| |||
if(ag[i].confidence>0.05) out.activeAgents++;
| |||
}
| |||
| |||
// level entry/SL/TP (non-repaint: close bar tertutup + ATR Engine 1)
| |||
out.entry=0.0; out.sl=0.0; out.tp=0.0; out.hasLevels=false;
| |||
if(e1.IsReady(slotE))
| |||
{
| |||
double close=e1.Close(slotE,0);
| |||
double atr=e1.ATR(slotE,14);
| |||
if(close>0.0 && atr>0.0)
| |||
{
| |||
out.entry=close;
| |||
out.hasLevels=true;
| |||
if(out.dir>0)
| |||
{
| |||
out.sl=close-AF_AGG_SL_ATR*atr;
| |||
out.tp=close+AF_AGG_TP_ATR*atr;
| |||
}
| |||
else if(out.dir<0)
| |||
{
| |||
out.sl=close+AF_AGG_SL_ATR*atr;
| |||
out.tp=close-AF_AGG_TP_ATR*atr;
| |||
}
| |||
}
| |||
}
| |||
| |||
// ringkasan
| |||
out.reason=(out.dir>0)? "BUY" : (out.dir<0)? "SELL" : "WAIT";
| |||
out.reason+="[bias="+DoubleToString(out.bias,2)+"]";
| |||
for(int i=0;i<4;i++)
| |||
{
| |||
string tag=(ag[i].dir>0)? "+" : (ag[i].dir<0)? "-" : "~";
| |||
out.reason+=" "+ag[i].name+":"+tag;
| |||
}
| |||
out.reason+=" | ";
| |||
for(int i=0;i<4;i++)
| |||
{
| |||
if(ag[i].dir!=0 && ag[i].reason!="")
| |||
{
| |||
out.reason+=ag[i].name+"("+ag[i].reason+") ";
| |||
if(StringLen(out.reason)>160)
| |||
{
| |||
out.reason=StringSubstr(out.reason,0,157)+"...";
| |||
break;
| |||
}
| |||
}
| |||
}
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| AFEngine2Signals - facade Engine 2 (4 agen + agregator) |
| |||
//| Satu panggilan: input Engine 1 + 4 slot -> output agen & final. |
| |||
//+------------------------------------------------------------------+
| |||
class AFEngine2Signals
| |||
{
| |||
private:
| |||
AFAgentNarrative m_n;
| |||
AFAgentContext m_c;
| |||
AFAgentEntry m_e;
| |||
AFAgentPriceAction m_p;
| |||
AFAggregator m_agg;
| |||
public:
| |||
void Compute(const AFEngine1MTF &e1,int sN,int sC,int sE,int sP,
| |||
AFSignalOut &oN,AFSignalOut &oC,AFSignalOut &oE,AFSignalOut &oP,
| |||
AFAggOut &agg) const;
| |||
};
| |||
| |||
void AFEngine2Signals::Compute(const AFEngine1MTF &e1,int sN,int sC,int sE,int sP,
| |||
AFSignalOut &oN,AFSignalOut &oC,AFSignalOut &oE,AFSignalOut &oP,
| |||
AFAggOut &agg) const
| |||
{
| |||
m_n.Compute(e1,sN,oN);
| |||
m_c.Compute(e1,sC,oC);
| |||
m_e.Compute(e1,sE,oE);
| |||
m_p.Compute(e1,sP,oP);
| |||
m_agg.Compute(e1,sE,oN,oC,oE,oP,agg);
| |||
}
| |||
| |||
#endif // AF_ENGINE2_AGGREGATOR_MQH
|