More EAs for beginners: HawaiianTsunamiSurfer, the statistical look at determinant price explosions

 

Hi there!,

Continuing my MQL5 learning process, today I post this cool EA that works very well on AUDUSD, USDJPY and EURUSD. If you have any question about it, you can comment what you want, I'll check this thread this week to comment whatever.

Once again, comments from experts are welcome!! You can also take a look to this message to get the basis of very very simple EAs: https://www.mql5.com/en/forum/9759


#property copyright     "Author: laplacianlab, CC Attribution-Noncommercial-No Derivate 3.0"
#property link          "https://www.mql5.com/en/forum/ea"
#property version       "1.00"
#property description   "This system, based on Momentum indicator, assumes that very strong price movements are determinant. It consists in riding the appearing tsunamis, for instance, an important US Nonfarm Payrolls release. HawaiianTsunamiSurfer works well on AUDUSD, USDJPY and EURUSD. It also works with a lower performance on USDCHF and GBPUSD."

#include <Trade\Trade.mqh>

//+------------------------------------------------------------------+
//| Var block                                                        |
//+------------------------------------------------------------------+

// MQL5 API vars

CPositionInfo PositionInfo;
CTrade trade;
MqlTick tick;

// EA's vars

enum ENUM_STATUS_EA
  {
   BUY,
   SELL,
   DO_NOTHING
  };

ENUM_STATUS_EA EAStatus;

// Momentum indicator vars

int iMomentumHandler;
double iMomentumBuffer[];

int momentumPeriod = 1;
ENUM_TIMEFRAMES momentumTimeframe = PERIOD_M1;
ENUM_APPLIED_PRICE momentumAppliedPrice = PRICE_CLOSE;

// Graphic bar management

static datetime previousBarTime;
datetime currentBarTime[1];
bool isNewBar = false;

// The following inputs are transparent to the user, they are optimized!
// This EA is very sensible to inputs. Please, don't change them unless you are sure about what you do.

int stopLoss = 700;
int takeProfit = 500;
double tsunamiStrength = 0.24;
double size = 0.1;

int OnInit()
  {  
                
   EAStatus = DO_NOTHING;        
  
   iMomentumHandler = iMomentum(Symbol(), momentumTimeframe, momentumPeriod, momentumAppliedPrice);
   ArraySetAsSeries(iMomentumBuffer, true);
    
   return(0);
  
  }
  
void OnDeinit(const int reason)
  {  
   IndicatorRelease(iMomentumHandler);
   ArrayFree(iMomentumBuffer);
  }
  
void OnTick()
  {
    
   // Let's first check if a new bar has come!
        
   if(CopyTime(_Symbol, _Period, 0, 1, currentBarTime) > 0)
     {
      if(previousBarTime != currentBarTime[0])
        {
         isNewBar = true;
         previousBarTime = currentBarTime[0];
        }
     }
   else
     {
      Alert("Error copying historical data, error: ", GetLastError());
      return;
     }
    
   if(!isNewBar) return;
  
   // We run the operations below only on new bars, that is to say, once per bar.
  
   double tp;
   double sl;      
    
   SymbolInfoTick(_Symbol, tick);
        
   if(CopyBuffer(iMomentumHandler, 0, 0, 2, iMomentumBuffer) < 0)
     {
      Alert("Error copying buffers, error: " , GetLastError());
      return;
     }    
    
   if(!PositionInfo.Select(_Symbol))      
     {
      if (iMomentumBuffer[0] > (100 + tsunamiStrength))
        {
                                  
         EAStatus = SELL;
  
        }  
      else if (iMomentumBuffer[0] < (100 - tsunamiStrength))
        {
            
         EAStatus = BUY;
                          
        }  
     }      
   else EAStatus = DO_NOTHING;

   switch(EAStatus)
     {
      case BUY:
      
         tp = tick.ask + takeProfit * _Point;
         sl = tick.bid - stopLoss * _Point;    
      
         trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, size, tick.ask, sl, tp);
        
         break;
        
      case SELL:
      
         sl = tick.ask + stopLoss * _Point;
         tp = tick.bid - takeProfit * _Point;
        
         trade.PositionOpen(_Symbol, ORDER_TYPE_SELL, size, tick.bid, sl, tp);
      
         break;
        
      case DO_NOTHING:
      
         // Nothing...
      
         break;
     }
    
}
Are you learning MQL5 and want to have a couple of very simple EAs? Here you have my two micro robots!
Are you learning MQL5 and want to have a couple of very simple EAs? Here you have my two micro robots!
  • www.mql5.com
This is the classical trading system which consists in buying when MACD crosses above the waterline line and selling when crosses below it.
 
laplacianlab:

Hi there!,

Continuing my MQL5 learning process, today I post this cool EA that works very well on AUDUSD, USDJPY and EURUSD. If you have any question about it, you can comment what you want, I'll check this thread this week to comment whatever.

Once again, comments from experts are welcome!! You can also take a look to this message to get the basis of very very simple EAs: https://www.mql5.com/en/forum/9759

1. Obviously to me, you did not read my answer number 4 for in  Are you learning MQL5 and want to have a couple of very simple EAs? Here you have my two micro robots! So your code here, will only open sell or will only open buy, but will not open buy then open sell or vice versa.

Close opposite position - if there's any - before opening a position using CTrade PositionClose

2. Also my answer number 5, which is checking the result using CheckResult if opening position is fail or not.

3. In another ways, you can make a simple code like this

   if(!PositionInfo.Select(_Symbol))      
     {
      if (iMomentumBuffer[0] > (100 + tsunamiStrength))
        {
                                  
         OPENING_POSITION(SELL);
  
        }  
      else if (iMomentumBuffer[0] < (100 - tsunamiStrength))
        {
            
         OPENING_POSITION(BUY);
                          
        }  
     }      
   else EAStatus = DO_NOTHING;

Then just outside OnTick(), I'll code my user defined function OPENING_POSITION()

int OPENING_POSITION (int ea_status)
   {
   switch(EAStatus)
     {
      case BUY:

         if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) PositionClose (_Symbol, 10);
      
         tp = tick.ask + takeProfit * _Point;
         sl = tick.bid - stopLoss * _Point;    
      
         trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, size, tick.ask, sl, tp);
        
         return;
        
      case SELL:
      
         if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) PositionClose (_Symbol, 10);
      
         sl = tick.ask + stopLoss * _Point;
         tp = tick.bid - takeProfit * _Point;
        
         trade.PositionOpen(_Symbol, ORDER_TYPE_SELL, size, tick.bid, sl, tp);
      
         return;
        
      case DO_NOTHING:
      
         // Nothing...
      
         return;
     }

   return (false);
   }

I write those code using SRC button, not compiled and not tested.

 

Thank you very much for your help! :)

Your reply poses some doubts.

1. I think I'm aware about what you say regarding the EA's strategy. My code there opens any position (buy or sell) and then waits until the sl or tp limits are reached. Once the position is closed, opens another buy or sell position depending on the upcoming wave. On other words, and as far as I understand things right now

if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) PositionClose (_Symbol, 10);

would be redundant because at this point the robot is absolutely sure there's no positigion thanks to  if(!PositionInfo.Select(_Symbol))   

Is it necessary to use CTrade PositionClose if you previously check the existence/unexistence of a position with the help of if(!PositionInfo.Select(_Symbol))? Logically speaking, there's no need to close a position if you are absolutely sure that there's no existing position... In fact, I took that fragment of code of some Code Base EA's once I got a similar conclusion.

 

2. I take note of CheckResult, I'll use it from now. As I say, I've seen some robots that don't use that function.

 

3. I would pack code in functions when it is potentially reusable. In this case, as the code is very strategy-dependent (it is likely only going to be used in this robot) I dont pack in a function, though maybe the final result is more readable and understandable.

I would thank an answer regarding if(!PositionInfo.Select(_Symbol))  and PositionClose, aren't they equivalent? Am I understanding things well? As I say, I saw at Code Base many EAs that only use the former.  

Thank you very much.  

Documentation on MQL5: Standard Constants, Enumerations and Structures / Trade Constants / Position Properties
Documentation on MQL5: Standard Constants, Enumerations and Structures / Trade Constants / Position Properties
  • www.mql5.com
Standard Constants, Enumerations and Structures / Trade Constants / Position Properties - Documentation on MQL5
 
laplacianlab:

Thank you very much for your help! :)

Your reply poses some doubts.

1. I think I'm aware about what you say regarding the EA's strategy. My code there opens any position (buy or sell) and then waits until the sl or tp limits are reached. Once the position is closed, opens another buy or sell position depending on the upcoming wave. On other words, and as far as I understand things right now

if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) PositionClose (_Symbol, 10);

would be redundant because at this point the robot is absolutely sure there's no positigion thanks to  if(!PositionInfo.Select(_Symbol))   

Is it necessary to use CTrade PositionClose if you previously check the existence/unexistence of a position with the help of if(!PositionInfo.Select(_Symbol))? Logically speaking, there's no need to close a position if you are absolutely sure that there's no existing position... In fact, I took that fragment of code of some Code Base EA's once I got a similar conclusion.

 

2. I take note of CheckResult, I'll use it from now. As I say, I've seen some robots that don't use that function.

 

3. I would pack code in functions when it is potentially reusable. In this case, as the code is very strategy-dependent (it is likely only going to be used in this robot) I dont pack in a function, though maybe the final result is more readable and understandable.

I would thank an answer regarding if(!PositionInfo.Select(_Symbol))  and PositionClose, aren't they equivalent? Am I understanding things well? As I say, I saw at Code Base many EAs that only use the former.  

Thank you very much.  

On point 1, you smarter than me now (No need to close if PositionSelect is false). I answer that way because I have different strategy, I don't set TP for my position, and I don't like my position get closed by SL, so I close that position either by trailing my SL or when opening opposite position. 

About function. you should create universal EA, with several function written in include. Basically EA just consist of 1] Collecting data 2] Comparing that data 3] Executing that data. Universal EA is about point # 3.

That way, you can create several EA from single copy of universal EA with different CI.

CPositionInfo::select is a method from CPositionInfo Class, which using mql5 function PositionSelect which is checking if there's an open position with that symbol. PositionClose is a method from CTrade class that basically open opposite position with same lot value.

Find their codes in include/Trade/    PositionInfo.mqh and Trade.mqh  and you will see that they are not the same


 
Thank you, your comments are always helpful! I am happy to know that logically speaking  if(!PositionInfo.Select(_Symbol)) is equivalent to what you say.
Reason: