618 行
26 KiB
MQL5
618 行
26 KiB
MQL5
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| ADWyckoffEventStream.mq5 |
|
||
|
|
//| Wyckoff Event Stream v3.2 |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
#property copyright "AD Institutional Indicators"
|
||
|
|
#property link ""
|
||
|
|
#property version "3.2"
|
||
|
|
#property description "AD Wyckoff Event Stream — smart labels, filled zones"
|
||
|
|
#property indicator_chart_window
|
||
|
|
#property indicator_buffers 14
|
||
|
|
#property indicator_plots 14
|
||
|
|
|
||
|
|
// Plot 0: EventCode (-7..+7) = BufEvent[0] — primary export buffer
|
||
|
|
#property indicator_label1 "EventCode"
|
||
|
|
#property indicator_type1 DRAW_LINE
|
||
|
|
#property indicator_color1 clrDimGray
|
||
|
|
#property indicator_width1 1
|
||
|
|
|
||
|
|
// Plot 1: EventPhase (-7..+7) = BufPhase[1]
|
||
|
|
#property indicator_label2 "EventPhase"
|
||
|
|
#property indicator_type2 DRAW_LINE
|
||
|
|
#property indicator_color2 clrDodgerBlue
|
||
|
|
#property indicator_width2 1
|
||
|
|
|
||
|
|
// Plot 2: ZoneTop = BufTop[2]
|
||
|
|
#property indicator_label3 "ZoneTop"
|
||
|
|
#property indicator_type3 DRAW_LINE
|
||
|
|
#property indicator_color3 clrLime
|
||
|
|
#property indicator_width3 1
|
||
|
|
|
||
|
|
// Plot 3: ZoneBottom = BufBot[3]
|
||
|
|
#property indicator_label4 "ZoneBottom"
|
||
|
|
#property indicator_type4 DRAW_LINE
|
||
|
|
#property indicator_color4 clrOrangeRed
|
||
|
|
#property indicator_width4 1
|
||
|
|
|
||
|
|
// Plot 4: EventPrice (close price when event active) = BufColor[4]
|
||
|
|
#property indicator_label5 "EventPrice"
|
||
|
|
#property indicator_type5 DRAW_LINE
|
||
|
|
#property indicator_color5 clrSilver
|
||
|
|
#property indicator_width5 1
|
||
|
|
|
||
|
|
// Plot 5: StructuralPhase (-5..+5)
|
||
|
|
#property indicator_label6 "StructuralPhase"
|
||
|
|
#property indicator_type6 DRAW_LINE
|
||
|
|
#property indicator_color6 clrGold
|
||
|
|
#property indicator_width6 1
|
||
|
|
|
||
|
|
// Plot 6: CHoCH Trend->Range / Range->Trend
|
||
|
|
#property indicator_label7 "CHoCHTrendToRange"
|
||
|
|
#property indicator_type7 DRAW_LINE
|
||
|
|
#property indicator_color7 clrAqua
|
||
|
|
#property indicator_width7 1
|
||
|
|
|
||
|
|
// Plot 7: CHoCH Range->Trend
|
||
|
|
#property indicator_label8 "CHoCHRangeToTrend"
|
||
|
|
#property indicator_type8 DRAW_LINE
|
||
|
|
#property indicator_color8 clrLime
|
||
|
|
#property indicator_width8 1
|
||
|
|
|
||
|
|
// Plot 8..11: Sloped structure classifications
|
||
|
|
#property indicator_label9 "SlopeAccumulationBullish"
|
||
|
|
#property indicator_type9 DRAW_LINE
|
||
|
|
#property indicator_color9 clrGreen
|
||
|
|
#property indicator_width9 1
|
||
|
|
|
||
|
|
#property indicator_label10 "SlopeAccumulationBearish"
|
||
|
|
#property indicator_type10 DRAW_LINE
|
||
|
|
#property indicator_color10 clrRed
|
||
|
|
#property indicator_width10 1
|
||
|
|
|
||
|
|
#property indicator_label11 "SlopeDistributionBullish"
|
||
|
|
#property indicator_type11 DRAW_LINE
|
||
|
|
#property indicator_color11 clrGreen
|
||
|
|
#property indicator_width11 1
|
||
|
|
|
||
|
|
#property indicator_label12 "SlopeDistributionBearish"
|
||
|
|
#property indicator_type12 DRAW_LINE
|
||
|
|
#property indicator_color12 clrRed
|
||
|
|
#property indicator_width12 1
|
||
|
|
|
||
|
|
// Plot 12..13: Continuation classification
|
||
|
|
#property indicator_label13 "Reaccumulation"
|
||
|
|
#property indicator_type13 DRAW_LINE
|
||
|
|
#property indicator_color13 clrDodgerBlue
|
||
|
|
#property indicator_width13 1
|
||
|
|
|
||
|
|
#property indicator_label14 "Redistribution"
|
||
|
|
#property indicator_type14 DRAW_LINE
|
||
|
|
#property indicator_color14 clrOrange
|
||
|
|
#property indicator_width14 1
|
||
|
|
|
||
|
|
//=== INPUTS ===
|
||
|
|
input int InpLookback = 50;
|
||
|
|
input int InpZigZag = 3;
|
||
|
|
input double InpVolClimax = 2.5;
|
||
|
|
input double InpVolHigh = 1.5;
|
||
|
|
input double InpRangeClimax = 1.8;
|
||
|
|
input double InpRangeSignificant = 1.2;
|
||
|
|
input double InpSTVolRatio = 0.6;
|
||
|
|
input double InpATR = 0.5;
|
||
|
|
input int InpContextMode = 0; // 0=FixedBars, 1=Session
|
||
|
|
input int InpSessionType = 5; // 1..10
|
||
|
|
input int InpSessionCount = 1; // 1..20
|
||
|
|
|
||
|
|
//=== 14 BUFFERS (order: Event, Phase, Top, Bot, Color, StructuralPhase, CHoCHTrendToRange, CHoCHRangeToTrend, slope classes, continuation classes) ===
|
||
|
|
double BufEvent[],BufPhase[],BufTop[],BufBot[],BufColor[],BufStruct[],BufChochTR[],BufChochRT[],BufSlopeABull[],BufSlopeABear[],BufSlopeDBull[],BufSlopeDBear[],BufReacc[],BufRedis[];
|
||
|
|
|
||
|
|
//=== HISTORICAL (chronological: index 0 = oldest bar) ===
|
||
|
|
double H[],L[],C[],V[],NR[],NV[],CP[],AT[];
|
||
|
|
int PT[];double PP[],RMn[],RMx[];
|
||
|
|
int gLB,gZZ;
|
||
|
|
double gVCM,gVHM,gRCM,gRSM,gSVR,gATM;
|
||
|
|
int gContextMode,gSessionType,gSessionCount;
|
||
|
|
//=== Pivot cache for O(1) Trend() ===
|
||
|
|
int g_pH1=-1,g_pH2=-1; double g_pH1P=0,g_pH2P=0;
|
||
|
|
int g_pL1=-1,g_pL2=-1; double g_pL1P=0,g_pL2P=0;
|
||
|
|
#define PFX "AWY_"
|
||
|
|
|
||
|
|
// Segment descriptor for post-processing
|
||
|
|
struct Seg {int ev;datetime t1,t2;double top,bot,hi,lo;};
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
int ColorIdx(int code){
|
||
|
|
switch(code){case 1:return 0;case 2:return 1;case 3:return 2;case 4:return 3;case 5:return 4;case 6:return 5;case 7:return 6;case -1:return 7;case -2:return 8;case -3:return 9;case -4:return 10;case -5:return 11;case -6:return 12;case -7:return 13;default:return 0;}
|
||
|
|
}
|
||
|
|
string EvName(int code){
|
||
|
|
switch(code){case 1:return"PS";case 2:return"SC";case 3:return"AR";case 4:return"ST";case 5:return"Spring";case 6:return"LPS";case 7:return"SOS";case -1:return"PSY";case -2:return"BC";case -3:return"ARB";case -4:return"STB";case -5:return"UTAD";case -6:return"LPSY";case -7:return"SOW";default:return"";}
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void PrecompMinMax(int bi){
|
||
|
|
int wS=MathMax(0,bi-gLB+1);
|
||
|
|
if(bi==0){RMn[bi]=L[bi];RMx[bi]=H[bi];return;}
|
||
|
|
RMn[bi]=MathMin(L[bi],RMn[bi-1]);RMx[bi]=MathMax(H[bi],RMx[bi-1]);
|
||
|
|
if(bi-wS>0&&RMn[bi]==L[MathMax(wS-1,0)]){RMn[bi]=DBL_MAX;for(int k=wS;k<=bi;k++){if(L[k]<RMn[bi])RMn[bi]=L[k];}}
|
||
|
|
if(bi-wS>0&&RMx[bi]==H[MathMax(wS-1,0)]){RMx[bi]=-DBL_MAX;for(int k=wS;k<=bi;k++){if(H[k]>RMx[bi])RMx[bi]=H[k];}}
|
||
|
|
}
|
||
|
|
bool IsNewLow(int bi,int lbS){return L[bi]<=RMn[bi]&&L[bi]<RMn[MathMax(lbS,MathMax(bi-1,0))];}
|
||
|
|
bool IsNewHigh(int bi,int lbS){return H[bi]>=RMx[bi]&&H[bi]>RMx[MathMax(lbS,MathMax(bi-1,0))];}
|
||
|
|
|
||
|
|
void PrecompNorm(int bi){
|
||
|
|
double hi=H[bi],lo=L[bi],cl=C[bi];
|
||
|
|
double bv=(double)MathMax(V[bi],1);double br=hi-lo;if(br<=0)br=0.001;
|
||
|
|
int wS=MathMax(0,bi-gLB+1),ct=bi-wS+1;
|
||
|
|
double sr=0,sv=0;
|
||
|
|
for(int k=wS;k<=bi;k++){sr+=H[k]-L[k];sv+=(double)MathMax(V[k],1);}
|
||
|
|
double avgr=(ct>0)?sr/ct:br,avgv=(ct>0)?sv/ct:bv;
|
||
|
|
if(avgr<=0)avgr=br;if(avgv<=0)avgv=1.0;
|
||
|
|
NR[bi]=br/avgr;NV[bi]=bv/avgv;CP[bi]=(br>0)?(cl-lo)/br:0.5;AT[bi]=avgr;
|
||
|
|
}
|
||
|
|
|
||
|
|
void PrecompPivot(int bi){
|
||
|
|
PT[bi]=0;PP[bi]=0.0;
|
||
|
|
double hj=H[bi],lj=L[bi];int lb=MathMax(0,bi-gZZ);
|
||
|
|
bool isH=true;for(int k=lb;k<bi;k++){if(H[k]>hj){isH=false;break;}}
|
||
|
|
if(isH){PT[bi]=(bi<gZZ)?2:1;PP[bi]=hj;CachePivot(bi);return;}
|
||
|
|
bool isL=true;for(int k=lb;k<bi;k++){if(L[k]<lj){isL=false;break;}}
|
||
|
|
if(isL){PT[bi]=(bi<gZZ)?-2:-1;PP[bi]=lj;CachePivot(bi);}
|
||
|
|
}
|
||
|
|
|
||
|
|
void CachePivot(int bi){
|
||
|
|
if(PT[bi]==1||PT[bi]==2){g_pH2=g_pH1;g_pH2P=g_pH1P;g_pH1=bi;g_pH1P=PP[bi];}
|
||
|
|
else if(PT[bi]==-1||PT[bi]==-2){g_pL2=g_pL1;g_pL2P=g_pL1P;g_pL1=bi;g_pL1P=PP[bi];}
|
||
|
|
}
|
||
|
|
|
||
|
|
int Trend(int e){
|
||
|
|
if(e<10||g_pH1==-1||g_pH2==-1||g_pL1==-1||g_pL2==-1)return 0;
|
||
|
|
bool hh=(g_pH1P>g_pH2P),hl=(g_pL1P>g_pL2P);
|
||
|
|
if(hh&&hl)return 1;if(!hh&&!hl)return -1;
|
||
|
|
double hs=(g_pH1P-g_pH2P)/MathMax(g_pH1-g_pH2,1),ls=(g_pL1P-g_pL2P)/MathMax(g_pL1-g_pL2,1);
|
||
|
|
if(hs>0&&ls>=0)return 1;if(hs<=0&&ls<0)return -1;return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int MapStructuralPhase(const int ev){
|
||
|
|
if(ev==0) return 0;
|
||
|
|
int sign=(ev>0)?1:-1;
|
||
|
|
int ae=(ev>0)?ev:-ev;
|
||
|
|
int phase=0;
|
||
|
|
if(ae<=2) phase=1;
|
||
|
|
else if(ae<=4) phase=2;
|
||
|
|
else if(ae==5) phase=3;
|
||
|
|
else if(ae==6) phase=4;
|
||
|
|
else phase=5;
|
||
|
|
return phase*sign;
|
||
|
|
}
|
||
|
|
|
||
|
|
int IsZigZagSessionTypeMT5(const int sessionType){
|
||
|
|
return (sessionType==9 || sessionType==10);
|
||
|
|
}
|
||
|
|
|
||
|
|
int IsPreviousSessionTypeMT5(const int sessionType){
|
||
|
|
return (sessionType>=1 && sessionType<=4);
|
||
|
|
}
|
||
|
|
|
||
|
|
int MapBaseCalendarTypeMT5(const int sessionType){
|
||
|
|
if(sessionType==1 || sessionType==5) return 1; // day
|
||
|
|
if(sessionType==2 || sessionType==6) return 2; // week
|
||
|
|
if(sessionType==3 || sessionType==7) return 3; // month
|
||
|
|
if(sessionType==4 || sessionType==8) return 4; // year
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
datetime DayStartMT5(const datetime t){
|
||
|
|
MqlDateTime dt;
|
||
|
|
TimeToStruct(t, dt);
|
||
|
|
dt.hour = 0;
|
||
|
|
dt.min = 0;
|
||
|
|
dt.sec = 0;
|
||
|
|
return StructToTime(dt);
|
||
|
|
}
|
||
|
|
|
||
|
|
datetime AddMonthsSafeMT5(const datetime t, const int months){
|
||
|
|
MqlDateTime dt;
|
||
|
|
TimeToStruct(t, dt);
|
||
|
|
|
||
|
|
int m = dt.mon + months;
|
||
|
|
while(m > 12){
|
||
|
|
m -= 12;
|
||
|
|
dt.year++;
|
||
|
|
}
|
||
|
|
while(m < 1){
|
||
|
|
m += 12;
|
||
|
|
dt.year--;
|
||
|
|
}
|
||
|
|
|
||
|
|
dt.mon = m;
|
||
|
|
dt.day = 1;
|
||
|
|
dt.hour = 0;
|
||
|
|
dt.min = 0;
|
||
|
|
dt.sec = 0;
|
||
|
|
return StructToTime(dt);
|
||
|
|
}
|
||
|
|
|
||
|
|
datetime ResolveCalendarContextStartMT5(const datetime currentTime){
|
||
|
|
int st = gSessionType;
|
||
|
|
int baseType = MapBaseCalendarTypeMT5(st);
|
||
|
|
datetime currentStart = DayStartMT5(currentTime);
|
||
|
|
|
||
|
|
if(baseType == 2){
|
||
|
|
MqlDateTime w;
|
||
|
|
TimeToStruct(currentStart, w);
|
||
|
|
int dow = w.day_of_week;
|
||
|
|
int back = (dow == 0) ? 6 : (dow - 1);
|
||
|
|
currentStart -= (datetime)(back * 86400);
|
||
|
|
}
|
||
|
|
else if(baseType == 3){
|
||
|
|
MqlDateTime m;
|
||
|
|
TimeToStruct(currentStart, m);
|
||
|
|
m.day = 1;
|
||
|
|
m.hour = 0;
|
||
|
|
m.min = 0;
|
||
|
|
m.sec = 0;
|
||
|
|
currentStart = StructToTime(m);
|
||
|
|
}
|
||
|
|
else if(baseType == 4){
|
||
|
|
MqlDateTime y;
|
||
|
|
TimeToStruct(currentStart, y);
|
||
|
|
y.mon = 1;
|
||
|
|
y.day = 1;
|
||
|
|
y.hour = 0;
|
||
|
|
y.min = 0;
|
||
|
|
y.sec = 0;
|
||
|
|
currentStart = StructToTime(y);
|
||
|
|
}
|
||
|
|
|
||
|
|
int shift = IsPreviousSessionTypeMT5(st) ? -gSessionCount : -(gSessionCount - 1);
|
||
|
|
|
||
|
|
if(baseType == 1)
|
||
|
|
return currentStart + (datetime)(shift * 86400);
|
||
|
|
if(baseType == 2)
|
||
|
|
return currentStart + (datetime)(shift * 7 * 86400);
|
||
|
|
if(baseType == 3)
|
||
|
|
return AddMonthsSafeMT5(currentStart, shift);
|
||
|
|
|
||
|
|
return AddMonthsSafeMT5(currentStart, shift * 12);
|
||
|
|
}
|
||
|
|
|
||
|
|
int ResolveSessionLowerBound(const int bi,const int rates_total,const datetime &time[]){
|
||
|
|
int fallback = MathMax(0, bi - gLB + 1);
|
||
|
|
if(gContextMode != 1){
|
||
|
|
return fallback;
|
||
|
|
}
|
||
|
|
|
||
|
|
if(IsZigZagSessionTypeMT5(gSessionType)){
|
||
|
|
return MathMax(0, bi - gLB * MathMax(1, gSessionCount) + 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
int si = rates_total - 1 - bi;
|
||
|
|
datetime contextStart = ResolveCalendarContextStartMT5(time[si]);
|
||
|
|
// Binary search (time[rates_total-1-j] is monotonically increasing with j)
|
||
|
|
int lo=0, hi=bi;
|
||
|
|
while(lo<hi){
|
||
|
|
int mid=lo+(hi-lo)/2;
|
||
|
|
int smid=rates_total-1-mid;
|
||
|
|
if(time[smid]>=contextStart) hi=mid;
|
||
|
|
else lo=mid+1;
|
||
|
|
}
|
||
|
|
int lb = lo;
|
||
|
|
|
||
|
|
return MathMax(0, MathMin(lb, bi));
|
||
|
|
}
|
||
|
|
|
||
|
|
double DetectChochTrendToRange(const int prevEv,const int ev){
|
||
|
|
if(prevEv==0||ev==0) return 0.0;
|
||
|
|
int p=(prevEv>0)?prevEv:-prevEv;
|
||
|
|
int c=(ev>0)?ev:-ev;
|
||
|
|
if(p>=6 && c>=3 && c<=5) return (ev>0)?1.0:-1.0;
|
||
|
|
return 0.0;
|
||
|
|
}
|
||
|
|
|
||
|
|
double DetectChochRangeToTrend(const int prevEv,const int ev){
|
||
|
|
if(prevEv==0||ev==0) return 0.0;
|
||
|
|
int p=(prevEv>0)?prevEv:-prevEv;
|
||
|
|
int c=(ev>0)?ev:-ev;
|
||
|
|
if(p>=3 && p<=5 && c>=6) return (ev>0)?1.0:-1.0;
|
||
|
|
return 0.0;
|
||
|
|
}
|
||
|
|
|
||
|
|
void DetectSlopeClasses(const int ev,const double zoneTop,const double zoneBot,const double prevTop,const double prevBot,double &aBull,double &aBear,double &dBull,double &dBear){
|
||
|
|
aBull=0.0; aBear=0.0; dBull=0.0; dBear=0.0;
|
||
|
|
if(ev==0) return;
|
||
|
|
if(zoneTop<=0||zoneBot<=0||prevTop<=0||prevBot<=0) return;
|
||
|
|
int ae=(ev>0)?ev:-ev;
|
||
|
|
if(ae>6) return;
|
||
|
|
|
||
|
|
double midNow=(zoneTop+zoneBot)*0.5;
|
||
|
|
double midPrev=(prevTop+prevBot)*0.5;
|
||
|
|
double slope=midNow-midPrev;
|
||
|
|
if(MathAbs(slope)<0.0000001) return;
|
||
|
|
|
||
|
|
if(ev>0){
|
||
|
|
if(slope>0) aBull=1.0;
|
||
|
|
if(slope<0) aBear=1.0;
|
||
|
|
} else {
|
||
|
|
if(slope>0) dBull=1.0;
|
||
|
|
if(slope<0) dBear=1.0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
int ScanPhase(int bi,int lbStart,double &outTop,double &outBot){
|
||
|
|
int trend=Trend(bi);
|
||
|
|
int ev[14];ArrayInitialize(ev,-1);
|
||
|
|
double scL=0,bcH=0,arH=0,arL=0,stL=0,stH=0,cH=0,iL=DBL_MAX,zT=0,zB=DBL_MAX;
|
||
|
|
int dir=0;double pt=0.0001,mp=MathMax(pt*10,0.000001); // hardcoded parity with Java
|
||
|
|
|
||
|
|
for(int j=lbStart;j<=bi&&j<ArraySize(NR)&&!IsStopped();j++){
|
||
|
|
double hi=H[j],lo=L[j],cl=C[j];
|
||
|
|
double vr=NV[j],rr=NR[j],cpP=CP[j];
|
||
|
|
double at=MathMax(AT[j]*gATM,mp);
|
||
|
|
bool iSH=(PT[j]>=1),iSL=(PT[j]<=-1),aB=(trend<=0),aR=(trend>=0);
|
||
|
|
|
||
|
|
if(ev[0]==-1&&ev[7]==-1&&vr>=gVHM&&vr<gVCM&&rr>=gRSM&&rr<gRCM)
|
||
|
|
{if((iSL||IsNewLow(j,lbStart))&&cpP>=0.55&&aB){ev[0]=j;if(dir==0)dir=1;if(scL==0||lo<scL)scL=lo;continue;}}
|
||
|
|
if(ev[7]==-1&&ev[0]==-1&&vr>=gVHM&&vr<gVCM&&rr>=gRSM&&rr<gRCM)
|
||
|
|
{if((iSH||IsNewHigh(j,lbStart))&&cpP<=0.45&&aR){ev[7]=j;if(dir==0)dir=-1;if(bcH==0||hi>bcH)bcH=hi;continue;}}
|
||
|
|
if(ev[1]==-1&&ev[8]==-1&&vr>=gVCM&&rr>=gRCM)
|
||
|
|
{if((iSL||IsNewLow(j,lbStart))&&cpP>=0.70&&aB){ev[1]=j;if(dir==0)dir=1;scL=lo;if(lo<zB)zB=lo;continue;}}
|
||
|
|
if(ev[8]==-1&&ev[1]==-1&&vr>=gVCM&&rr>=gRCM)
|
||
|
|
{if((iSH||IsNewHigh(j,lbStart))&&cpP<=0.30&&aR){ev[8]=j;if(dir==0)dir=-1;bcH=hi;if(hi>zT)zT=hi;continue;}}
|
||
|
|
if(ev[2]==-1&&(ev[1]!=-1||(dir==1&&ev[7]==-1))&&j>lbStart&&cl>C[j-1]&&vr>=0.8&&ev[9]==-1&&aB)
|
||
|
|
{ev[2]=j;arH=hi;if(hi>cH)cH=hi;if(hi>zT)zT=hi;continue;}
|
||
|
|
if(ev[9]==-1&&(ev[8]!=-1||(dir==-1&&ev[0]==-1))&&j>lbStart&&cl<L[j-1]&&vr>=0.8&&ev[2]==-1&&aR)
|
||
|
|
{ev[9]=j;arL=lo;if(lo<iL)iL=lo;if(lo<zB)zB=lo;continue;}
|
||
|
|
if(ev[3]==-1&&(ev[1]!=-1||ev[0]!=-1)&&scL>0&&ev[4]==-1&&ev[6]==-1&&vr<=gSVR&&rr<=1.0&&aB)
|
||
|
|
{double pc=(scL>0)?MathAbs(lo-scL)/MathMax(scL,pt):1.0,ad=MathAbs(lo-scL)/MathMax(at,mp);
|
||
|
|
if((pc<=0.02||ad<=2.0)&&cl>scL-at*0.5){ev[3]=j;if(stL==0||lo<stL)stL=lo;if(lo<zB)zB=lo;if(hi>zT)zT=hi;continue;}}
|
||
|
|
if(ev[10]==-1&&(ev[8]!=-1||ev[7]!=-1)&&bcH>0&&ev[11]==-1&&ev[13]==-1&&vr<=gSVR&&rr<=1.0&&aR)
|
||
|
|
{double pc=(bcH>0)?MathAbs(hi-bcH)/MathMax(bcH,pt):1.0,ad=MathAbs(hi-bcH)/MathMax(at,mp);
|
||
|
|
if((pc<=0.02||ad<=2.0)&&cl<bcH+at*0.5){ev[10]=j;if(stH==0||hi>stH)stH=hi;if(hi>zT)zT=hi;if(lo<zB)zB=lo;continue;}}
|
||
|
|
double sL=(stL>0)?stL:((scL>0)?scL:zB);
|
||
|
|
if(ev[4]==-1&&ev[11]==-1&&sL<DBL_MAX&&sL>0&&ev[6]==-1&&lo<sL-at*0.3&&cl>sL&&vr>=0.8&&vr<=2.0&&cpP>=0.55&&aB)
|
||
|
|
{ev[4]=j;if(dir==0||dir==-1)dir=1;continue;}
|
||
|
|
double sH=(stH>0)?stH:((bcH>0)?bcH:zT);
|
||
|
|
if(ev[11]==-1&&ev[4]==-1&&sH>0&&sH<DBL_MAX&&ev[13]==-1&&hi>sH+at*0.3&&cl<sH&&vr>=0.8&&vr<=2.0&&cpP<=0.45&&aR)
|
||
|
|
{ev[11]=j;if(dir==0||dir==1)dir=-1;continue;}
|
||
|
|
double bL=(cH>0)?cH:zT;
|
||
|
|
if(ev[6]==-1&&ev[13]==-1&&bL>0&&cl>bL+at*0.5&&hi>bL&&rr>=gRSM&&vr>=gVHM&&cpP>=0.70&&aB){ev[6]=j;continue;}
|
||
|
|
double bW=(iL<DBL_MAX&&iL>0)?iL:zB;
|
||
|
|
if(ev[13]==-1&&ev[6]==-1&&bW>0&&bW<DBL_MAX&&cl<bW-at*0.5&&lo<bW&&rr>=gRSM&&vr>=gVHM&&cpP<=0.30&&aR){ev[13]=j;continue;}
|
||
|
|
double lpsL=(arH>0)?arH:((cH>0)?cH:zT);
|
||
|
|
if(ev[5]==-1&&ev[6]!=-1&&lpsL>0&&vr<=gSVR&&rr<=1.0&&cpP>=0.40&&aB){double pd=MathAbs(cl-lpsL)/MathMax(at,mp);if(pd<=2.0){ev[5]=j;continue;}}
|
||
|
|
double lpsY=(arL>0)?arL:((iL<DBL_MAX)?iL:zB);
|
||
|
|
if(ev[12]==-1&&ev[13]!=-1&&lpsY>0&&vr<=gSVR&&rr<=1.0&&cpP<=0.60&&aR){double pd=MathAbs(cl-lpsY)/MathMax(at,mp);if(pd<=2.0){ev[12]=j;continue;}}
|
||
|
|
|
||
|
|
if(iSH&&hi>cH)cH=hi;if(iSH&&hi>zT)zT=hi;if(iSL&&lo<iL)iL=lo;if(iSL&&lo<zB)zB=lo;
|
||
|
|
}
|
||
|
|
|
||
|
|
double segHi=H[bi],segLo=L[bi];
|
||
|
|
for(int j=lbStart;j<bi;j++){if(H[j]>segHi)segHi=H[j];if(L[j]<segLo)segLo=L[j];}
|
||
|
|
outTop=segHi;outBot=segLo;
|
||
|
|
if(outTop<=outBot){outTop=segHi+0.01;outBot=segLo-0.01;} // hardcoded parity with Java (0.0001*100)
|
||
|
|
|
||
|
|
if(ev[6]!=-1)return 7;if(ev[5]!=-1)return 6;if(ev[4]!=-1)return 5;
|
||
|
|
if(ev[3]!=-1)return 4;if(ev[2]!=-1)return 3;if(ev[1]!=-1)return 2;
|
||
|
|
if(ev[0]!=-1)return 1;if(ev[13]!=-1)return -7;if(ev[12]!=-1)return -6;
|
||
|
|
if(ev[11]!=-1)return -5;if(ev[10]!=-1)return -4;if(ev[9]!=-1)return -3;
|
||
|
|
if(ev[8]!=-1)return -2;if(ev[7]!=-1)return -1;return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
// Chart drawing (rectangle zones + smart labels)
|
||
|
|
datetime gTimeArr[]; // persistent: stores time[i] for each chronological index
|
||
|
|
|
||
|
|
void DrawSegZone(datetime t1,datetime t2,double top,double bot,int ev,string tag){
|
||
|
|
string zn=PFX+"Z_"+tag;
|
||
|
|
if(top<=0||bot<=0||top<=bot)return;
|
||
|
|
if(ObjectFind(0,zn)<0){ObjectCreate(0,zn,OBJ_RECTANGLE,0,t1,top,t2,bot);}
|
||
|
|
else{ObjectSetDouble(0,zn,OBJPROP_PRICE,1,top);ObjectSetDouble(0,zn,OBJPROP_PRICE,0,bot);
|
||
|
|
ObjectSetInteger(0,zn,OBJPROP_TIME,0,t1);ObjectSetInteger(0,zn,OBJPROP_TIME,1,t2);}
|
||
|
|
ObjectSetInteger(0,zn,OBJPROP_COLOR,(ev>0)?clrGreen:clrRed);
|
||
|
|
ObjectSetInteger(0,zn,OBJPROP_FILL,true);ObjectSetInteger(0,zn,OBJPROP_BACK,true);
|
||
|
|
ObjectSetInteger(0,zn,OBJPROP_WIDTH,0);
|
||
|
|
}
|
||
|
|
|
||
|
|
void DrawSegLabelSmart(datetime t,double ly,double zoneTop,string txt,string tag){
|
||
|
|
string ln=PFX+"L_"+tag;
|
||
|
|
if(ObjectFind(0,ln)<0){ObjectCreate(0,ln,OBJ_TEXT,0,t,ly);}
|
||
|
|
else{ObjectSetInteger(0,ln,OBJPROP_TIME,0,t);ObjectSetDouble(0,ln,OBJPROP_PRICE,0,ly);}
|
||
|
|
ObjectSetString(0,ln,OBJPROP_TEXT,txt);ObjectSetInteger(0,ln,OBJPROP_COLOR,clrOrange);
|
||
|
|
ObjectSetInteger(0,ln,OBJPROP_FONTSIZE,8);ObjectSetInteger(0,ln,OBJPROP_ANCHOR,ANCHOR_BOTTOM);
|
||
|
|
ObjectSetInteger(0,ln,OBJPROP_BACK,false);
|
||
|
|
string an=PFX+"A_"+tag;
|
||
|
|
double labelBot=ly-0.0002;
|
||
|
|
if(labelBot>zoneTop){
|
||
|
|
if(ObjectFind(0,an)<0){ObjectCreate(0,an,OBJ_TREND,0,t,labelBot,t,zoneTop);}
|
||
|
|
else{ObjectSetInteger(0,an,OBJPROP_TIME,0,t);ObjectSetDouble(0,an,OBJPROP_PRICE,0,labelBot);
|
||
|
|
ObjectSetInteger(0,an,OBJPROP_TIME,1,t);ObjectSetDouble(0,an,OBJPROP_PRICE,1,zoneTop);}
|
||
|
|
ObjectSetInteger(0,an,OBJPROP_COLOR,clrOrange);
|
||
|
|
ObjectSetInteger(0,an,OBJPROP_WIDTH,1);ObjectSetInteger(0,an,OBJPROP_STYLE,STYLE_DOT);
|
||
|
|
ObjectSetInteger(0,an,OBJPROP_BACK,false);ObjectSetInteger(0,an,OBJPROP_RAY_RIGHT,false);
|
||
|
|
} else { if(ObjectFind(0,an)>=0) ObjectDelete(0,an); }
|
||
|
|
}
|
||
|
|
|
||
|
|
void PostDraw(int rates_total,const datetime &time[]){
|
||
|
|
// Delete only previous AWY_ objects, then redraw all segments fresh
|
||
|
|
ObjectsDeleteAll(0,PFX);
|
||
|
|
// Buffers are ArraySetAsSeries(true): BufEvent[0]=newest
|
||
|
|
// Iterate chronologically: chrono=0=oldest → si = rates_total-1-chrono
|
||
|
|
Seg seg;seg.ev=0;seg.top=0;seg.bot=0;seg.hi=0;seg.lo=0;seg.t1=0;seg.t2=0;
|
||
|
|
bool segActive=false;
|
||
|
|
int drawStart=gLB+5;
|
||
|
|
for(int chrono=drawStart;chrono<rates_total;chrono++){
|
||
|
|
int si=rates_total-1-chrono;
|
||
|
|
datetime tBar=time[si];
|
||
|
|
int ev=(int)BufEvent[si];
|
||
|
|
if(ev==0)continue;
|
||
|
|
if(!segActive||ev!=seg.ev){
|
||
|
|
if(segActive&&seg.t2>=seg.t1){
|
||
|
|
string tag=EvName(seg.ev)+"_"+IntegerToString(seg.t1);
|
||
|
|
DrawSegZone(seg.t1,seg.t2,seg.top,seg.bot,seg.ev,tag);
|
||
|
|
double ly=(seg.ev>0)?seg.bot-0.0003:seg.top+0.001;
|
||
|
|
string evLbl=(seg.ev>0)?EvName(seg.ev)+" ↑":EvName(seg.ev)+" ↓";
|
||
|
|
DrawSegLabelSmart(seg.t1,ly,seg.top,evLbl,tag);
|
||
|
|
}
|
||
|
|
seg.ev=ev;seg.t1=tBar;seg.t2=tBar;
|
||
|
|
seg.top=BufTop[si];seg.bot=BufBot[si];
|
||
|
|
seg.hi=seg.top;seg.lo=seg.bot;
|
||
|
|
segActive=true;
|
||
|
|
}else{seg.t2=tBar;if(BufTop[si]>seg.top)seg.top=BufTop[si];if(BufBot[si]<seg.bot)seg.bot=BufBot[si];}
|
||
|
|
}
|
||
|
|
if(segActive&&seg.t2>=seg.t1){
|
||
|
|
string tag=EvName(seg.ev)+"_"+IntegerToString(seg.t1);
|
||
|
|
DrawSegZone(seg.t1,seg.t2,seg.top,seg.bot,seg.ev,tag);
|
||
|
|
double ly=(seg.ev>0)?seg.bot-0.0003:seg.top+0.001;
|
||
|
|
string evLbl=(seg.ev>0)?EvName(seg.ev)+" ↑":EvName(seg.ev)+" ↓";
|
||
|
|
DrawSegLabelSmart(seg.t1,ly,seg.top,evLbl,tag);
|
||
|
|
} ChartRedraw(0);}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void OnInit(){
|
||
|
|
ObjectsDeleteAll(0,PFX);
|
||
|
|
int t=ObjectsTotal(0);
|
||
|
|
for(int i=t-1;i>=0;i--){string n=ObjectName(0,i);if(StringFind(n,"ADWv2")>=0||StringFind(n,"ADWES_")>=0||StringFind(n,"AWY_")>=0)ObjectDelete(0,n);}
|
||
|
|
gLB=MathMax(5,MathMin(200,InpLookback));gZZ=MathMax(1,MathMin(10,InpZigZag));
|
||
|
|
gVCM=InpVolClimax;gVHM=InpVolHigh;gRCM=InpRangeClimax;
|
||
|
|
gRSM=InpRangeSignificant;gSVR=InpSTVolRatio;gATM=InpATR;
|
||
|
|
gContextMode = (InpContextMode==1) ? 1 : 0;
|
||
|
|
gSessionType = (int)MathMax(1,MathMin(10,InpSessionType));
|
||
|
|
gSessionCount = (int)MathMax(1,MathMin(20,InpSessionCount));
|
||
|
|
|
||
|
|
SetIndexBuffer(0,BufEvent,INDICATOR_DATA);SetIndexBuffer(1,BufPhase,INDICATOR_DATA);
|
||
|
|
SetIndexBuffer(2,BufTop,INDICATOR_DATA);SetIndexBuffer(3,BufBot,INDICATOR_DATA);
|
||
|
|
SetIndexBuffer(4,BufColor,INDICATOR_DATA);SetIndexBuffer(5,BufStruct,INDICATOR_DATA);
|
||
|
|
SetIndexBuffer(6,BufChochTR,INDICATOR_DATA);SetIndexBuffer(7,BufChochRT,INDICATOR_DATA);
|
||
|
|
SetIndexBuffer(8,BufSlopeABull,INDICATOR_DATA);SetIndexBuffer(9,BufSlopeABear,INDICATOR_DATA);
|
||
|
|
SetIndexBuffer(10,BufSlopeDBull,INDICATOR_DATA);SetIndexBuffer(11,BufSlopeDBear,INDICATOR_DATA);
|
||
|
|
SetIndexBuffer(12,BufReacc,INDICATOR_DATA);SetIndexBuffer(13,BufRedis,INDICATOR_DATA);
|
||
|
|
// SOT pattern: ArraySetAsSeries on buffers so index 0 = newest bar → CopyBuffer shift 0 = current bar
|
||
|
|
ArraySetAsSeries(BufEvent, true);ArraySetAsSeries(BufPhase, true);
|
||
|
|
ArraySetAsSeries(BufTop, true);ArraySetAsSeries(BufBot, true);ArraySetAsSeries(BufColor, true);
|
||
|
|
ArraySetAsSeries(BufStruct, true);ArraySetAsSeries(BufChochTR, true);ArraySetAsSeries(BufChochRT, true);
|
||
|
|
ArraySetAsSeries(BufSlopeABull, true);ArraySetAsSeries(BufSlopeABear, true);
|
||
|
|
ArraySetAsSeries(BufSlopeDBull, true);ArraySetAsSeries(BufSlopeDBear, true);
|
||
|
|
ArraySetAsSeries(BufReacc, true);ArraySetAsSeries(BufRedis, true);
|
||
|
|
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,gLB);
|
||
|
|
PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0.0);PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,gLB);
|
||
|
|
PlotIndexSetDouble(2,PLOT_EMPTY_VALUE,0.0);PlotIndexSetInteger(2,PLOT_DRAW_BEGIN,gLB);
|
||
|
|
PlotIndexSetDouble(3,PLOT_EMPTY_VALUE,0.0);PlotIndexSetInteger(3,PLOT_DRAW_BEGIN,gLB);
|
||
|
|
PlotIndexSetDouble(4,PLOT_EMPTY_VALUE,0.0);PlotIndexSetInteger(4,PLOT_DRAW_BEGIN,gLB);
|
||
|
|
PlotIndexSetDouble(5,PLOT_EMPTY_VALUE,0.0);PlotIndexSetInteger(5,PLOT_DRAW_BEGIN,gLB);
|
||
|
|
PlotIndexSetDouble(6,PLOT_EMPTY_VALUE,0.0);PlotIndexSetInteger(6,PLOT_DRAW_BEGIN,gLB);
|
||
|
|
PlotIndexSetDouble(7,PLOT_EMPTY_VALUE,0.0);PlotIndexSetInteger(7,PLOT_DRAW_BEGIN,gLB);
|
||
|
|
PlotIndexSetDouble(8,PLOT_EMPTY_VALUE,0.0);PlotIndexSetInteger(8,PLOT_DRAW_BEGIN,gLB);
|
||
|
|
PlotIndexSetDouble(9,PLOT_EMPTY_VALUE,0.0);PlotIndexSetInteger(9,PLOT_DRAW_BEGIN,gLB);
|
||
|
|
PlotIndexSetDouble(10,PLOT_EMPTY_VALUE,0.0);PlotIndexSetInteger(10,PLOT_DRAW_BEGIN,gLB);
|
||
|
|
PlotIndexSetDouble(11,PLOT_EMPTY_VALUE,0.0);PlotIndexSetInteger(11,PLOT_DRAW_BEGIN,gLB);
|
||
|
|
PlotIndexSetDouble(12,PLOT_EMPTY_VALUE,0.0);PlotIndexSetInteger(12,PLOT_DRAW_BEGIN,gLB);
|
||
|
|
PlotIndexSetDouble(13,PLOT_EMPTY_VALUE,0.0);PlotIndexSetInteger(13,PLOT_DRAW_BEGIN,gLB);
|
||
|
|
IndicatorSetInteger(INDICATOR_DIGITS,0);IndicatorSetString(INDICATOR_SHORTNAME,"ADWES");
|
||
|
|
}
|
||
|
|
void OnDeinit(const int r){ObjectsDeleteAll(0,PFX);}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
int OnCalculate(const int rates_total,
|
||
|
|
const int prev_calculated,
|
||
|
|
const datetime &time[],
|
||
|
|
const double &open[],
|
||
|
|
const double &high[],
|
||
|
|
const double &low[],
|
||
|
|
const double &close[],
|
||
|
|
const long &tick_volume[],
|
||
|
|
const long &volume[],
|
||
|
|
const int &spread[]){
|
||
|
|
if(rates_total < gLB + 5) return(0);
|
||
|
|
|
||
|
|
ArraySetAsSeries(time, true);
|
||
|
|
ArraySetAsSeries(high, true);
|
||
|
|
ArraySetAsSeries(low, true);
|
||
|
|
ArraySetAsSeries(close, true);
|
||
|
|
ArraySetAsSeries(tick_volume, true);
|
||
|
|
|
||
|
|
// Resize internal chronological arrays
|
||
|
|
ArrayResize(H, rates_total); ArrayResize(L, rates_total);
|
||
|
|
ArrayResize(C, rates_total); ArrayResize(V, rates_total);
|
||
|
|
ArrayResize(NR, rates_total); ArrayResize(NV, rates_total);
|
||
|
|
ArrayResize(CP, rates_total); ArrayResize(AT, rates_total);
|
||
|
|
ArrayResize(PT, rates_total); ArrayResize(PP, rates_total);
|
||
|
|
ArrayResize(RMn,rates_total); ArrayResize(RMx,rates_total);
|
||
|
|
|
||
|
|
// Forward chronological loop for correct precomp dependencies (i=0=oldest)
|
||
|
|
// Write to series buffers: BufXxx[rates_total-1-i] so BufXxx[0]=newest
|
||
|
|
for(int i=0;i<rates_total&&!IsStopped();i++){
|
||
|
|
int si=rates_total-1-i; // series input read index (0=newest)
|
||
|
|
H[i]=high[si];L[i]=low[si];C[i]=close[si];
|
||
|
|
V[i]=(double)MathMax(tick_volume[si],1);
|
||
|
|
|
||
|
|
PrecompMinMax(i);PrecompNorm(i);PrecompPivot(i);
|
||
|
|
|
||
|
|
int wi=rates_total-1-i; // series buffer write index (0=newest)
|
||
|
|
if(i<gLB+5){
|
||
|
|
BufEvent[wi]=0;
|
||
|
|
BufPhase[wi]=0;
|
||
|
|
BufTop[wi]=0;
|
||
|
|
BufBot[wi]=0;
|
||
|
|
BufColor[wi]=0;
|
||
|
|
BufStruct[wi]=0;
|
||
|
|
BufChochTR[wi]=0;
|
||
|
|
BufChochRT[wi]=0;
|
||
|
|
BufSlopeABull[wi]=0;
|
||
|
|
BufSlopeABear[wi]=0;
|
||
|
|
BufSlopeDBull[wi]=0;
|
||
|
|
BufSlopeDBear[wi]=0;
|
||
|
|
BufReacc[wi]=0;
|
||
|
|
BufRedis[wi]=0;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
int lb=MathMax(0,i-gLB+1);
|
||
|
|
lb=ResolveSessionLowerBound(i,rates_total,time);
|
||
|
|
double zT=0,zB=0;
|
||
|
|
int ev=ScanPhase(i,lb,zT,zB);
|
||
|
|
int prevEv=(i>0)?(int)BufEvent[wi+1]:0;
|
||
|
|
int structPhase=MapStructuralPhase(ev);
|
||
|
|
double chochTR=DetectChochTrendToRange(prevEv,ev);
|
||
|
|
double chochRT=DetectChochRangeToTrend(prevEv,ev);
|
||
|
|
double prevTop=(i>0)?BufTop[wi+1]:0.0;
|
||
|
|
double prevBot=(i>0)?BufBot[wi+1]:0.0;
|
||
|
|
double slopeABull=0.0,slopeABear=0.0,slopeDBull=0.0,slopeDBear=0.0;
|
||
|
|
double reacc=0.0, redis=0.0;
|
||
|
|
DetectSlopeClasses(ev,zT,zB,prevTop,prevBot,slopeABull,slopeABear,slopeDBull,slopeDBear);
|
||
|
|
int tr=Trend(i);
|
||
|
|
int ae=(ev>0)?ev:-ev;
|
||
|
|
if(ae<=6){
|
||
|
|
if(ev>0 && tr>0) reacc=1.0;
|
||
|
|
if(ev<0 && tr<0) redis=1.0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Normalize: guard against NaN/Inf from edge-case inputs
|
||
|
|
if(!MathIsValidNumber((double)structPhase)) structPhase = 0;
|
||
|
|
if(!MathIsValidNumber(chochTR)) chochTR = 0.0;
|
||
|
|
if(!MathIsValidNumber(chochRT)) chochRT = 0.0;
|
||
|
|
if(!MathIsValidNumber(zT)) zT = 0.0;
|
||
|
|
if(!MathIsValidNumber(zB)) zB = 0.0;
|
||
|
|
|
||
|
|
BufEvent[wi]=(double)ev;
|
||
|
|
BufPhase[wi]=(double)ev;
|
||
|
|
BufTop[wi]=zT;
|
||
|
|
BufBot[wi]=zB;
|
||
|
|
BufColor[wi]=(ev!=0)?C[i]:0;
|
||
|
|
BufStruct[wi]=(double)structPhase;
|
||
|
|
BufChochTR[wi]=chochTR;
|
||
|
|
BufChochRT[wi]=chochRT;
|
||
|
|
BufSlopeABull[wi]=slopeABull;
|
||
|
|
BufSlopeABear[wi]=slopeABear;
|
||
|
|
BufSlopeDBull[wi]=slopeDBull;
|
||
|
|
BufSlopeDBear[wi]=slopeDBear;
|
||
|
|
BufReacc[wi]=reacc;
|
||
|
|
BufRedis[wi]=redis;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Segment post-process: draw zones + labels on chart (uses buffer data, works regardless of series)
|
||
|
|
PostDraw(rates_total,time);
|
||
|
|
|
||
|
|
return(rates_total);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|