//+------------------------------------------------------------------+ //| DzDraw.mqh | //| Copyright 2026, Allan Niñal | //| https://www.allanninal.dev/mql5 | //+------------------------------------------------------------------+ //| Draws a CDzEngine's zones on the chart: rectangles (fresh filled,| //| tested outlined, broken grey up to the bar that broke them), the | //| middle line, a short label and the broken swing. Objects share | //| one prefix and are rebuilt only when a bar closes. | //+------------------------------------------------------------------+ // SPDX-License-Identifier: LicenseRef-PolyForm-Noncommercial-1.0.0 (see LICENSE) #property strict #ifndef DZDRAW_MQH #define DZDRAW_MQH #include "DzEngine.mqh" #include "ObjSync.mqh" int g_dz_fail=0; // objects the chart refused in the current pass struct SDzStyle { bool fill,show_tested,show_broken,midline,labels,swings,show_filtered; int draw_bars,max_zones,extend; color dem,sup,broken,outline; }; void DzRect(const string name,const datetime t1,const double top,const datetime t2,const double bot,const color clr, const bool fill,const ENUM_LINE_STYLE style,const string tip) { if(!OsPlace(name,OBJ_RECTANGLE,2,t1,top,t2,bot)) { g_dz_fail++; return; } OsInt(name,OBJPROP_COLOR,clr); OsInt(name,OBJPROP_FILL,fill); OsInt(name,OBJPROP_STYLE,style); OsInt(name,OBJPROP_BACK,true); OsInt(name,OBJPROP_WIDTH,1); OsStr(name,OBJPROP_TOOLTIP,tip); } void DzSeg(const string name,const datetime t1,const double p1,const datetime t2,const double p2,const color clr, const ENUM_LINE_STYLE style,const string tip) { if(!OsPlace(name,OBJ_TREND,2,t1,p1,t2,p2)) { g_dz_fail++; return; } OsInt(name,OBJPROP_COLOR,clr); OsInt(name,OBJPROP_STYLE,style); OsInt(name,OBJPROP_RAY_RIGHT,false); OsInt(name,OBJPROP_BACK,true); OsStr(name,OBJPROP_TOOLTIP,tip); } void DzText(const string name,const datetime t,const double p,const string text,const color clr,const ENUM_ANCHOR_POINT anchor) { if(!OsPlace(name,OBJ_TEXT,1,t,p,0,0)) { g_dz_fail++; return; } OsStr(name,OBJPROP_TEXT,text); OsInt(name,OBJPROP_COLOR,clr); OsInt(name,OBJPROP_FONTSIZE,8); OsInt(name,OBJPROP_ANCHOR,anchor); } string DzStateText(const SDzZone &z) { if(z.state==DZ_FRESH) return("fresh"); if(z.state==DZ_TESTED) return(z.retests>1 ? StringFormat("tested, %d entries",z.retests) : "tested"); if(z.state==DZ_BROKEN) return("broken"); return("dropped (zone limit)"); } //--- a small corner label with the validated market structure after the last closed bar void DzTrendLabel(const string name,CDzEngine &e,const string tfname,const ENUM_BASE_CORNER corner,const int x,const int y, const color clr,const int digits) { if(e.done<1) return; string tx=StringFormat("%sValidated trend: %s (validated %s %s)",tfname!="" ? tfname+" " : "",e.Trend()>0 ? "up" : "down", e.Trend()>0 ? "low" : "high",DoubleToString(e.ValidLevel(),digits)); if(!OsPlace(name,OBJ_LABEL,1,0,0,0,0)) { g_dz_fail++; return; } OsInt(name,OBJPROP_CORNER,corner); OsInt(name,OBJPROP_ANCHOR,(corner==CORNER_RIGHT_UPPER || corner==CORNER_RIGHT_LOWER) ? ANCHOR_RIGHT_UPPER : ANCHOR_LEFT_UPPER); OsInt(name,OBJPROP_XDISTANCE,x); OsInt(name,OBJPROP_YDISTANCE,y); OsInt(name,OBJPROP_COLOR,clr); OsInt(name,OBJPROP_FONTSIZE,9); OsStr(name,OBJPROP_TEXT,tx); } //--- draw the zones of one engine; `t` = bar times of the series it ran on. `tfname` != "" marks a higher timeframe. int DzDrawEngine(CDzEngine &e,const datetime &t[],const string pfx,const string tfname,const datetime from_t, const datetime right_t,const int budget,const SDzStyle &st,const int digits) { int drawn=0; bool htf=(tfname!=""); for(int z=e.nz-1; z>=0 && drawn0),live=(e.zones[z].end<0); color clr=(!shown || s==DZ_BROKEN ? st.broken : (htf ? st.outline : (dem ? st.dem : st.sup))); datetime t2=(live ? right_t : t[e.zones[z].end]); string tip=StringFormat("%s%s zone %s - %s, made %s, %s",htf ? tfname+" " : "",dem ? "Demand" : "Supply", DoubleToString(e.zones[z].bot,digits),DoubleToString(e.zones[z].top,digits), TimeToString(t[e.zones[z].born]),DzStateText(e.zones[z])); tip+=StringFormat(", validated trend %s, reward-to-risk %.1f",e.zones[z].trend>0 ? "up" : "down",e.zones[z].rr); if(!shown) tip+=" - left out by the trend / reward-to-risk option"; string nm=StringFormat("%sZ%d",pfx,z); bool fill=(st.fill && !htf && s==DZ_FRESH && shown); DzRect(nm,t[e.zones[z].t0],e.zones[z].top,t2,e.zones[z].bot,clr,fill,!shown ? STYLE_DOT : (s==DZ_TESTED ? STYLE_DASH : STYLE_SOLID),tip); if(st.midline && shown) DzSeg(nm+"m",t[e.zones[z].t0],e.zones[z].mid,t2,e.zones[z].mid,clr,STYLE_DOT,tip); if(st.labels && shown) { string lb=(htf ? tfname+" " : "")+(dem ? "D" : "S")+(e.zones[z].retests>1 ? "x"+IntegerToString(e.zones[z].retests) : ""); DzText(nm+"l",t[e.zones[z].t0],dem ? e.zones[z].bot : e.zones[z].top,lb,clr,dem ? ANCHOR_LEFT_UPPER : ANCHOR_LEFT_LOWER); } drawn++; } int shown=0; if(st.swings && !htf) for(int b=e.nb-1; b>=0 && shown0); DzSeg(StringFormat("%sB%d",pfx,b),t[e.breaks[b].frm],e.breaks[b].level,t[e.breaks[b].at],e.breaks[b].level, up ? st.dem : st.sup,STYLE_DOT,up ? "Swing high closed through with displacement" : "Swing low closed through with displacement"); shown++; } return(drawn); } #endif //+------------------------------------------------------------------+