Water EA

Place your new trading idea here to see if someone can automate it.
User avatar
SteveHopwood
Owner
Posts: 9754
Joined: Tue Nov 15, 2011 8:43 am
Location: Misterton - an insignificant village in England. Very pleasant to live in.

Water EA

Post by SteveHopwood »

A little more clarification.

You are depending on the host chart receiving a quote from your broker if you run an EA with your code in the OnTick() event. Masses of stuff can be happening to the other pairs and your bot will not pick them up.

The solution is the OnTimer() function. You have to add this yourself:

Code: Select all

void OnTimer()
{
     //Call all your functions that were previously called from OnTick(). 
     //OnTick() will be empty.

}//End void OnTimer()
The compiler needs to know how often to fire OnTimer(). You can make this a user input choice. You will see this input in all my multi-pair bots:

Code: Select all

extern int              EventTimerIntervalSeconds=1;
I want the function called once a second. Then you go to OnInit() to add the code that runs the timer. Mine is this:

Code: Select all

   //create timer
   //EventSetTimer(EventTimerIntervalSeconds);
   secureSetTimer(EventTimerIntervalSeconds);//Explanation at the top of the function
The second comment is the CrapQl4 code. It turns out that this can fail when running on a VPS, so the call is made to a function that will keep on trying until it succeeds. Explanation in the comments:

Code: Select all

bool secureSetTimer(int seconds) 
{

   //This is another brilliant idea by tomele. Many thanks Thomas. Here is the explanation:
/*
I am testing something René has developed on Eaymon's VPS as well as on Google's VPS. I ran into a problem with EventSetTimer(). 
This problem was reported by other users before and apparently occurs only on VPS's, not on desktop machines. The problem is that 
calls to EventSetTimer() eventually fail with different error codes returned. The EA stays on the chart with a smiley (it 
is not removed), but no timer events are sent to OnTimer() and the EA doesn't act anymore. 

The problem might be caused by the VPS running out of handles. A limited number of these handles is shared as a pool 
between all virtual machines running on the same host machine. The problem occurs randomly when all handles are in use 
and can be cured by repeatedly trying to set a timer until you get no error code.

I have implemented a function secureSetTimer() that does this. If you replace EventSetTimer() calls with secureSetTimer() 
calls in the EA code, this VPS problem will not affect you anymore:

*/   
   
   int error=-1;
   int counter=1;
   
   do
   {
      EventKillTimer();
      ResetLastError();
      EventSetTimer(seconds);
      error=GetLastError();
      Print("secureSetTimer, attempt=",counter,", error=",error);
      if(error!=0) Sleep(1000);
      counter++;
   }
   while(error!=0 && !IsStopped() && counter<100);
   
   return(error==0);
}

There are a couple of weird thingies that coders need to know. The first concerns dividing integers.

In the rational world, the result of dividing 1 by 2 is 0.5, even if the result is held in a double so,
double someNumber = 1 /2;
results in someNumber being zero, not 0.5

The second concerns comparing doubles. Suppose you declare two doubles i.e.

Code: Select all

double num1 = 0, num2 = 0;
At some point in the code you need to compare the two, so:

Code: Select all

if (num1 == num2)
{
      //Do something
}
This should result is the something you want doing should be done. So imagine that both numbers are 25. They are equal, so the something should get done, yet sometimes it does not.

Variable declared as 'double' have 8 decimal points, so the equation should be comparing two values of 25.00000000 each. The compiler sometimes adds an extra 1 to the final decimal point, so one of the numbers might contain 25.00000001. They are unequal so the equation fails. Sane programming languages have the fix for this installed. CrapQl4 doesn't, or at least did not, so we have a function provided by garyfritz a long time ago:

Code: Select all

bool closeEnough(double num1,double num2)
{
/*
   This function addresses the problem of the way in which mql4 compares doubles. It often messes up the 8th
   decimal point.
   For example, if A = 1.5 and B = 1.5, then these numbers are clearly equal. Unseen by the coder, mql4 may
   actually be giving B the value of 1.50000001, and so the variable are not equal, even though they are.
   This nice little quirk explains some of the problems I have endured in the past when comparing doubles. This
   is common to a lot of program languages, so watch out for it if you program elsewhere.
   Gary (garyfritz) offered this solution, so our thanks to him.
   */

   if(num1==0 && num2==0) return(true); //0==0
   if(MathAbs(num1 - num2) / (MathAbs(num1) + MathAbs(num2)) < 0.00000001) return(true);

//Doubles are unequal
   return(false);

}//End bool closeEnough(double num1, double num2)

The call to the function now becomes:

Code: Select all

if (closeEnough(num1, num2) )
{
      //Do something
}
There is a little more rock_bottom_basic stuff you need to know, but I will present you with it tomorrow.

:xm: :rocket:
Read the effing manual, ok?

Afterprime is the official SHF broker. Read about them at https://www.stevehopwoodforex.com/phpBB3/viewtopic.php?p=175790#p175790.

I still suffer from OCCD. Good thing, really.

Anyone here feeling generous? My paypal account is always in the market for a tiny donation. [email protected] is the account.

To see The Weekly Roundup of stuff you guys might have missed Click here

My special thanks to Thomas (tomele) for all the incredible work he does here.
User avatar
SteveHopwood
Owner
Posts: 9754
Joined: Tue Nov 15, 2011 8:43 am
Location: Misterton - an insignificant village in England. Very pleasant to live in.

Water EA

Post by SteveHopwood »

Some more of the stuff not usually mentioned in coding lessons or Mql4 documentation.

Two thingies that will stop your code executing are: division by zero; the Array out of range error. These stop your EA in its tracks without telling you, so you think it is still running. This is why all mine have the time display on the chart; the EA has stopped if the time is not updating. Thomas flashes, "Active" to show that TDesk is running.

Use a conditional if there is any chance of the divisor being 0 i.e.

Code: Select all

double num1, num2, num3;
if (!closeEnough(num2, 0) )
    num3 = num1 / num2;
This nasty little trick is the reason I used Tommas and Rene's double getPipFactor(string symbolName) to generate a value for the 'factor' variable I used in place of 'Point'.

This is the standard use of Point in a single pair trader and always works:
double take = NormalizeDouble(Ask + (takeProfit * Point), Digits);

We need to find the value of Point differently in a multi pair trader such as SPB. Here, the code would be:

Code: Select all

double point = MarketInfo(symbol, MODE_POINT);
The problem with this is that it often fails, returning zero instead of the real value of Point, causing a divide by zero error if you are dividing, that you did not think could happen. We use 'factor' as a divisor when converting pips to points and multiplier when going from points to pips so:

Code: Select all

double take  = NormalizeDouble(ask + (takeProfit / factor), digits);
The array out of range error happens if you try to use the final element in the array so:

Code: Select all

int someArray[4];
someArray[4] = 15;
would generate the error.

You will see the errors in the Experts tab, along with the line number in the code that generated it.

:xm: :rocket:
Read the effing manual, ok?

Afterprime is the official SHF broker. Read about them at https://www.stevehopwoodforex.com/phpBB3/viewtopic.php?p=175790#p175790.

I still suffer from OCCD. Good thing, really.

Anyone here feeling generous? My paypal account is always in the market for a tiny donation. [email protected] is the account.

To see The Weekly Roundup of stuff you guys might have missed Click here

My special thanks to Thomas (tomele) for all the incredible work he does here.
wallywonka
Trader
Posts: 176
Joined: Thu May 12, 2016 7:46 am

Water EA

Post by wallywonka »

Appreciate all of these posts Steve, very informative stuff! :clap:
User avatar
SteveHopwood
Owner
Posts: 9754
Joined: Tue Nov 15, 2011 8:43 am
Location: Misterton - an insignificant village in England. Very pleasant to live in.

Water EA

Post by SteveHopwood »

Here is a nasty little trick that our beloved platform has up its sleeve and which it is essential to know about.

A trade shows up in our trades window as soon as it is opened but this is a mirage. It is not safely tucked away in the memory location that an EA interrogates for open trades until the platform receives a return receipt from the broker's server. This can take some time to arrive.

So here is what happens:
  • There is a trade signal generated.
  • The EA checks that there is not already an open trade, finds there is not one, yells, "Yippee, time to party" and sends a trade.
  • The receipt is not returned by the broker's server for a while. There is another tick. The EA checks that there is not already an open trade, finds there is not one, yells, "Yippee, time to party" and sends a trade.
This can happen many times before the return receipt for the original trade arrives - I have seen instances of over 100. The spread costs overwhelm the equity and there is a margin call the first time the market moves in the wrong direction - and it never moves in the right one under these circumstances.

We discovered this in the early years of SHF. It has not been a problem since because none of us would bother to have nightmares about not including code to combat it.

This has not been an issue lately because we have been writing so many multi-pair EA's that mostly send off stop orders. It is a huge problem when you are writing single pair bots.

PostTradeAttemptWaitSeconds that defaults to 10 minutes. This tells the bot to wait for ten minutes after attempting to send a trade regardless of whether or not the order send was successful.

Further down is this:

Code: Select all

extern int     MinMinutesBetweenTradeOpenClose=1;//For spotting possible rogue trades
and its associated variables:

Code: Select all

bool           SafetyViolation;//For chart display
bool           RobotSuspended=false;

All my shells and hence single pair EA's have this input, defaulting to 1 minute. This is a defence for novice coders, against faulty coding. The most likely scenario is coding the trade trigger incorrectly, sending a buy when the EA should be sending a sell. The EA spots this at the next tick and instantly closes the trade, costing the spread. This will continue until you notice.

My code includes a check on the most recently closed trade and declares it a 'rogue' trade if it opened and closed inside one minute. It then displays a warning on the chart feedback display and sounds an alert.

All this happens automatically if you are using my shells to write an EA, at viewtopic.php?p=803#p803 Or you can hack the attached - just search for the inputs/variables to see how I code their use.

:xm: :rocket:
You do not have the required permissions to view the files attached to this post.
Read the effing manual, ok?

Afterprime is the official SHF broker. Read about them at https://www.stevehopwoodforex.com/phpBB3/viewtopic.php?p=175790#p175790.

I still suffer from OCCD. Good thing, really.

Anyone here feeling generous? My paypal account is always in the market for a tiny donation. [email protected] is the account.

To see The Weekly Roundup of stuff you guys might have missed Click here

My special thanks to Thomas (tomele) for all the incredible work he does here.
Post Reply

Return to “Ideas for Possible Automation”