Disallowing multiple EA instances in one terminal - page 2

 
zzuegg:
i might be wrong, but this seems to be the first scenario where i would use a GlobalVariable

You make a good point, given that Fromin explicitly limits his/her requirements to "in one MT4 terminal at once".

The file-locking route has the disadvantages of complexity and requiring "Allow DLL imports" to be turned on. However, it also has three small advantages:

* If MT4 crashes or an EA/script shuts down in a disorderly fashion, a global-variable lock will remain in place and have to be manually removed. The file-based lock can be done in a way which is automatically freed when MT4 terminates.

* The file-based method is more future-proof; it offers the possibility of extending the locking beyond the single MT4 instance.

* I'm not 100% sure that MT4 synchronises access to global variables. If you have two EAs starting at exactly the same time, e.g. because MT4 is starting up with EAs already in place on its charts, then it may be possible for both EAs to think that the lock is free because e.g. they both call GlobalVariableCheck() before either of them then goes on to acquire a lock by calling GlobalVariableSet(). Or, depending on how you code it, two simultaneous calls to GlobalVariableSet() might both return 0.

 
jjc:

However, it also has three small advantages: [...]

Of course, there's also a fourth difference which could either be an advantage or disadvantage as far as Fromin is concerned:

* It's very easy for the user to manually override a global-variable lock and allow multiple EAs to trade at once. Whereas a lock which is done by having or not having an open file handle (i.e. my version of the code) requires specialist tools to override.
 
jjc:

You make a good point, given that Fromin explicitly limits his/her requirements to "in one MT4 terminal at once".

The file-locking route has the disadvantages of complexity and requiring "Allow DLL imports" to be turned on. It has three small advantages over global variables:

* If MT4 crashes or an EA/script shuts down in a disorderly fashion, a global-variable lock will remain in place and have to be manually removed. The file-based lock can automatically be freed when MT4 terminates.

* The file-based method is more future-proof; it offers the possibility of extending the locking beyond the single MT4 instance.

* I'm not 100% sure that MT4 synchronises access to global variables. If you have two EAs starting at exactly the same time, e.g. because MT4 is starting up with EAs already in place on its charts, then it may be possible for both EAs to think that the lock is free because e.g. they both call GlobalVariableCheck() before either of them then goes on to acquire a lock by calling GlobalVariableSet(). Or, depending on how you code it, two simultaneous calls to GlobalVariableSet() might both return 0.

Hi, i agree with the crash situation, which your file lock mechanism would handle nicely. Good point here is that you only lock the file but don't write anything into it. Could be tricked out by writing the actual time in the global variable and if there was no update in the last X minutes the EA could regain operation status.

GlobalVariableSetOnCondition() operations seems (according to the doc) providing atomic access so the syncho will not be a problem.

I personally would go for the GlobalVar() solution, but maybe because i don't want to use dll's if possible. I had to many problems when switching form xp to win7 to wine (operating in osx)

 
jjc:
Of course, there's also a fourth difference which could either be an advantage or disadvantage as far as Fromin is concerned:

* It's very easy for the user to manually override a global-variable lock and allow multiple EAs to trade at once. Whereas a lock which is done by having or not having an open file handle (i.e. my version of the code) requires specialist tools to override.
not really, if the checkup() would be made at every tick (it is not an expensive function) it would be guaranteed that only one instance is allowed simultaneously
 
zzuegg:

GlobalVariableSetOnCondition() operations seems (according to the doc) providing atomic access so the syncho will not be a problem. [...]

You're right. I'd forgotten about GlobalVariableSetOnCondition(). It ought to be possible to do the following, though this route is vulnerable to abuse if you can delete the global variable and start a second EA in between ticks to the first EA. Relatively easy to do overnight or at the start/end of the week. Both EAs then believe that they're in control of the global variable. Protecting against that would complicate the code yet further.

#define LOCKNAME     "glbvar"

bool glbAcquiredLock = false;

void init()
{
   if (GlobalVariableCheck(LOCKNAME)) {
      // Another EA owns the lock. Failed.
   } else {
      GlobalVariableSet(LOCKNAME, 0);
      if (GlobalVariableSetOnCondition(LOCKNAME, 1, 0)) {
         // Successfully got lock
         glbAcquiredLock = true;
      } else {
         // Another EA has started simultaneously, and it won the race
         // to get the lock. Failed.
      }
   }
}

void deinit()
{
   // Release the lock on exit. MUST ONLY DO THIS IF WE HAVE THE LOCK, or else
   // it breaks the EA which does have the lock.
   if (glbAcquiredLock) GlobalVariableDel(LOCKNAME);
}

void start()
{
   if (glbAcquiredLock) {
      // The gv should continue to exist...
      if (!GlobalVariableCheck(LOCKNAME)) {
         // Ooops. The lock has been damaged.
         glbAcquiredLock = false;
      } else {
         // Still have the lock
      }
   } else {
      // Don't have the lock
   }
}
 

That issue is easy to ship around.

If the GlobalVariable is not existend, simply create it and set it to unlocked, of course at this moment you don't have the lock. Afterwards you can use GVSetOncondition to lock it.

The only problem with your routine is when you start two EA's simultaneosly and both pass the first GlobalVariableCheck() call. Theoretically it would be possible that both of the EA's are able to get a lock.

sorry for the formatting, i typed it here in the comment box.

#define MODE_INIT 1
#define MODE_FREE 2
#define MODE_LOCK 3
#define GVLOCK "gvEaLock"

void init(){
 if(GlobalVariableCheck(GVLOCK)){
   GlobalVariableSetOnCondition(GVLOCK,MODE_FREE,MODE_INIT);
 }else{
   GlobalVariableSet(GVLOCK,MODE_INIT);
   GlobalVariableSetOnCondition(GVLOCK,MODE_FREE,MODE_INIT);
 }
}


bool hasLock=false;
void start(){
 if(GlobalVariableCheck(GVLOCK)){
   if(hasLock){
     
   }else{
     if(GlobalVariableSetOnCondition(GVLOCK,MODE_LOCK,MODE_FREE)){
       //Hurray, got lock
       hasLock=true;
     }
   }   
 }else{
  //Global Var not found. Creating uninitialized
  hasLock=false;
  GlobalVariableSet(GVLOCK,MODE_INIT);
  GlobalVariableSetOnCondition(GVLOCK,MODE_FREE,MODE_INIT) 
  }
}

void deinit(){
 if(hasLock){
   GlobalVariableSetOnCondition(GVLOCK,MODE_FREE,MODE_LOCK)
 }
}
 
zzuegg:

If the GlobalVariable is not existend, simply create it and set it to unlocked, of course at this moment you don't have the lock. Afterwards you can use GVSetOncondition to lock it.

Much the same problem. In your code, once an EA reaches the state where hasLock == true then it's still the case that all it is does is a check for the existence of the global variable. The way to cheat your code is as follows:

  • Set one EA running, and wait until it gets into a state where hasLock == true.
  • Turn off the "Expert Advisors" button, and start the EA on a second chart. The init() function will run in the second EA despite the fact that EAs are turned off, but neither the first nor second EAs will then get any calls to start().
  • Manually set the global variable to MODE_FREE, and then turn EAs back on.
  • The first EA will continue with hasLock == true, and doesn't care about anything apart from the fact that the global variable still exists.
  • The second EA will try doing GlobalVariableSetOnCondition() to turn MODE_FREE into MODE_LOCK, which will succeed. Both EAs will then believe that they have the lock.


The only significant point is that all this is close to becoming more complex than the equivalent file I/O code. If you strip out all the stuff from my earlier example which isn't directly relevant to the single-instance scenario, then it's very debatable which is more complicated.

 
jjc:

The only significant point is that all this is close to becoming more complex than the equivalent file I/O code. If you strip out all the stuff from my earlier example which isn't directly relevant to the single-instance scenario, then it's very debatable which is more complicated.

The file I/O route for a single-instance solution looks like this. There's a very strong argument that this is simpler than global variables, and while it does require "Allow DLL imports" to be turned on, it's not using DLLs in the usual worry-inducing sense of custom DLLs which are prone to be flaky and cause MT4 to crash. It's not actually necessary to delete the lock file, and therefore you could save three further lines of code by removing the import of DeleteFile(); the global variable which holds the filename; and the use of DeleteFile() in deinit().

#define  LOCKNAME                "myea"

// Kernel constants and imports
#import "kernel32.dll"
   int CreateFileA(string Filename, int AccessMode, int ShareMode, int PassAsZero, int CreationMode, int FlagsAndAttributes, int AlsoPassAsZero);
   int CloseHandle(int);
   string DeleteFile(string);
#import

// Global variables holding the file handle and file name. It's not actually
// necessary to record and then delete the file.
int glbLockFileHandle = -1;
string glbLockFileName = "";


void init()
{
   // Single-instance solution, therefore we can just create the file in experts\files
   glbLockFileName = TerminalPath() + "\\experts\\files\\" + LOCKNAME + ".dat";

   // Try opening the file for writing, with exclusive access. This will fail, returning -1,
   // if the file is already in use by another EA.
   glbLockFileHandle = CreateFileA(glbLockFileName, 1073741824, 0, 0, 2, 0, 0);
}

// EA termination. Remove the lock.
void deinit()
{
   // Close the handle to the file, releasing the lock
   CloseHandle(glbLockFileHandle);
   
   // Delete the file (not actually required; just included for general cleanliness)
   DeleteFile(glbLockFileName);
}

// EA per-tick handling. Check for the existence of the lock.
void start()
{
   if (glbLockFileHandle == -1) {
      Comment("FAILED TO ACQUIRE LOCK during init(): " + glbLockFileName);
   } else {
      Comment("Got lock during init() using file: " + glbLockFileName);
   }
}
 

You are right, i missed that point.

Since the EA's have no options to identify itself by some unique number all those options will fail.
Your file lock seems to be the only valid solution in addition with the options to lock more then one mt4 instance

 

can someone help me edit sar ohlc to use heiken ashi ohlc

Hi, I have an MTF indicator that uses sar, however I'd like the sar to calculate heiken ashi ohlc, and not the normal type

Can you tell me how I can do this, my mtf indicator calls to the sar indicator to calculate sar formula, I think it is calling to the internal indicator in mt4 that can not edit

you can skype or email if you can assist and like to talk about it

skype sty671

email sty671@gmail.com

I can also supply the original file that I'm trying to use heiken ashi ohlc for

Reason: