76 lines
3 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| ObjSync.mqh |
| |||
//| Copyright 2026, Allan Niñal |
| |||
//| https://www.allanninal.dev/mql5 |
| |||
//+------------------------------------------------------------------+
| |||
//| Chart objects that survive a redraw. A product that redraws on |
| |||
//| every new bar used to delete all its objects and create them |
| |||
//| again; here each object is created once, its points and |
| |||
//| properties are changed only when they differ, and only the |
| |||
//| objects the pass did not ask for are deleted: |
| |||
//| OsBegin(); ... OsRect / OsTrend / OsText / OsLabel ... |
| |||
//| OsEnd(prefix); |
| |||
//| An object is marked "used in this pass" in its z-order property |
| |||
//| (a pass number; the objects are not selectable). Works the same |
| |||
//| in MQL5 and MQL4. |
| |||
//+------------------------------------------------------------------+
| |||
// SPDX-License-Identifier: LicenseRef-PolyForm-Noncommercial-1.0.0 (see LICENSE)
| |||
#ifndef OBJSYNC_MQH
| |||
#define OBJSYNC_MQH
| |||
| |||
int g_os_gen=0;
| |||
| |||
void OsBegin(void)
| |||
{
| |||
g_os_gen=(g_os_gen>=2000000000 ? 1 : g_os_gen+1);
| |||
}
| |||
| |||
void OsInt(const string name,const ENUM_OBJECT_PROPERTY_INTEGER prop,const long v)
| |||
{
| |||
if(ObjectGetInteger(0,name,prop)!=v)
| |||
ObjectSetInteger(0,name,prop,v);
| |||
}
| |||
| |||
void OsStr(const string name,const ENUM_OBJECT_PROPERTY_STRING prop,const string v)
| |||
{
| |||
if(ObjectGetString(0,name,prop)!=v)
| |||
ObjectSetString(0,name,prop,v);
| |||
}
| |||
| |||
//--- the object `name`: created once, moved only when a point differs, marked as used in this pass.
| |||
//--- npts is 1 or 2. Returns false when the chart refuses the object.
| |||
bool OsPlace(const string name,const ENUM_OBJECT type,const int npts,const datetime t1,const double p1,
| |||
const datetime t2,const double p2)
| |||
{
| |||
if(ObjectFind(0,name)<0)
| |||
{
| |||
bool ok=(npts==1 ? ObjectCreate(0,name,type,0,t1,p1) : ObjectCreate(0,name,type,0,t1,p1,t2,p2));
| |||
if(!ok)
| |||
return(false);
| |||
ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
| |||
ObjectSetInteger(0,name,OBJPROP_HIDDEN,true);
| |||
}
| |||
else
| |||
{
| |||
if(ObjectGetInteger(0,name,OBJPROP_TIME,0)!=(long)t1 || ObjectGetDouble(0,name,OBJPROP_PRICE,0)!=p1)
| |||
ObjectMove(0,name,0,t1,p1);
| |||
if(npts>1 && (ObjectGetInteger(0,name,OBJPROP_TIME,1)!=(long)t2 || ObjectGetDouble(0,name,OBJPROP_PRICE,1)!=p2))
| |||
ObjectMove(0,name,1,t2,p2);
| |||
}
| |||
ObjectSetInteger(0,name,OBJPROP_ZORDER,g_os_gen);
| |||
return(true);
| |||
}
| |||
| |||
//--- delete every object with `prefix` that this pass did not ask for
| |||
void OsEnd(const string prefix)
| |||
{
| |||
for(int i=ObjectsTotal(0,-1,-1)-1; i>=0; i--)
| |||
{
| |||
string nm=ObjectName(0,i);
| |||
if(StringFind(nm,prefix)==0 && ObjectGetInteger(0,nm,OBJPROP_ZORDER)!=g_os_gen)
| |||
ObjectDelete(0,nm);
| |||
}
| |||
}
| |||
| |||
#endif
| |||
//+------------------------------------------------------------------+
|