Download MetaTrader 5

Expert Advisors Based on Popular Trading Systems and Alchemy of Trading Robot Optimization (Cont.)

2 June 2008, 07:16
Nikolay Kositsin
0
1 435

Introduction


I have received an offer from a reader of the previous article to automatize a little the process of backtesting to get the possibility of receiving results of all optimizations at the same time. Moreover, it is not very convenient to shift the testing period manually, this process should be also automated. The idea is great. The more so, MQL4 means offer all possibilities for its implementation. So I will start the article from the solution of this problem.

Backtesting Automation


What we need for the solution of this task:

1. Write in the necessary Expert Advisor below its heading a line of the following content:

//+==================================================================+
//| Custom BackTesting function                                      |
//+==================================================================+
#include <IsBackTestingTime.mqh>

Using this directive we include the function IsBackTestingTime() into the EA code. And don't forget to place the IsBackTestingTime.mqh file into the folder INCLUDE. This function:

bool IsBackTestingTime()
 {
 } 

is used to define period of time, within which the backtesting optimization or backtesting will take place. In this time periods the function always returns 'true', in other times it returns 'false'. Besides this function external EA variables are added to the EA code by this directive:

//---- Declaration of external variables for backtesting
extern datetime Start_Time = D'2007.01.01'; // start time of zero optimization
extern int Opt_Period = 3; // optimization period in months, if less than zero, parameters are in days
extern int Test_Period = 2; // testing period in months
extern int Period_Shift = 1; // step of optimization period shift in months
extern int Opt_Number = 0; // optimization number

I hope, the meaning of these variables is clear for those who have read my previous article, so there is no need to explain them once again.

2. In the block of the starting function before the EA code place the simplest universal code of IsBackTestingTime() call, it limits EA operation to certain time frames depending on the number of the backtesting optimization.


 //----+ Execution of backtesting conditions
   if (!IsBackTestingTime())
                       return(0);

Schematically it will look like this:


//+==================================================================+
//|                                                 Exp_BackTest.mq4 |
//|                             Copyright © 2008,   Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+==================================================================+
#property copyright "Copyright © 2008, Nikolay Kositsin"
#property link "farria@mail.redcom.ru"
//+==================================================================+
//| Custom BackTesting function                                      |
//+==================================================================+
#include <IsBackTestingTime.mqh>
//---- INPUT PARAMETERS OF THE EA
//---- GLOBAL VARIABLES OF THE EA
//+==================================================================+
//| USER-DEFINED FUNCTIONS OF THE EA                                 |
//+==================================================================+
 
//+==================================================================+
//| Custom Expert initialization function                            |
//+==================================================================+
int init()
  {
//----+ +------------------------------------------------------------+    
//---- CODE FOR THE EA INITIALIZATION
//----+ +------------------------------------------------------------+                 
//---- end of initialization
   return(0);
  }
//+==================================================================+
//| Custom Expert iteration function                                 |
//+==================================================================+
int start()
  {
   //----+ Execution of backtesting conditions
   if (!IsBackTestingTime())
                       return(0);             
   //----+ +---------------------------------------------------------+    
   //----+ CODE OF THE EA ALGORITHM
   //----+ +---------------------------------------------------------+
//----+ 
    
    return(0);
  }
//+------------------------------------------------------------------+

If you are interested in the detailed problem solution on the example of a ready EA, see the EA code Exp_5_1.mq4, which is the EA form the previous article Exp_5.mq4 modified for backtesting. Actually there is no large difference in the optimization of the like EA as compared to a simple Expert Advisor. However, I think backtesting variables shouldn't be optimized, except for Opt_Number, though you may have another opinion.

It is important to remember that after optimization during testing we get results not inside the optimization period, but after it, beyond its right border! It is not the best decision to make all backtesting optimization within one run using a genetic algorithm, it is much more interesting to analyze deeper each backtesting optimization separately without the optimization of the input variable Opt_Number.

But even in this case such an approach facilitates the understanding of the EA behavior. And it should be remembered that the value of the external variable Opt_Number can change from zero to a certain maximal value that can be defined the following way: from the total period in which all backtesting optimizations are conducted (in months) subtract the period of backtesting optimization in months (Opt_Period) and subtract backtesting period (Test_Period). Add one to the obtained value. The obtained result will be the maximum of the Opt_Number variable if Period_Shift is equal to one.

Trading Systems Based on the Crossing of Two Movings


This variant of trading systems is quite popular. Now let's analyze the algorithm underlying such strategies. For long positions the entering algorithm looks like this:

For short positions it is the following:

As indicators two identical movings with different parameters defining averaging in indicators can be used. It is assumed that the parameter defining the averaging of MovA moving is always smaller than the same parameter of MovB moving. Thus in this trading system MovA is a quick moving, MovB is a slow one. Here is the trading system implementation variant based on two JMA movings:

//+==================================================================+
//|                                                        Exp_6.mq4 |
//|                             Copyright © 2007,   Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+==================================================================+
#property copyright "Copyright © 2007, Nikolay Kositsin"
#property link "farria@mail.redcom.ru"
//----+ +-------------------------------------------------------------------------------+
//---- EA INPUT PARAMETERS FOR BUY TRADES 
extern bool   Test_Up = true;//filter of trade calculations direction
extern int    Timeframe_Up = 240;
extern double Money_Management_Up = 0.1;
extern int    LengthA_Up = 4;  // smoothing depth of the quick moving
extern int    PhaseA_Up = 100; // parameter changing in the range 
          //-100 ... +100, influences the quality of transient process of quick moving
extern int    IPCA_Up = 0;/* Selecting prices, on which the indicator will be 
calculated by the quick moving (0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 
6-WEIGHTED, 7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW, 
11-Heiken Ashi Low, 12-Heiken Ashi High, 13-Heiken Ashi Open, 
14-Heiken Ashi Close.) */
extern int    LengthB_Up = 4; // smoothing depth increment of slow moving to quick one
extern int    PhaseB_Up = 100; // parameter changing in the range 
          //-100 ... +100, influences the quality of transient process of slow moving; 
extern int    IPCB_Up = 0;/* Selecting prices, on which the indicator will be 
calculated by the slow moving (0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 
6-WEIGHTED, 7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW, 
11-Heiken Ashi Low, 12-Heiken Ashi High, 13-Heiken Ashi Open, 
14-Heiken Ashi Close.) */
extern int    STOPLOSS_Up = 50;  // stop loss
extern int    TAKEPROFIT_Up = 100; // take profit
extern bool   ClosePos_Up = true; // forced position closing allowed
//----+ +-------------------------------------------------------------------------------+
//---- EA INPUT PARAMETERS FOR SELL TRADES 
extern bool   Test_Dn = true;//filter of trade calculations direction
extern int    Timeframe_Dn = 240;
extern double Money_Management_Dn = 0.1;
extern int    LengthA_Dn = 4;  // smoothing depth of the quick moving
extern int    PhaseA_Dn = 100; // parameter changing in the range
         // -100 ... +100, influences the quality of transient process of quick moving; 
extern int    IPCA_Dn = 0;/* Selecting prices, on which the indicator will be 
calculated by the quick moving (0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 
6-WEIGHTED, 7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW, 
11-Heiken Ashi Low, 12-Heiken Ashi High, 13-Heiken Ashi Open, 
14-Heiken Ashi Close.) */
extern int    LengthB_Dn = 4; // smoothing depth increment of slow moving to quick one
extern int    PhaseB_Dn = 100; // parameter changing in the range
         // -100 ... +100, influences the quality of transient process of slow moving; 
extern int    IPCB_Dn = 0;/* Selecting prices, on which the indicator will be 
calculated by the slow moving(0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 
6-WEIGHTED, 7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW, 
11-Heiken Ashi Low, 12-Heiken Ashi High, 13-Heiken Ashi Open, 
14-Heiken Ashi Close.) */
extern int   STOPLOSS_Dn = 50;  // stop loss
extern int   TAKEPROFIT_Dn = 100; // take profit
extern bool   ClosePos_Dn = true; // forced position closing allowed
//----+ +-------------------------------------------------------------------------------+
//---- Integer variables for the minimum of calculation bars
int MinBar_Up, MinBar_Dn;
//+==================================================================+
//| Custom Expert functions                                          |
//+==================================================================+
#include <Lite_EXPERT1.mqh>
//+==================================================================+
//| Custom Expert initialization function                            |
//+==================================================================+
int init()
  {
//---- Checking the correctness of Timeframe_Up variable value
   if (Timeframe_Up != 1)
    if (Timeframe_Up != 5)
     if (Timeframe_Up != 15)
      if (Timeframe_Up != 30)
       if (Timeframe_Up != 60)
        if (Timeframe_Up != 240)
         if (Timeframe_Up != 1440)
           Print(StringConcatenate("Parameter Timeframe_Up cannot ",  
                                  "be equal to ", Timeframe_Up, "!!!"));
//---- Checking the correctness of Timeframe_Dn variable value 
   if (Timeframe_Dn != 1)
    if (Timeframe_Dn != 5)
     if (Timeframe_Dn != 15)
      if (Timeframe_Dn != 30)
       if (Timeframe_Dn != 60)
        if (Timeframe_Dn != 240)
         if (Timeframe_Dn != 1440)
           Print(StringConcatenate("Parameter Timeframe_Dn cannot ",  
                                 "be equal to ", Timeframe_Dn, "!!!")); 
//---- Initialization of variables            
   MinBar_Up = 4 + 30;
   MinBar_Dn = 4 + 30;                                        
//---- end of initialization
   return(0);
  }
//+==================================================================+
//| expert deinitialization function                                 |
//+==================================================================+  
int deinit()
  {
//----+
   
    //---- End of EA deinitialization
    return(0);
//----+ 
  }
//+==================================================================+
//| Custom Expert iteration function                                 |
//+==================================================================+
int start()
  {
   //----+ Declaring local variables
   int    bar;
   double MovA[2], MovB[2];
   //----+ Declaring static variables
   static int LastBars_Up, LastBars_Dn;
   static bool BUY_Sign, BUY_Stop, SELL_Sign, SELL_Stop;
   
   //----++ CODE FOR LONG POSITIONS
   if (Test_Up)
    {
      int IBARS_Up = iBars(NULL, Timeframe_Up);
      
      if (IBARS_Up >= MinBar_Up)
       {
         if (LastBars_Up != IBARS_Up)
          {
           //----+ Initialization of variables 
           BUY_Sign = false;
           BUY_Stop = false;
           LastBars_Up = IBARS_Up;
           
           //----+ CALCULATING INDICATOR VALUES AND UPLOADING THEM TO BUFFERS        
           for(bar = 1; bar < 3; bar++)
                     MovA[bar - 1] =                  
                         iCustom(NULL, Timeframe_Up, 
                                "JJMA", LengthA_Up, PhaseA_Up, 
                                                   0, IPCA_Up, 0, bar);
           for(bar = 1; bar < 3; bar++)
                MovB[bar - 1] =                  
                   iCustom(NULL, Timeframe_Up, 
                     "JJMA", LengthA_Up + LengthB_Up, PhaseB_Up, 
                                                   0, IPCB_Up, 0, bar);
                                                   
           //----+ DEFINING SIGNALS FOR TRADES                                          
           if ( MovA[1] < MovB[1])
               if ( MovA[0] > MovB[0])
                        BUY_Sign = true;
                          
            if ( MovA[0] > MovB[0])
                        BUY_Stop = true;                                           
          }
          
          //----+ EXECUTION OF TRADES
          if (!OpenBuyOrder1(BUY_Sign, 1, Money_Management_Up, 
                                          STOPLOSS_Up, TAKEPROFIT_Up))
                                                                 return(-1);
          if (ClosePos_Up)
                if (!CloseOrder1(BUY_Stop, 1))
                                        return(-1);
        }
     }
     
   //----++ CODE FOR SHORT POSITIONS
   if (Test_Dn)
    {
      int IBARS_Dn = iBars(NULL, Timeframe_Dn);
      
      if (IBARS_Dn >= MinBar_Dn)
       {
         if (LastBars_Dn != IBARS_Dn)
          {
           //----+ Initialization of variables 
           SELL_Sign = false;
           SELL_Stop = false;
           LastBars_Dn = IBARS_Dn; 
           
           //----+ CALCULATING INDICATOR VALUES AND UPLOADING THEM TO BUFFERS
           for(bar = 1; bar < 3; bar++)
                     MovA[bar - 1] =                  
                         iCustom(NULL, Timeframe_Dn, 
                                "JJMA", LengthA_Dn, PhaseA_Dn, 
                                                   0, IPCA_Dn, 0, bar);
           for(bar = 1; bar < 3; bar++)
                MovB[bar - 1] =                  
                   iCustom(NULL, Timeframe_Dn, 
                     "JJMA", LengthA_Dn + LengthB_Dn, PhaseB_Dn, 
                                                   0, IPCB_Dn, 0, bar);
           
           //----+ DEFINING SIGNALS FOR TRADES                                          
           if ( MovA[1] > MovB[1])
               if ( MovA[0] < MovB[0])
                        SELL_Sign = true;
                          
            if ( MovA[0] < MovB[0])
                        SELL_Stop = true;                                                
          }
          //----+ EXECUTION OF TRADES
          if (!OpenSellOrder1(SELL_Sign, 2, Money_Management_Dn, 
                                            STOPLOSS_Dn, TAKEPROFIT_Dn))
                                                                   return(-1);
          if (ClosePos_Dn)
                if (!CloseOrder1(SELL_Stop, 2))
                                        return(-1);
        }
     }
//----+ 
    
    return(0);
  }
//+------------------------------------------------------------------+

Trading Systems Based on Crossing of Two Oscillators


The like trading strategy can be used not only with movings, but also with oscillators, but in this case, as written in the previous article, it is better to place pending orders instead of entering the market immediately after receiving signals. As a vivid example MACD diagram can be used.

For placing pending BuyLimit orders the algorithm will be like this:

Here is the algorithm for orders of SellLimit type:

The code of this EA is similar to the code of the previous EA:

//+==================================================================+
//|                                                        Exp_7.mq4 |
//|                             Copyright © 2007,   Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+==================================================================+
#property copyright "Copyright © 2007, Nikolay Kositsin"
#property link "farria@mail.redcom.ru"
//----+ +---------------------------------------------------------------------------+
//---- EA INPUT PARAMETERS FOR BUY TRADES 
extern bool   Test_Up = true; //filter of trade calculations direction
extern int    Timeframe_Up = 240;
extern double Money_Management_Up = 0.1;
extern int    FST_period_Up = 12;  // period of the quick moving
extern int    SLO_period_Up = 22; // period increment of slow moving to quick one
extern int    SIGN_period_Up = 8; // period of the signal line
extern int    Price_Up = 0;  // selecting prices, upon which MACD is calculated
extern int    STOPLOSS_Up = 50;  // stop loss
extern int    TAKEPROFIT_Up = 100; // take profit
extern int    PriceLevel_Up =40; // difference between the current price and 
                                         // price of pending order triggering
extern bool   ClosePos_Up = true; // forced position closing allowed
//----+ +---------------------------------------------------------------------------+
//---- EA INPUT PARAMETERS FOR SELL TRADES 
extern bool   Test_Dn = true; //filter of trade calculations direction
extern int    Timeframe_Dn = 240;
extern double Money_Management_Dn = 0.1;
extern int    FST_period_Dn = 12;  // period of the quick moving
extern int    SLO_period_Dn = 22; // period increment of slow moving to quick one
extern int    SIGN_period_Dn = 8; // period of the signal line
extern int    Price_Dn = 0;  // selecting prices, upon which MACD is calculated
extern int    STOPLOSS_Dn = 50;  // stop loss
extern int    TAKEPROFIT_Dn = 100; // take profit
extern int    PriceLevel_Dn =40;  // difference between the current price and 
                                         // price of pending order triggering
extern bool   ClosePos_Dn = true; // forced position closing allowed
//----+ +---------------------------------------------------------------------------+
//---- Integer variables for the minimum of calculation bars
int MinBar_Up, MinBar_Dn;
//+==================================================================+
//| Custom Expert functions                                          |
//+==================================================================+
#include <Lite_EXPERT1.mqh>
//+==================================================================+
//| Custom Expert initialization function                            |
//+==================================================================+
int init()
  {
//---- Checking the correctness of Timeframe_Up variable value
   if (Timeframe_Up != 1)
    if (Timeframe_Up != 5)
     if (Timeframe_Up != 15)
      if (Timeframe_Up != 30)
       if (Timeframe_Up != 60)
        if (Timeframe_Up != 240)
         if (Timeframe_Up != 1440)
           Print(StringConcatenate("Parameter Timeframe_Up cannot ",  
                                  "be equal to ", Timeframe_Up, "!!!"));
//---- Checking the correctness of Timeframe_Dn variable value 
   if (Timeframe_Dn != 1)
    if (Timeframe_Dn != 5)
     if (Timeframe_Dn != 15)
      if (Timeframe_Dn != 30)
       if (Timeframe_Dn != 60)
        if (Timeframe_Dn != 240)
         if (Timeframe_Dn != 1440)
           Print(StringConcatenate("Parameter Timeframe_Dn cannot ",  
                                 "be equal to ", Timeframe_Dn, "!!!")); 
//---- Initialization of variables             
   MinBar_Up = 4 + FST_period_Up + SLO_period_Up + SIGN_period_Up;
   MinBar_Dn = 4 + FST_period_Dn + SLO_period_Dn + SIGN_period_Dn;                                        
//---- end of initialization
   return(0);
  }
//+==================================================================+
//| expert deinitialization function                                 |
//+==================================================================+  
int deinit()
  {
//----+
   
    //---- End of the EA deinitialization
    return(0);
//----+ 
  }
//+==================================================================+
//| Custom Expert iteration function                                 |
//+==================================================================+
int start()
  {
   //----+ Declaring local variables
   int    bar;
   double MovA[2], MovB[2];
   //----+ Declaring static variables
   static int LastBars_Up, LastBars_Dn;
   static datetime StopTime_Up, StopTime_Dn; 
   static bool BUY_Sign, BUY_Stop, SELL_Sign, SELL_Stop;
   
   //----++ CODE FOR LONG POSITIONS
   if (Test_Up)
    {
      int IBARS_Up = iBars(NULL, Timeframe_Up);
      
      if (IBARS_Up >= MinBar_Up)
       {
         if (LastBars_Up != IBARS_Up)
          {
           //----+ Initialization of variables 
           BUY_Sign = false;
           BUY_Stop = false;
           LastBars_Up = IBARS_Up;
           StopTime_Up = iTime(NULL, Timeframe_Up, 0)
                                            + 60 * Timeframe_Up;
           
           //----+ CALCULATING INDICATOR VALUES AND UPLOADING THEM TO BUFFERS           
           for(bar = 1; bar < 3; bar++)
             MovA[bar - 1] = iMACD(NULL, Timeframe_Up, 
                      FST_period_Up, FST_period_Up + SLO_period_Up,
                                         SIGN_period_Up, Price_Up, 0, bar);
                          
           for(bar = 1; bar < 3; bar++)
             MovB[bar - 1] = iMACD(NULL, Timeframe_Up, 
                      FST_period_Up, FST_period_Up + SLO_period_Up,
                                         SIGN_period_Up, Price_Up, 1, bar);
                 
           //----+ DEFINING SIGNALS FOR TRADES                                          
           if ( MovA[1] < MovB[1])
               if ( MovA[0] > MovB[0])
                        BUY_Sign = true;
                          
            if ( MovA[0] > MovB[0])
                        BUY_Stop = true;                                           
          }
          
          //----+ EXECUTION OF TRADES
          if (!OpenBuyLimitOrder1(BUY_Sign, 1, 
              Money_Management_Up, STOPLOSS_Up, TAKEPROFIT_Up,
                                            PriceLevel_Up, StopTime_Up))
                                                                 return(-1);
          if (ClosePos_Up)
                if (!CloseOrder1(BUY_Stop, 1))
                                        return(-1);
        }
     }
     
   //----++ CODE FOR SHORT POSITIONS
   if (Test_Dn)
    {
      int IBARS_Dn = iBars(NULL, Timeframe_Dn);
      
      if (IBARS_Dn >= MinBar_Dn)
       {
         if (LastBars_Dn != IBARS_Dn)
          {
           //----+ Initialization of variables 
           SELL_Sign = false;
           SELL_Stop = false;
           LastBars_Dn = IBARS_Dn;
           StopTime_Dn = iTime(NULL, Timeframe_Dn, 0) 
                                            + 60 * Timeframe_Dn; 
           
           //----+ CALCULATING INDICATOR VALUES AND UPLOADING THEM TO BUFFERS          
           for(bar = 1; bar < 3; bar++)
             MovA[bar - 1] = iMACD(NULL, Timeframe_Dn, 
                      FST_period_Dn, FST_period_Dn + SLO_period_Dn,
                                         SIGN_period_Dn, Price_Dn, 0, bar);
                          
           for(bar = 1; bar < 3; bar++)
             MovB[bar - 1] = iMACD(NULL, Timeframe_Dn, 
                      FST_period_Dn, FST_period_Dn + SLO_period_Dn,
                                         SIGN_period_Dn, Price_Dn, 1, bar);
           
           //----+ DEFINING SIGNALS FOR TRADES                                          
           if ( MovA[1] > MovB[1])
               if ( MovA[0] < MovB[0])
                        SELL_Sign = true;
                          
            if ( MovA[0] < MovB[0])
                        SELL_Stop = true;                                                
          }
          //----+ EXECUTION OF TRADES
          if (!OpenSellLimitOrder1(SELL_Sign, 2, 
              Money_Management_Dn, STOPLOSS_Dn, TAKEPROFIT_Dn,
                                            PriceLevel_Dn, StopTime_Dn))
                                                                 return(-1);
          if (ClosePos_Dn)
                if (!CloseOrder1(SELL_Stop, 2))
                                        return(-1);
        }
     }
//----+ 
    
    return(0);
  }
//+------------------------------------------------------------------+

Conclusion

One more article is over. One more trading system was implemented in Expert Advisors based on absolutely different variants of indicators. I hope this article will be useful for beginning EA writers for further development of skills of converting a correctly formalized algorithm into a ready and absolutely operating code of your Expert Advisors.


Translated from Russian by MetaQuotes Software Corp.
Original article: https://www.mql5.com/ru/articles/1521

Attached files |
EXPERTS.zip (8.58 KB)
INCLUDE.zip (17.88 KB)
indicators.zip (5.19 KB)
TESTER.zip (5.27 KB)
Step on New Rails: Custom Indicators in MQL5 Step on New Rails: Custom Indicators in MQL5

I will not list all of the new possibilities and features of the new terminal and language. They are numerous, and some novelties are worth the discussion in a separate article. Also there is no code here, written with object-oriented programming, it is a too serous topic to be simply mentioned in a context as additional advantages for developers. In this article we will consider the indicators, their structure, drawing, types and their programming details, as compared to MQL4. I hope that this article will be useful both for beginners and experienced developers, maybe some of them will find something new.

Here Comes the New MetaTrader 5 and MQL5 Here Comes the New MetaTrader 5 and MQL5

This is just a brief review of MetaTrader 5. I can't describe all the system's new features for such a short time period - the testing started on 2009.09.09. This is a symbolical date, and I am sure it will be a lucky number. A few days have passed since I got the beta version of the MetaTrader 5 terminal and MQL5. I haven't managed to try all its features, but I am already impressed.

Using text files for storing input parameters of Expert Advisors, indicators and scripts Using text files for storing input parameters of Expert Advisors, indicators and scripts

The article describes the application of text files for storing dynamic objects, arrays and other variables used as properties of Expert Advisors, indicators and scripts. The files serve as a convenient addition to the functionality of standard tools offered by MQL languages.

How to create an indicator of non-standard charts for MetaTrader Market How to create an indicator of non-standard charts for MetaTrader Market

Through offline charts, programming in MQL4, and reasonable willingness, you can get a variety of chart types: "Point & Figure", "Renko", "Kagi", "Range bars", equivolume charts, etc. In this article, we will show how this can be achieved without using DLL, and therefore such "two-for-one" indicators can be published and purchased from the Market.