//+------------------------------------------------------------------+ //| CkObj.mqh | //| Copyright 2026, Allan NiƱal | //| https://www.allanninal.dev/mql5 | //+------------------------------------------------------------------+ //| Chart kit object helpers: create once (hidden from the object | //| list, not selectable), then set a property only when its value | //| changed, so a redraw with nothing new sends nothing. Every name | //| carries the product's own prefix; CkDeleteAll(prefix) cleans up. | //| g_ck_dirty turns true when something was sent: call ChartRedraw | //| once per handler, not per object. | //+------------------------------------------------------------------+ #ifndef CK_OBJ_MQH #define CK_OBJ_MQH bool g_ck_dirty=false; //--- the non-visual Strategy Tester has no chart to draw on bool CkCanDraw(void) { return(!(MQLInfoInteger(MQL_TESTER) && !MQLInfoInteger(MQL_VISUAL_MODE))); } bool CkEnsure(const string name,const ENUM_OBJECT type) { if(ObjectFind(0,name)>=0) return(true); if(!ObjectCreate(0,name,type,0,0,0)) return(false); ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false); ObjectSetInteger(0,name,OBJPROP_HIDDEN,true); g_ck_dirty=true; return(true); } void CkSetI(const string name,const ENUM_OBJECT_PROPERTY_INTEGER p,const long v,const int mod=0) { if(ObjectGetInteger(0,name,p,mod)!=v) { ObjectSetInteger(0,name,p,mod,v); g_ck_dirty=true; } } void CkSetD(const string name,const ENUM_OBJECT_PROPERTY_DOUBLE p,const double v,const int mod=0) { if(MathAbs(ObjectGetDouble(0,name,p,mod)-v)>1e-12) { ObjectSetDouble(0,name,p,mod,v); g_ck_dirty=true; } } void CkSetS(const string name,const ENUM_OBJECT_PROPERTY_STRING p,const string v) { if(ObjectGetString(0,name,p)!=v) { ObjectSetString(0,name,p,v); g_ck_dirty=true; } } //--- a filled rectangle behind the candles (time t1..t2, price p1..p2) void CkRect(const string name,const datetime t1,const double p1,const datetime t2,const double p2,const color fill,const string tip="") { if(!CkEnsure(name,OBJ_RECTANGLE)) return; CkSetI(name,OBJPROP_BACK,1); CkSetI(name,OBJPROP_FILL,1); CkSetI(name,OBJPROP_COLOR,fill); CkSetI(name,OBJPROP_TIME,t1,0); CkSetD(name,OBJPROP_PRICE,p1,0); CkSetI(name,OBJPROP_TIME,t2,1); CkSetD(name,OBJPROP_PRICE,p2,1); CkSetS(name,OBJPROP_TOOLTIP,tip=="" ? "\n" : tip); } //--- a text anchored at a time and price void CkText(const string name,const datetime t,const double p,const string text,const color clr,const ENUM_ANCHOR_POINT anchor, const int size=8,const string font="Segoe UI Semibold",const string tip="") { if(!CkEnsure(name,OBJ_TEXT)) return; CkSetI(name,OBJPROP_BACK,0); CkSetI(name,OBJPROP_ANCHOR,anchor); CkSetI(name,OBJPROP_FONTSIZE,size); CkSetS(name,OBJPROP_FONT,font); CkSetI(name,OBJPROP_COLOR,clr); CkSetI(name,OBJPROP_TIME,t,0); CkSetD(name,OBJPROP_PRICE,p,0); CkSetS(name,OBJPROP_TEXT,text=="" ? " " : text); CkSetS(name,OBJPROP_TOOLTIP,tip=="" ? "\n" : tip); } void CkDelete(const string name) { if(ObjectFind(0,name)>=0 && ObjectDelete(0,name)) g_ck_dirty=true; } void CkDeleteAll(const string prefix) { if(ObjectsDeleteAll(0,prefix)>0) g_ck_dirty=true; } #endif //+------------------------------------------------------------------+