!Control
Download scriptThis script is designed to synchronize visual elements on your trading charts across different windows or platforms. Essentially, it allows for a "mirroring" effect where objects created on one chart can be automatically replicated and updated on another.
How the Logic Works
The script functions by designating one terminal window as a Writer and others as Listeners. It uses a shared data file to facilitate this communication.
1. The Communication System
The script identifies whether it should act as a sender or receiver based on specific internal variables.
- The Writer: This is the "source" chart. When you add, move, or modify an object (like a trend line, rectangle, or text label), the Writer captures all the details of that object.
- The Listener: These are the "destination" charts. They constantly check the data file to see if there are any updates from the Writer.
2. Data Capturing (Writing)
When the script identifies itself as a Writer, it scans your current chart for all visual objects. It gathers detailed information about each one, including:
- The unique name of the object.
- The type of object (e.g., an arrow vs. a line).
- Detailed coordinates and visual properties (colors, styles, sizes, etc.). This information is then saved into a shared text file.
3. Synchronization (Listening)
When the script acts as a Listener, it performs a continuous "check and update" loop:
- Object Creation: If the Listener sees an object in the data file that doesn't exist on its current chart, it automatically creates it.
- Property Updating: If the object already exists, the script compares the properties of the local object with the data from the Writer. If anything is different (like a moved price point or a changed color), the Listener updates the local object to match the source perfectly.
- Cleanup: The script also performs a cleanup routine. If an object exists on the chart but is no longer present in the Writer's data file, it removes the "extra" object to ensure the charts remain identical.
4. Performance and Execution
The script runs in the background, checking for updates every second. It includes a refresh mechanism that tells the platform to redraw the screen immediately whenever an update occurs, ensuring that the visual changes appear seamless and near-instantaneous to the user.
//+------------------------------------------------------------------+
//| Dupel.mq4 |
//| Copyright © 2009, Ñåðãååâ Àëåêñåé |
//| mailto: profy.mql@gmail.com |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2009, Ñåðãååâ Àëåêñåé"
#property link "mailto: profy.mql@gmail.com"
int i, j, type, w;
string name, st, var;
int obj, fo;
double d;
bool b, bNeedUpdate;
int gType, sType;
string gText, sText;
double gProp[232], sProp[232];
string names[1000];
//------------------------------------------------------------------
int start()
{
while(!IsStopped())
{
Sleep(1000);
bNeedUpdate=false;
//ñîõðàíÿåì
var="DupelSync_"+Symbol()+Period();
if (!GlobalVariableCheck("DupelSync")) GlobalVariableSet("DupelSync", 0); // ñîçäà¸ì, åñëè íåò
if (!GlobalVariableCheck("DupelSync_"+Symbol()+Period())) GlobalVariableSet("DupelSync_"+Symbol()+Period(), -1); // ñîçäà¸ì, åñëè íåò
if (GlobalVariableGet(var)>0) // åñëè ýòà âàëþòà ïèñàòåëü
{
Comment("writter");
if (GlobalVariableSetOnCondition("DupelSync", 1, 0))
{
obj=FileOpen("DupelSync.txt", FILE_CSV|FILE_WRITE);
if (obj<0) { Print("Íå ñìîãëè çàïèñàòü!"); GlobalVariableSet("DupelSync", 0); continue; }
FileSeek(obj, 0, SEEK_SET);
for (i=0; i<ObjectsTotal(); i++)
{
name=ObjectName(i);
if (ObjectFind(name)!=0) continue; // áåð¸ì òîëüêî ãëàâíîå îêíî
FileWrite(obj, name); // ñîõðàíèëè èìÿ
FileWrite(obj, ObjectType(name)); // ñîõðàíèëè òèï
FileWrite(obj, ObjectDescription(name)); // ñîõðàíèëè îïèñàíèå
for (j=0; j<=16; j++) FileWrite(obj, DoubleToStr(ObjectGet(name, j), Digits));
for (j=100; j<=103; j++) FileWrite(obj, DoubleToStr(ObjectGet(name, j), Digits));
for (j=200; j<=203; j++) FileWrite(obj, DoubleToStr(ObjectGet(name, j), Digits));
for (j=210; j<=231; j++) FileWrite(obj, DoubleToStr(ObjectGet(name, j), Digits));
}
FileClose(obj);
GlobalVariableSet("DupelSync", 0);
}
}
if (GlobalVariableGet(var)<=0) // åñëè ýòà âàëþòà ÷èòàòåëü
{
Comment("lister");
if (GlobalVariableSetOnCondition("DupelSync", 1, 0))
{
obj=FileOpen("DupelSync.txt", FILE_CSV|FILE_READ);
if (obj<0) { Print("íå ñìîãëè îòêðûòü"); GlobalVariableSet("DupelSync", 0); continue; }
// ñðàâíèâàåì íàëè÷èå îáúåêòîâ
w=0;
FileSeek(obj, 0, SEEK_SET);
while (!FileIsEnding(obj)) // ÷èòàåì äàííûå îáúåêòîâ èç ôàéëà
{
names[w]=FileReadString(obj); if (names[w]=="") break;
w++;
st=FileReadString(obj); // òèï îáúåêòà
st=FileReadString(obj); // òåêñò
for (j=0; j<=16; j++) st=FileReadString(obj); for (j=100; j<=103; j++) st=FileReadString(obj);
for (j=200; j<=203; j++) st=FileReadString(obj); for (j=210; j<=231; j++) st=FileReadString(obj);
}
// ïðîõîäèì ïî òåêóùèì è ñðàâíèâàåì íàëè÷èå îáúåêòîâ
for (i=0; i<ObjectsTotal(); i++)
{
b=true;
name=ObjectName(i); // ïîëó÷èëè èìÿ
if (ObjectFind(name)>0) continue; // åñëè îáúåêò íå íà ãëàâíîì ãðàôèêå, òî ïðîïóñêàåì
for(j=0; j<w; j++) if (name==names[j]) b=false; // åñëè íàøëè îáúåêò, òî ïðîïóñêàåì
if (b) { ObjectsDeleteAll(0, -1); bNeedUpdate=true; break; } // óäàëÿåì âñå ëèøíèå îáúåêòû
}
// òåïåðü êîïèðóåì ñâîéñòâà
FileSeek(obj, 0, SEEK_SET);
while (!FileIsEnding(obj)) // ÷èòàåì äàííûå îáúåêòîâ èç ôàéëà
{
b=false;
name=FileReadString(obj); if (name=="") break; // èìÿ îáúåêòà
gType=StrToInteger(FileReadString(obj)); // òèï îáúåêòà
gText=FileReadString(obj); // òåêñò îáúåêòà
for (j=0; j<=16; j++) gProp[j]=StrToDouble(FileReadString(obj)); for (j=100; j<=103; j++) gProp[j]=StrToDouble(FileReadString(obj));
for (j=200; j<=203; j++) gProp[j]=StrToDouble(FileReadString(obj)); for (j=210; j<=231; j++) gProp[j]=StrToDouble(FileReadString(obj));
if (ObjectFind(name)<0) { ObjectCreate(name, gType, 0, 0, 0); b=true; bNeedUpdate=true; }
else
{
// áåð¸ì äàííûå
sType=ObjectType(name); // òèï îáúåêòà
sText=ObjectDescription(name); // òåêñò îáúåêòà
for (j=0; j<=16; j++) sProp[j]=ObjectGet(name, j); for (j=100; j<=103; j++) sProp[j]=ObjectGet(name, j);
for (j=200; j<=203; j++) sProp[j]=ObjectGet(name, j); for (j=210; j<=231; j++) sProp[j]=ObjectGet(name, j);
if (IsDifObject()) { b=true; bNeedUpdate=true; }// åñëè îáúåêòû îòëè÷àþòñÿ, òî áóäåì îáíîâëÿòü
}
if (b)
{
ObjectSetText(name, gText);
for (j=0; j<=16; j++) ObjectSet(name, j, gProp[j]); for (j=100; j<=103; j++) ObjectSet(name, j, gProp[j]);
for (j=200; j<=203; j++) ObjectSet(name, j, gProp[j]); for (j=210; j<=231; j++) ObjectSet(name, j, gProp[j]);
}
}
FileClose(obj); // çàêðûëè ôàéë
GlobalVariableSet("DupelSync", 0); // ðàçðåøèëè ðàáîòó ñ ôàéëîì
if (bNeedUpdate) WindowRedraw(); // ïåðåðèñîâàëè
}
}
}
return(0);
}
//+------------------------------------------------------------------+
bool IsDifObject()
{
int j;
if (gType!=sType) return (true);
if (gText!=sText) return (true);
for (j=0; j<=16; j++) if (gProp[j]!=sProp[j]) return (true);
for (j=100; j<=103; j++) if (gProp[j]!=sProp[j]) return (true);
for (j=200; j<=203; j++) if (gProp[j]!=sProp[j]) return (true);
for (j=210; j<=231; j++) if (gProp[j]!=sProp[j]) return (true);
}
Comments