Elder-Ray (Bulls Power and Bears Power)

Vladimir Karputov | 4 October, 2018

Introduction

Elder-Ray trading system was described by Alexander Elder in his book "Trading for a Living". It is based on Bulls Power and Bears Power oscillators, as well as Moving Average trend-following indicator (EMA — exponential averaging).

The system is both simple and complex:

In this article, we will go through all the stages from simple to complex and check two types of trading system: 

  1. all indicators on the same chart (and therefore, on a single timeframe);
  2. in combination with the "Triple choice" system.

The EAs in the article are meant for working with netting accounts only. 


Key points

To grasp the idea behind the trading system, it is necessary to understand each Elder-Ray element: price, EMA, highs and lows of Bulls Power and Bears Power indicators at each bar, as well as the strength of bulls and bears.


Option 1: All indicators on a single chart

We will explore futures and stocks on the D1 timeframe. All three indicators (Bulls Power, Bears Power and EMA) are placed on a single chart. The averaging period of all indicators is 13.


Buy rules

CATDaily Buy signals

CAT, Daily Buy signals

Sell rules

CATDaily Sell signal

CAT, Daily Sell signals


Trading rules

Looking at Figures 1 and 2, we can see that in the option "All indicators on a single chart", the buy and sell rules are triggered at roll-backs on a stable trend. There are quite a few such favorable moments, especially since the analyzed timeframe is D1. Therefore, in the option "All indicators on a single chart", we need to analyze a very large number of instruments to increase the frequency of transactions on a trading account.

D1 charts also have a considerable advantage: analysis of EMA slope, as well as Bulls Power and Bears Power indicators, can be performed only once a day — when a new bar appears. This is exactly how the EA is to work: wait for a new bar on D1 at each specified symbol and look for possible entries after that. 

Since futures and stocks are traded only in netting mode, oppositely directed positions (hedging) cannot be applied here, but we can increase position volume. The EA can trade on the current symbol only or on several symbols stored in the text file. While all is clear with the current symbol, selecting several symbols may present the following issues:

How to select all symbols from one market? Suppose, we have "CAT" symbol located at "Stock Markets\USA\NYSE/NASDAQ(SnP100)\CAT"

Symbols Specification

Suppose that this symbol suits us, and we want to select all other instruments from the "\NYSE/NASDAQ(SnP100)\" branch. In this case, we can do the following:

  1. open the chart of this symbol;
  2. launch the script (let's name it Symbols on the specified path.mq5) that will receive the symbol path (in the above example, for "CAT" symbol, it is "Stock Markets\USA\NYSE/NASDAQ(SnP100)") and save all symbols from the obtained path to the text file. The text file is to be saved to the Common Data Folder;
  3. it only remains to set the text file name in the EA settings.
If we need symbols from several markets, then run the script on each of the markets (list of symbols is saved to its unique file) and combine both text files manually.

Implementation of the Symbols on the specified path.mq5 script is to be described below.


Assembling the EA. Option 1: All indicators on a single chart

Symbols on the specified path.mq5 — script to be used for obtaining the text file with the symbols. 

NOTE: only the text "Everything is fine. There are no errors" in the Experts tab guarantees that the script's work has been successful, and the obtained file with symbols can be used for the EA operation!

To shorten the code of file operations, the CFileTxt class is connected, and the work with the text file is performed by m_file_txtCFileTxt class object. The script performs its work in seven steps:

//+------------------------------------------------------------------+
//|                                Symbols on the specified path.mq5 |
//|                              Copyright © 2018, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2018, Vladimir Karputov"
#property link      "http://wmua.ru/slesar/"
#property version   "1.002"
#property script_show_inputs
//---
#include <Files\FileTxt.mqh>
CFileTxt       m_file_txt;                   // file txt object
//--- input parameters
input string   InpFileName="Enter a unique name.txt";  // File name
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- STEP 1
   string current_path="";
   if(!SymbolInfoString(Symbol(),SYMBOL_PATH,current_path))
     {
      Print("ERROR: SYMBOL_PATH");
      return;
     }
//--- STEP 2
   string sep_="\\";                 // A separator as a character 
   ushort u_sep_;                    // The code of the separator character 
   string result_[];                 // An array to get strings 
//--- Get the separator code 
   u_sep_=StringGetCharacter(sep_,0);
//--- Split the string to substrings 
   int k_=StringSplit(current_path,u_sep_,result_);
//--- STEP 3
//--- Now output all obtained strings 
   if(k_>0)
     {
      current_path="";
      for(int i=0;i<k_-1;i++)
         current_path=current_path+result_[i]+sep_;
     }
//--- STEP 4
   string symbols_array[];
   int symbols_total=SymbolsTotal(false);
   for(int i=0;i<symbols_total;i++)
     {
      string symbol_name=SymbolName(i,false);
      string symbol_path="";
      if(!SymbolInfoString(symbol_name,SYMBOL_PATH,symbol_path))
         continue;
      if(StringFind(symbol_path,current_path,0)==-1)
         continue;
      
      int size=ArraySize(symbols_array);
      ArrayResize(symbols_array,size+1,10);
      symbols_array[size]=symbol_name];
     }
//--- STEP 5
   int size=ArraySize(symbols_array);
   if(size==0)
     {
      PrintFormat("ERROR: On path \"%s\" %d symbols",current_path,size);
      return;
     }
   PrintFormat("On path \"%s\" %d symbols",current_path,size);
//--- STEP 6
   if(m_file_txt.Open(InpFileName,FILE_WRITE|FILE_COMMON)==INVALID_HANDLE)
     {
      PrintFormat("ERROR: \"%s\" file in the Data Folder Common folder is not created",InpFileName);
      return;
     }
//--- STEP 7
   for(int i=0;i<size;i++)
      m_file_txt.WriteString(symbols_array[i]+"\r\n");
   m_file_txt.Close();
   Print("Everything is fine. There are no errors");
//---
  }
//+------------------------------------------------------------------+

Script operation algorithm:


Elder-Ray 1 — EA (or several EAs) with 1.xxx version numbers to be traded according to the option 1: all indicators on a single chart.

How to set the position volume — the minimum lot may be different

Let's conduct a simple experiment: check the minimum lot size of futures and securities: go through all symbols located at the same path as the current one (similar to the Symbols on the specified path.mq5 script), but inside saving symbols to the file, display statistics on the minimum lot size.

Gets minimal volume.mq5 — script used to display statistics on the minimum volume of the symbol group. The script bypasses the symbol group and accumulates statistics (minimal volume to close a deal and counter) in the two-dimensional array:

//--- STEP 4
/* 
   symbols_array[][2]:
   [*][minimal volume to close a deal]
   [*][counter]
*/

Full script code:

//+------------------------------------------------------------------+
//|                                          Gets minimal volume.mq5 |
//|                              Copyright © 2018, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2018, Vladimir Karputov"
#property link      "http://wmua.ru/slesar/"
#property version   "1.000"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- STEP 1
   string current_path="";
   if(!SymbolInfoString(Symbol(),SYMBOL_PATH,current_path))
     {
      Print("ERROR: SYMBOL_PATH");
      return;
     }
//--- STEP 2
   string sep_="\\";                 // A separator as a character 
   ushort u_sep_;                    // The code of the separator character 
   string result_[];                 // An array to get strings 
//--- Get the separator code 
   u_sep_=StringGetCharacter(sep_,0);
//--- Split the string to substrings 
   int k_=StringSplit(current_path,u_sep_,result_);
//--- STEP 3
//--- Now output all obtained strings 
   if(k_>0)
     {
      current_path="";
      for(int i=0;i<k_-1;i++)
         current_path=current_path+result_[i]+sep_;
     }
//--- STEP 4
/* 
   symbols_array[][2]:
   [*][minimal volume to close a deal]
   [*][counter]
*/
   double symbols_array[][2];
   int symbols_total=SymbolsTotal(false);
   for(int i=0;i<symbols_total;i++)
     {
      string symbol_name=SymbolName(i,false);
      string symbol_path="";
      if(!SymbolInfoString(symbol_name,SYMBOL_PATH,symbol_path))
         continue;
      if(StringFind(symbol_path,current_path,0)==-1)
         continue;

      double min_volume=0.0;
      if(!SymbolInfoDouble(symbol_name,SYMBOL_VOLUME_MIN,min_volume))
         continue;
      int size=ArrayRange(symbols_array,0);
      bool found=false;
      for(int j=0;j<size;j++)
        {
         if(symbols_array[j][0]==min_volume)
           {
            symbols_array[j][1]=symbols_array[j][1]+1;
            found=true;
            continue;
           }
        }
      if(!found)
        {
         ArrayResize(symbols_array,size+1,10);
         symbols_array[size][0]=min_volume;
         symbols_array[size][1]=1.0;
        }
     }
//--- STEP 5
   int size=ArrayRange(symbols_array,0);
   if(size==0)
     {
      PrintFormat("ERROR: On path \"%s\" %d symbols",current_path,size);
      return;
     }
//--- STEP 6
   for(int i=0;i<size;i++)
      PrintFormat("Minimal volume %.2f occurs %.1f times",symbols_array[i][0],symbols_array[i][1]);
   Print("Everything is fine. There are no errors");
//---
  }
//+------------------------------------------------------------------+

Script operation algorithm:

The result of launching on securities:

Gets minimal volume (CAT,D1)    Minimal volume 1.00 occurs 100.0 times

and on futures:

Gets minimal volume (RTSRIU8,D1)        Minimal volume 1.00 occurs 77.0 times

- on the two markets, the lot size is the same — 1.0.

Thus, let's not over-complicate the system and set "1.0" as the minimum lot.


Visualizing applied indicators

When you launch a visualized test in the tester, you can see the indicators applied by the EA. But when the EA is launched on the terminal chart, the indicators are not displayed. In this trading system, I want to see these indicators on the chart for visual control of the EA's work. It should look like this:

CATDaily visual trading

As you can see, here I used custom color and line width settings for all indicators (of course, this was done manually). For auto visualization of the indicators applied on the terminal chart, we need to slightly re-write Moving Average, Bulls Power and Bears Power indicators. I already implemented a similar thing in the Custom Moving Average Input Color code — the indicator color was included into the inputs: this input parameter is available when creating an indicator from an EA. Now, we just need to develop three more similar indicators.

You can download these indicators (Custom Moving Average Inputs, Custom Bulls Power Inputs and Custom Bears Power Inputs) in CodeBase. Place the downloaded indicators to the root of [data folder]\MQL5\Indicators\.


Elder-Ray 1.001.mq5visualizing the applied indicators you can set the color and width for. It works both in the strategy tester and when launching the EA on the chart:

Elder-Ray 1.001

How is this implemented?

The main condition is the presence of the Custom Moving Average InputsCustom Bulls Power Inputs and Custom Bears Power Inputs indicators in [data folder]\MQL5\Indicators

Three indicators

The indicators' look is managed and the period is set in the inputs, while for working with the indicators, three variables the indicator handles are to be stored in are declared (handle_iCustom_MA, handle_iCustom_Bulls and handle_iCustom_Bears).

//+------------------------------------------------------------------+
//|                                                  Elder-Ray 1.mq5 |
//|                              Copyright © 2018, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2018, Vladimir Karputov"
#property link      "http://wmua.ru/slesar/"
#property version   "1.000"
//---

//---
enum ENUM_INPUT_SYMBOLS
  {
   INPUT_SYMBOLS_CURRENT=0,   // current symbol
   INPUT_SYMBOLS_FILE=1,      // text file
  };
//--- input parameters
input ENUM_INPUT_SYMBOLS   InpInputSymbol       = INPUT_SYMBOLS_FILE;   // works on ...
input uint                 InpNumberMinLots     = 1;                    // Number of minimum lots
//--- Custom Moving Average Inputs
input int                  Inp_MA_ma_period     = 13;                   // MA: averaging period 
input int                  Inp_MA_ma_shift      = 0;                    // MA: horizontal shift 
input ENUM_MA_METHOD       Inp_MA_ma_method     = MODE_EMA;             // MA: smoothing type 
input ENUM_APPLIED_PRICE   Inp_MA_applied_price = PRICE_CLOSE;          // MA: type of price 
input color                Inp_MA_Color         = clrChartreuse;        // MA: Color
input int                  Inp_MA_Width         = 2;                    // MA: Width
//--- Custom Bulls Power Inputs
input int                  Inp_Bulls_ma_period  = 13;                   // Bulls Power: averaging period 
input color                Inp_Bulls_Color      = clrBlue;              // Bulls Power: Color
input int                  Inp_Bulls_Width      = 2;                    // Bulls Power: Width
//--- Custom Bears Power Inputs
input int                  Inp_Bears_ma_period  = 13;                   // Bears Power: averaging period 
input color                Inp_Bears_Color      = clrRed;               // Bears Power: Color
input int                  Inp_Bears_Width      = 2;                    // Bears Power: Width

int    handle_iCustom_MA;                    // variable for storing the handle of the iCustom indicator
int    handle_iCustom_Bulls;                 // variable for storing the handle of the iCustom indicator 
int    handle_iCustom_Bears;                 // variable for storing the handle of the iCustom indicator 
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()


In OnInit(), we create handles of custom indicators (iCustom is applied), and created indicators are added to the chart (ChartIndicatorAdd is applied).

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- create handle of the indicator iCustom
   handle_iCustom_MA=iCustom(Symbol(),Period(),"Custom Moving Average Inputs",
                             Inp_MA_ma_period,
                             Inp_MA_ma_shift,
                             Inp_MA_ma_method,
                             Inp_MA_Color,
                             Inp_MA_Width,
                             Inp_MA_applied_price);
//--- if the handle is not created 
   if(handle_iCustom_MA==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code 
      PrintFormat("Failed to create handle of the iCustom indicator (\"Custom Moving Average Inputs\") for the symbol %s/%s, error code %d",
                  Symbol(),
                  EnumToString(Period()),
                  GetLastError());
      //--- the indicator is stopped early 
      return(INIT_FAILED);
     }

//--- create handle of the indicator iCustom
   handle_iCustom_Bulls=iCustom(Symbol(),Period(),"Custom Bulls Power Inputs",
                                Inp_Bulls_ma_period,
                                Inp_Bulls_Color,
                                Inp_Bulls_Width);
//--- if the handle is not created 
   if(handle_iCustom_Bulls==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code 
      PrintFormat("Failed to create handle of the iCustom indicator (\"Custom Bulls Power Inputs\") for the symbol %s/%s, error code %d",
                  Symbol(),
                  EnumToString(Period()),
                  GetLastError());
      //--- the indicator is stopped early 
      return(INIT_FAILED);
     }

//--- create handle of the indicator iCustom
   handle_iCustom_Bears=iCustom(Symbol(),Period(),"Custom Bears Power Inputs",
                                Inp_Bears_ma_period,
                                Inp_Bears_Color,
                                Inp_Bears_Width);
//--- if the handle is not created 
   if(handle_iCustom_Bears==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code 
      PrintFormat("Failed to create handle of the iCustom indicator (\"Custom Bears Power Inputs\") for the symbol %s/%s, error code %d",
                  Symbol(),
                  EnumToString(Period()),
                  GetLastError());
      //--- the indicator is stopped early 
      return(INIT_FAILED);
     }

   ChartIndicatorAdd(0,0,handle_iCustom_MA);
   int windows_total=(int)ChartGetInteger(0,CHART_WINDOWS_TOTAL);
   ChartIndicatorAdd(0,windows_total,handle_iCustom_Bulls);
   ChartIndicatorAdd(0,windows_total+1,handle_iCustom_Bears);
//---
   return(INIT_SUCCEEDED);
  }


Saving resources. Elder-Ray 1.010.mq5

There may be about a hundred analyzed symbols of a single group. Thus, the issue of saving RAM becomes relevant, since each chart is to contain three indicators. Like with a minimum lot, the best thing to do is to check the resource consumption by the EA. At the same time, we will also make a little progress in assembling our EA by adding the code for reading symbol names of one group from the text file and working with them.

The CFileTxt class (we already applied it in the script Symbols on the specified path.mq5) is included to the EA. Its m_file_txt object is responsible for accessing the text file and reading data from the file. We also include the CSymbolInfo class. Its object m_symbol is responsible for checking the existence of a symbol and adding it to the Market Watch window. Why did I choose CSymbolInfo, rather than implementing the function via SymbolInfoInteger and SymbolSelect? All is simple: in the CSymbolInfo class, all the code for checking, adding or informing of errors is hidden inside the class, and we need only to add the following three strings in the EA:

         if(!m_symbol.Name(name)) // sets symbol name
           {
            m_file_txt.Close();
            return(INIT_FAILED);
           }

Here we should recall that all symbols of a multi-currency EA should be added to the Market Watch window: Enable required symbols in Market Watch for multi-currency Expert Advisors

Thus, the EA works according to the following algorithm: a text file is opened in OnInit(), a symbol is read and an attempt is immediately made to create three custom indicators (Custom Moving Average Inputs, Custom Bulls Power Inputs and Custom Bears Power Inputs) for the read symbol on the current timeframe. If that attempt fails (for example, due to insufficient number of bars for creating Custom Moving Average Inputs), move on further along the loop. If the indicators are created, write the symbol name to m_symbols_array, while the handles of three indicators are sent to the three-dimensional m_handles_array. Thus, by the first dimension, both arrays synchronously contain data on the symbol name and symbol's handles:

//---
   if(m_file_txt.Open(InpFileName,FILE_READ|FILE_COMMON)==INVALID_HANDLE)
     {
      PrintFormat("ERROR: \"%s\" file in the Data Folder Common folder is not open: %d",InpFileName,GetLastError());
      return(INIT_FAILED);
     }
//--- symbol info object OR file txt object
   if(InpInputSymbol==INPUT_SYMBOLS_FILE)
     {
      //--- read data from the file 
      int counter=0;
      while(!m_file_txt.IsEnding())
        {
         counter++;
         Print("Iteration ",counter);
         string name=m_file_txt.ReadString();
         if(!m_symbol.Name(name)) // sets symbol name
           {
            m_file_txt.Close();
            return(INIT_FAILED);
           }
         int MA,Bulls,Bears;
         if(!CreateHandles(name,Period(),MA,Bulls,Bears))
            continue; //return(INIT_FAILED);
         int size=ArraySize(m_symbols_array);
         ArrayResize(m_symbols_array,size+1,10);
         ArrayResize(m_handles_array,size+1,10);
         m_symbols_array[size]=name;
         m_handles_array[size][0]=MA;
         m_handles_array[size][1]=Bulls;
         m_handles_array[size][2]=Bears;
        }
      m_file_txt.Close();
     }
   else
     {
      if(!m_symbol.Name(Symbol())) // sets symbol name
         return(INIT_FAILED);
     }
//---
   ChartIndicatorAdd(0,0,handle_iCustom_MA);

Indicator handles are created in CreateHandles().

Thus, memory consumption was measured via TERMINAL_MEMORY_USED and visually in the Windows 10 task manager. To define memory consumption by steps, some strings were deliberately disabled (commented out) in the version 1.010. In the final version 1.010, all the strings for adding symbols and creating indicators were uncommented.


Conclusion: TERMINAL_MEMORY_USED shows the total consumption of RAM and disk space. Since the RAM consumption in the normal mode does not exceed 300 MB, there is no need to save resources.


Trend (EMA) is...

The main EA objective is to define the trend (EMA) direction. A trend cannot be determined by a single bar. We need data from several bars. Let's mark this parameter as "bars". Below are three securities charts — CAT, MCD and V. The trend is to be defined as follows: "+1" for uptrend, "0" for no trend and "—1" for downtrend

Trend (EMA) is ...

"CAT" chart shows trend "0" (4 bullish and 4 bearish bars, while the change is insignificant on the remaining bars), "MCD" shows trend "—1" (8 bearish bars, while others are in the uncertain state). Finally, "V" displays trend "0" (6 bullish bars, while 2 or 3 are bearish ones). We may need the 'different' parameter — minimum difference between the indicator readings on neighboring bars. 


Defining trend. Elder-Ray 1.020.mq5

Trend existence conditions: EMA along bars should be in a certain direction. The two additional parameters should probably be checked afterwards: 


Additions and removals in the version 1.020: 


The block for catching a new bar and defining a trend direction

In OnTimer(), go through the symbols array (m_symbols_array) downloaded from the text file once per 60 seconds and catch a new bar on a symbol from the array. Get EMA indicator data sufficient to determine a trend to the ema_array array. Perform calculation: number of bars the indicator moved upwards and downwards. Print detected patterns.

//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
//---
   int size=ArraySize(m_symbols_array);
   for(int i=0;i<size;i++)
     {
      //--- we work only at the time of the birth of new bar
      datetime PrevBars=m_prev_bars[i];
      datetime time_0=iTime(m_symbols_array[i],Period(),0);
      if(time_0==PrevBars)
         continue;
      m_prev_bars[i]=time_0;
      double ema_array[];
      ArraySetAsSeries(ema_array,true);
/*
      m_handles_array[*][MA][Bulls][Bears]
*/
      if(!iMAGetArray(m_handles_array[i][0],0,InpBarsEMA+2,ema_array))
         continue;
      int upwards=0;
      int downward=0;
      for(int j=1;j<InpBarsEMA+1;j++)
        {
         if(ema_array[j]>ema_array[j+1])
            upwards++;
         else if(ema_array[j]<ema_array[j+1])
            downward++;
        }
      if((double)upwards>InpBarsEMA*InpMinTrendPercentage/100.0)
         Print("On ",m_symbols_array[i]," trend UP!");
      else if((double)downward>InpBarsEMA*InpMinTrendPercentage/100.0)
         Print("On ",m_symbols_array[i]," trend DOWN!");
      else
         Print("On ",m_symbols_array[i]," trend NONE!");
     }
  }

Trend search result. Settings: number of bars for identifying the trend — 6, minimum percentage of the trend — 75%. Keep in mind that a zero bar is not taken into account when working at the moment a new bar appears:

Trend on symbols


Trend on symbols


Setting pending orders (Buy stop or Sell stop). Elder-Ray 1.030.mq5

Is it possible to avoid the lack of funds error when opening a position? Since we work with pending orders, the answer is "No". There may be half-way measures, but nothing can be guaranteed. The main reason is that no one knows at what point a pending order is activated and whether it is activated at all.

Now that the EA knows how to define a trend, we need to use the Buy and Sell rules to find points suitable for setting a pending order. For BUY, there will be a simple check: Bears Power on bar #1 should be less than zero and greater than Bears Power on bar #2. For SELL, the condition is the opposite: Bulls Power on bar #1 should exceed zero and less than Bears Power on bar #2.

Describing the strategy, Alexander Elder pointed out for opening a buy position, protective stop loss should be placed below the last Low, while for opening a sell position, it should be placed above the last High. The very concept of "Last" is rather blurred, so I checked the two options:

  1. setting a stop loss by bar #1 prices and
  2. searching for the nearest extreme point.

The option 1 turned out to be inviable - stop loss activations were too frequent. Therefore, I implemented the option 2 (searching for the nearest extremum) in the Elder-Ray 1.030.mq5 EA code.


Searching for the nearest extremum

The function look for the nearest extremum:

Nearest extremum

If no extremum is found or an error is detected, 'false' is returned:

//+------------------------------------------------------------------+
//| Find the nearest extremum                                        |
//+------------------------------------------------------------------+
bool NearestExtremum(ENUM_SERIESMODE type,double &price)
  {
   if(type==MODE_LOW)
     {
      //--- search for the nearest minimum
      double low_array[];
      ArraySetAsSeries(low_array,true);
      int copy=CopyLow(m_symbol.Name(),Period(),0,100,low_array);
      if(copy==-1)
         return(false);
      double low=DBL_MAX;
      for(int k=0;k<copy;k++)
        {
         if(low_array[k]<low)
            low=low_array[k];
         else if(low_array[k]>low)
            break;
        }
      if(low!=DBL_MAX)
        {
         price=low;
         return(true);
        }
     }
   else if(type==MODE_HIGH)
     {
      //--- search for the nearest maximum
      double high_array[];
      ArraySetAsSeries(high_array,true);
      int copy=CopyHigh(m_symbol.Name(),Period(),0,100,high_array);
      if(copy==-1)
         return(false);
      double high=DBL_MIN;
      for(int k=0;k<copy;k++)
        {
         if(high_array[k]>high)
            high=high_array[k];
         else if(high_array[k]<high)
            break;
        }
      if(high!=DBL_MIN)
        {
         price=high;
         return(true);
        }
     }
//---
   return(false);
  }


Additions and removals in the version 1.030: 

To deal with situations when a pending order opposite to the current position is triggered, we need to consider three typical situations after a Buy Stop pending order is triggered:

Existing position, volume Pending order activated, volume Resulting position, volume Note to a pending order trigger moment Position's previous magic  Compensation algorithm (NB: magic is set to m_magic_compensation before the compensation) Position's new magic
 1  Sell 1.0  Buy Stop 3.0  Buy 2.0 Position reversal (DEAL_ENTRY_INOUT deal direction)  m_magic Open additional Buy with the volume of 3.0 — 2.0 = 1.0  m_magic_compensation
 2  Sell 1.0  Buy Stop 1.0  --- Closing position in full (DEAL_ENTRY_OUT deal direction)  m_magic Searching for a position. If there is no position, open Buy with the volume of 1.0  m_magic_compensation
 3  Sell 2.0  Buy Stop 1.0  Sell 1.0 Closing position partially (DEAL_ENTRY_OUT deal direction)  m_magic Searching for a position. If a position is present and it is opposite to Buy, open Buy with the volume of 1.0 + 1.0 = 2.0  m_magic_compensation

For each of the three cases, I prepared a printout of deals and orders (test on a real netting account, as well as in the tester). To generate a report on deals and orders, I used the code from the History Deals and Orders script.

#1: Sell 1.0 -> Buy Stop 3.0

Sell 1.0, Buy Stop 3.0

Deal:
|Ticket              |Order               |Time                |Time msc            |Type                |Entry               |Magic               |Reason              |Position ID        
|1                   |0                   |2016.12.08 00:00:00 |1481155200000       |DEAL_TYPE_BALANCE   |DEAL_ENTRY_IN       |0                   |DEAL_REASON_CLIENT  |0                  
|Volume              |Price               |Commission          |Swap                |Profit              |Symbol              |Comment                                  |External ID        
|0.00                |0.00000             |0.00                |0.00                |50000.00            |                    |                                         |                   
Order 0 is not found in the trade history between the dates 2010.08.07 11:06:20 and 2018.08.10 00:00:00

Deal:
|Ticket              |Order               |Time                |Time msc            |Type                |Entry               |Magic               |Reason              |Position ID        
|2                   |2                   |2016.12.08 00:00:00 |1481155200100       |DEAL_TYPE_SELL      |DEAL_ENTRY_IN       |15489               |DEAL_REASON_EXPERT  |2                  
|Volume              |Price               |Commission          |Swap                |Profit              |Symbol              |Comment                                  |External ID        
|1.00                |79.31               |0.00                |0.00                |0.00                |V                   |                                         |                   
Order:
|Ticket              |Time setup          |Type                |State               |Time expiration     |Time done           |Time setup msc      |Time done msc       |Type filling       
|2                   |2016.12.08 00:00:00 |ORDER_TYPE_SELL     |ORDER_STATE_FILLED  |2016.12.08 00:00:00 |2016.12.08 00:00:00 |1481155200100       |1481155200100       |ORDER_FILLING_FOK  
|Type time           |Magic               |Reason              |Position id         |Position by id     
|1970.01.01 00:00:00 |15489               |ORDER_REASON_EXPERT |2                   |0                  
|Volume initial      |Volume current      |Open price          |sl                  |tp                  |Price current       |Price stoplimit    
|1.00                |0.00                |79.31               |0.00                |0.00                |79.39               |0.00               
|Symbol              |Comment                                  |Extarnal id        
|V                   |                                         |                   

Deal:
|Ticket              |Order               |Time                |Time msc            |Type                |Entry               |Magic               |Reason              |Position ID        
|3                   |3                   |2016.12.08 17:27:37 |1481218057877       |DEAL_TYPE_BUY       |DEAL_ENTRY_INOUT    |15489               |DEAL_REASON_EXPERT  |2                  
|Volume              |Price               |Commission          |Swap                |Profit              |Symbol              |Comment                                  |External ID        
|3.00                |79.75               |0.00                |0.00                |-0.44               |V                   |                                         |                   
Order:
|Ticket              |Time setup          |Type                |State               |Time expiration     |Time done           |Time setup msc      |Time done msc       |Type filling       
|3                   |2016.12.08 14:30:00 |ORDER_TYPE_BUY_STOP |ORDER_STATE_FILLED  |2016.12.08 14:30:00 |2016.12.08 17:27:37 |1481207400100       |1481218057877       |ORDER_FILLING_RETURN
|Type time           |Magic               |Reason              |Position id         |Position by id     
|1970.01.01 00:00:00 |15489               |ORDER_REASON_EXPERT |2                   |0                  
|Volume initial      |Volume current      |Open price          |sl                  |tp                  |Price current       |Price stoplimit    
|3.00                |0.00                |79.74               |75.17               |0.00                |79.74               |0.00               
|Symbol              |Comment                                  |Extarnal id        
|V                   |                                         |                   

Deal:
|Ticket              |Order               |Time                |Time msc            |Type                |Entry               |Magic               |Reason              |Position ID        
|4                   |4                   |2016.12.09 23:59:00 |1481327940000       |DEAL_TYPE_SELL      |DEAL_ENTRY_OUT      |0                   |DEAL_REASON_CLIENT  |2                  
|Volume              |Price               |Commission          |Swap                |Profit              |Symbol              |Comment                                  |External ID        
|2.00                |79.13               |0.00                |0.00                |-1.24               |V                   |end of test                              |                   
Order:
|Ticket              |Time setup          |Type                |State               |Time expiration     |Time done           |Time setup msc      |Time done msc       |Type filling       
|4                   |2016.12.09 23:59:00 |ORDER_TYPE_SELL     |ORDER_STATE_FILLED  |2016.12.09 23:59:00 |2016.12.09 23:59:00 |1481327940000       |1481327940000       |ORDER_FILLING_FOK  
|Type time           |Magic               |Reason              |Position id         |Position by id     
|1970.01.01 00:00:00 |0                   |ORDER_REASON_CLIENT |2                   |0                  
|Volume initial      |Volume current      |Open price          |sl                  |tp                  |Price current       |Price stoplimit    
|2.00                |0.00                |79.13               |0.00                |0.00                |79.13               |0.00               
|Symbol              |Comment                                  |Extarnal id        
|V                   |end of test                              |                   


#2: Sell 1.0 -> Buy Stop 1.0

Sell 1.0, Buy Stop 1.0

Deal:
|Ticket              |Order               |Time                |Time msc            |Type                |Entry               |Magic               |Reason              |Position ID        
|1                   |0                   |2016.12.08 00:00:00 |1481155200000       |DEAL_TYPE_BALANCE   |DEAL_ENTRY_IN       |0                   |DEAL_REASON_CLIENT  |0                  
|Volume              |Price               |Commission          |Swap                |Profit              |Symbol              |Comment                                  |External ID        
|0.00                |0.00000             |0.00                |0.00                |50000.00            |                    |                                         |                   
Order 0 is not found in the trade history between the dates 2010.08.07 11:06:20 and 2018.08.10 00:00:00

Deal:
|Ticket              |Order               |Time                |Time msc            |Type                |Entry               |Magic               |Reason              |Position ID        
|2                   |2                   |2016.12.08 00:00:00 |1481155200100       |DEAL_TYPE_SELL      |DEAL_ENTRY_IN       |15489               |DEAL_REASON_EXPERT  |2                  
|Volume              |Price               |Commission          |Swap                |Profit              |Symbol              |Comment                                  |External ID        
|1.00                |79.31               |0.00                |0.00                |0.00                |V                   |                                         |                   
Order:
|Ticket              |Time setup          |Type                |State               |Time expiration     |Time done           |Time setup msc      |Time done msc       |Type filling       
|2                   |2016.12.08 00:00:00 |ORDER_TYPE_SELL     |ORDER_STATE_FILLED  |2016.12.08 00:00:00 |2016.12.08 00:00:00 |1481155200100       |1481155200100       |ORDER_FILLING_FOK  
|Type time           |Magic               |Reason              |Position id         |Position by id     
|1970.01.01 00:00:00 |15489               |ORDER_REASON_EXPERT |2                   |0                  
|Volume initial      |Volume current      |Open price          |sl                  |tp                  |Price current       |Price stoplimit    
|1.00                |0.00                |79.31               |0.00                |0.00                |79.39               |0.00               
|Symbol              |Comment                                  |Extarnal id        
|V                   |                                         |                   

Deal:
|Ticket              |Order               |Time                |Time msc            |Type                |Entry               |Magic               |Reason              |Position ID        
|3                   |3                   |2016.12.08 17:27:37 |1481218057877       |DEAL_TYPE_BUY       |DEAL_ENTRY_OUT      |15489               |DEAL_REASON_EXPERT  |2                  
|Volume              |Price               |Commission          |Swap                |Profit              |Symbol              |Comment                                  |External ID        
|1.00                |79.75               |0.00                |0.00                |-0.44               |V                   |                                         |                   
Order:
|Ticket              |Time setup          |Type                |State               |Time expiration     |Time done           |Time setup msc      |Time done msc       |Type filling       
|3                   |2016.12.08 14:30:00 |ORDER_TYPE_BUY_STOP |ORDER_STATE_FILLED  |2016.12.08 14:30:00 |2016.12.08 17:27:37 |1481207400100       |1481218057877       |ORDER_FILLING_RETURN
|Type time           |Magic               |Reason              |Position id         |Position by id     
|1970.01.01 00:00:00 |15489               |ORDER_REASON_EXPERT |2                   |0                  
|Volume initial      |Volume current      |Open price          |sl                  |tp                  |Price current       |Price stoplimit    
|1.00                |0.00                |79.74               |75.17               |0.00                |79.74               |0.00               
|Symbol              |Comment                                  |Extarnal id        
|V                   |                                         |                   


#3: Sell 2.0 -> Buy Stop 1.0

Sell 2.0, Buy Stop 1.0

Deal:
|Ticket              |Order               |Time                |Time msc            |Type                |Entry               |Magic               |Reason              |Position ID        
|1                   |0                   |2016.12.08 00:00:00 |1481155200000       |DEAL_TYPE_BALANCE   |DEAL_ENTRY_IN       |0                   |DEAL_REASON_CLIENT  |0                  
|Volume              |Price               |Commission          |Swap                |Profit              |Symbol              |Comment                                  |External ID        
|0.00                |0.00000             |0.00                |0.00                |50000.00            |                    |                                         |                   
Order 0 is not found in the trade history between the dates 2010.08.07 11:06:20 and 2018.08.10 00:00:00

Deal:
|Ticket              |Order               |Time                |Time msc            |Type                |Entry               |Magic               |Reason              |Position ID        
|2                   |2                   |2016.12.08 00:00:00 |1481155200100       |DEAL_TYPE_SELL      |DEAL_ENTRY_IN       |15489               |DEAL_REASON_EXPERT  |2                  
|Volume              |Price               |Commission          |Swap                |Profit              |Symbol              |Comment                                  |External ID        
|2.00                |79.31               |0.00                |0.00                |0.00                |V                   |                                         |                   
Order:
|Ticket              |Time setup          |Type                |State               |Time expiration     |Time done           |Time setup msc      |Time done msc       |Type filling       
|2                   |2016.12.08 00:00:00 |ORDER_TYPE_SELL     |ORDER_STATE_FILLED  |2016.12.08 00:00:00 |2016.12.08 00:00:00 |1481155200100       |1481155200100       |ORDER_FILLING_FOK  
|Type time           |Magic               |Reason              |Position id         |Position by id     
|1970.01.01 00:00:00 |15489               |ORDER_REASON_EXPERT |2                   |0                  
|Volume initial      |Volume current      |Open price          |sl                  |tp                  |Price current       |Price stoplimit    
|2.00                |0.00                |79.31               |0.00                |0.00                |79.39               |0.00               
|Symbol              |Comment                                  |Extarnal id        
|V                   |                                         |                   

Deal:
|Ticket              |Order               |Time                |Time msc            |Type                |Entry               |Magic               |Reason              |Position ID        
|3                   |3                   |2016.12.08 17:27:37 |1481218057877       |DEAL_TYPE_BUY       |DEAL_ENTRY_OUT      |15489               |DEAL_REASON_EXPERT  |2                  
|Volume              |Price               |Commission          |Swap                |Profit              |Symbol              |Comment                                  |External ID        
|1.00                |79.75               |0.00                |0.00                |-0.44               |V                   |                                         |                   
Order:
|Ticket              |Time setup          |Type                |State               |Time expiration     |Time done           |Time setup msc      |Time done msc       |Type filling       
|3                   |2016.12.08 14:30:00 |ORDER_TYPE_BUY_STOP |ORDER_STATE_FILLED  |2016.12.08 14:30:00 |2016.12.08 17:27:37 |1481207400100       |1481218057877       |ORDER_FILLING_RETURN
|Type time           |Magic               |Reason              |Position id         |Position by id     
|1970.01.01 00:00:00 |15489               |ORDER_REASON_EXPERT |2                   |0                  
|Volume initial      |Volume current      |Open price          |sl                  |tp                  |Price current       |Price stoplimit    
|1.00                |0.00                |79.74               |75.17               |0.00                |79.74               |0.00               
|Symbol              |Comment                                  |Extarnal id        
|V                   |                                         |                   

Deal:
|Ticket              |Order               |Time                |Time msc            |Type                |Entry               |Magic               |Reason              |Position ID        
|4                   |4                   |2016.12.09 23:59:00 |1481327940000       |DEAL_TYPE_BUY       |DEAL_ENTRY_OUT      |0                   |DEAL_REASON_CLIENT  |2                  
|Volume              |Price               |Commission          |Swap                |Profit              |Symbol              |Comment                                  |External ID        
|1.00                |79.13               |0.00                |0.00                |0.18                |V                   |end of test                              |                   
Order:
|Ticket              |Time setup          |Type                |State               |Time expiration     |Time done           |Time setup msc      |Time done msc       |Type filling       
|4                   |2016.12.09 23:59:00 |ORDER_TYPE_BUY      |ORDER_STATE_FILLED  |2016.12.09 23:59:00 |2016.12.09 23:59:00 |1481327940000       |1481327940000       |ORDER_FILLING_FOK  
|Type time           |Magic               |Reason              |Position id         |Position by id     
|1970.01.01 00:00:00 |0                   |ORDER_REASON_CLIENT |2                   |0                  
|Volume initial      |Volume current      |Open price          |sl                  |tp                  |Price current       |Price stoplimit    
|1.00                |0.00                |79.13               |0.00                |0.00                |79.13               |0.00               
|Symbol              |Comment                                  |Extarnal id        
|V                   |end of test                              |                   


Below is yet another case on a real account and real time (not in the tester): the market Buy order with the volume of 2.0 (Buy trading order generated two deals with the volumes of 1.0 — 20087494 and 20087495), then Sell limit with the volume of 2.0 was placed to take the profit and close the position. A bit later, that Sell limit was completed in two parts (deals 20088091 and 20088145). The printout:

Buy 2.0, Sell limit 2.0 

Deal:
|Ticket              |Order               |Time                |Time msc            |Type                |Entry               |Magic               |Reason              |Position ID        
|20087494            |29080489            |2018.08.10 07:23:34 |1533885814000       |DEAL_TYPE_BUY       |DEAL_ENTRY_IN       |0                   |DEAL_REASON_CLIENT  |29080489           
|Volume              |Price               |Commission          |Swap                |Profit              |Symbol              |Comment                                  |External ID        
|1.00                |14595               |-0.10               |0.00                |0.00                |RTSGZU8             |                                         |                   
Order:
|Ticket              |Time setup          |Type                |State               |Time expiration     |Time done           |Time setup msc      |Time done msc       |Type filling       
|29080489            |2018.08.10 07:23:34 |ORDER_TYPE_BUY      |ORDER_STATE_FILLED  |2018.08.10 07:23:34 |2018.08.10 07:23:34 |1533885814000       |1533885814000       |ORDER_FILLING_RETURN
|Type time           |Magic               |Reason              |Position id         |Position by id     
|1970.01.01 00:00:00 |0                   |ORDER_REASON_CLIENT |29080489            |0                  
|Volume initial      |Volume current      |Open price          |sl                  |tp                  |Price current       |Price stoplimit    
|2.00                |0.00                |0                   |0                   |0                   |14588               |0                  
|Symbol              |Comment                                  |External id        
|RTSGZU8             |                                         |13_31861873584     

Deal:
|Ticket              |Order               |Time                |Time msc            |Type                |Entry               |Magic               |Reason              |Position ID        
|20087495            |29080489            |2018.08.10 07:23:34 |1533885814000       |DEAL_TYPE_BUY       |DEAL_ENTRY_IN       |0                   |DEAL_REASON_CLIENT  |29080489           
|Volume              |Price               |Commission          |Swap                |Profit              |Symbol              |Comment                                  |External ID        
|1.00                |14595               |-0.10               |0.00                |0.00                |RTSGZU8             |                                         |                   
Order:
|Ticket              |Time setup          |Type                |State               |Time expiration     |Time done           |Time setup msc      |Time done msc       |Type filling       
|29080489            |2018.08.10 07:23:34 |ORDER_TYPE_BUY      |ORDER_STATE_FILLED  |2018.08.10 07:23:34 |2018.08.10 07:23:34 |1533885814000       |1533885814000       |ORDER_FILLING_RETURN
|Type time           |Magic               |Reason              |Position id         |Position by id     
|1970.01.01 00:00:00 |0                   |ORDER_REASON_CLIENT |29080489            |0                  
|Volume initial      |Volume current      |Open price          |sl                  |tp                  |Price current       |Price stoplimit    
|2.00                |0.00                |0                   |0                   |0                   |14588               |0                  
|Symbol              |Comment                                  |External id        
|RTSGZU8             |                                         |13_31861873584     

Deal:
|Ticket              |Order               |Time                |Time msc            |Type                |Entry               |Magic               |Reason              |Position ID        
|20088091            |29080662            |2018.08.10 08:03:08 |1533888188000       |DEAL_TYPE_SELL      |DEAL_ENTRY_OUT      |0                   |DEAL_REASON_CLIENT  |29080489           
|Volume              |Price               |Commission          |Swap                |Profit              |Symbol              |Comment                                  |External ID        
|1.00                |14626               |-0.10               |0.00                |0.46                |RTSGZU8             |                                         |                   
Order:
|Ticket              |Time setup          |Type                |State               |Time expiration     |Time done           |Time setup msc      |Time done msc       |Type filling       
|29080662            |2018.08.10 07:27:19 |ORDER_TYPE_SELL_LIMIT |ORDER_STATE_FILLED  |2018.08.10 07:27:19 |2018.08.10 08:05:42 |1533886039000       |1533888342000       |ORDER_FILLING_RETURN
|Type time           |Magic               |Reason              |Position id         |Position by id     
|1970.01.01 00:00:00 |0                   |ORDER_REASON_CLIENT |29080489            |0                  
|Volume initial      |Volume current      |Open price          |sl                  |tp                  |Price current       |Price stoplimit    
|2.00                |0.00                |14626               |0                   |0                   |14624               |0                  
|Symbol              |Comment                                  |External id        
|RTSGZU8             |                                         |13_31862155871     

Deal:
|Ticket              |Order               |Time                |Time msc            |Type                |Entry               |Magic               |Reason              |Position ID        
|20088145            |29080662            |2018.08.10 08:05:42 |1533888342000       |DEAL_TYPE_SELL      |DEAL_ENTRY_OUT      |0                   |DEAL_REASON_CLIENT  |29080489           
|Volume              |Price               |Commission          |Swap                |Profit              |Symbol              |Comment                                  |External ID        
|1.00                |14626               |-0.10               |0.00                |0.46                |RTSGZU8             |                                         |                   
Order:
|Ticket              |Time setup          |Type                |State               |Time expiration     |Time done           |Time setup msc      |Time done msc       |Type filling       
|29080662            |2018.08.10 07:27:19 |ORDER_TYPE_SELL_LIMIT |ORDER_STATE_FILLED  |2018.08.10 07:27:19 |2018.08.10 08:05:42 |1533886039000       |1533888342000       |ORDER_FILLING_RETURN
|Type time           |Magic               |Reason              |Position id         |Position by id     
|1970.01.01 00:00:00 |0                   |ORDER_REASON_CLIENT |29080489            |0                  
|Volume initial      |Volume current      |Open price          |sl                  |tp                  |Price current       |Price stoplimit    
|2.00                |0.00                |14626               |0                   |0                   |14624               |0                  
|Symbol              |Comment                                  |External id        
|RTSGZU8             |                                         |13_31862155871     


Tips on testing 1.xxx


Option 2: in combination with the "Triple choice" system

In the Option 1 (all indicators on a single chart), a trend indicator was on the same timeframe. In the Option 2, the trend indicator will be located on a higher timeframe. Thus, only one new parameter is added — trend timeframe (Trend timeframe).

The Option 2 is implemented in the Elder-Ray 2.000.mq5 EA.


Files attached to the article:

Name File type Description
Symbols on the specified path.mq5 Script Forms a text file with the symbols of the group and is saved in the Common Data Folder
Gets minimal volume.mq5 Script Displays statistics on the minimum volume of the group.
Elder-Ray 1.001.mq5 Expert Advisor Shows visualization of applied indicators
Elder-Ray 1.010.mq5 Expert Advisor Start working with the text file and create indicators for symbols from the file. The EA is used to monitor memory consumption
Elder-Ray 1.020.mq5 Expert Advisor Define a trend. Check the trend definition validity
Elder-Ray 1.030.mq5 Expert Advisor Run-time version for Option 1: all indicators on a single chart
Elder-Ray 2.000.mq5 Expert Advisor Option 2: in combination with the "Triple choice" system


Conclusion

Elder-Ray (Bulls Power and Bears Power) trading system is viable enough, especially in combination with the "Triple choice" system when EMA trend indicator is calculated on a higher timeframe than Bulls Power and Bears Power.

When testing the EA, we should keep in mind that the prepared text file may contain up to 100 symbols. Considering this number, you may need up to 10 minutes to launch the test, as well as up to 5 GB of memory during the test. 

Regardless of your trust to the EA, you will surely want to intervene the process, like I did while writing the article and testing the EA versions:

CAT and V manual