Custom Walk Forward optimization in MetaTrader 5

Stanislav Korotky | 15 September, 2017

Algorithmic trading consists not only of planning and development of trading robots but also (to a greater extent) testing and verifying the survivability of ideas and algorithms implemented in them. MetaTrader 5 provides the built-in tester for optimizing Expert Advisors on historical data. This tool is often indispensable in everyday activity. However, its main issue is the search for parameters that remain steadily profitable over time beyond the period the optimization was performed on. One of the possible solutions is forward testing. The tester features the appropriate built-in mode. But is it enough to optimize the EA once and successfully check it on a subsequent period to ensure its reliability?

The EA's operation cycle implies that the optimization and trade stages are repeated from time to time with the chosen frequency, and traders expect positive (or at least loss-free) results over a long period of time. To ensure the system's efficiency, it is necessary to repeat the cycle stages many times in the tester launching optimization and forward testing with a constant shift of the current period from the past to the virtual future.

This is called the walk forward optimization and widely used by many traders. Unfortunately, the built-in MetaTrader tester does not allow launching it at the touch of a button. Instead, we have to automate the tester launch using external tools and stick forward test reports together. Therefore, there is a need to execute a walk forward analysis in a simpler way solely by means of MetaTrader and MQL with no routine operations.

As it tuns out, we are able to develop an MQL library that can be easily connected to any EA if necessary. You will need some programming skills since we are going to adapt the EA source code.


Planning

Before describing the library principles, let's introduce a few concepts.

The optimization period is usually called in-sample data. The subsequent testing period is usually called out-of-sample data. For more convenience, we will also use the terms "optimization window" (or simply "window") and "test step" (or simply "step", "test").

The idea of the walk forward optimization is simple. In the tester, select the overall optimization period D which is much larger than the usual optimization window by pushing the start date to the past (point B). Allow the EA trade only within the current window W of a predetermined size and the subsequent testing step S. Make sure that D > W >> S. For example, D should include one W window and a dozen of S steps.

First, the window starts at the initial B point, but then it should move to the right by the step value sequentially many times till the window's right border reaches the final date of the overall optimization range D.

Optimization parameters should be calculated only based on trading within W window. Trading results within the S segment are to be calculated and saved for later analysis. Thus, it is possible to determine the optimal parameters for each particular window and, knowing the pass number, get a link to the corresponding test results.

This completely repeats the canonical walk forward except for one obvious nuance: trading on S does not start with an initial deposit, but with the amount the EA managed to earn within the W time. This feature limits the library's applicability only to strategies with a fixed lot. However, you will probably agree that verification with a fixed lot is the mandatory procedure when analyzing any EA even if you are going to enable money management at subsequent stages.

We are able to carry out the "fragmentary" trading mentioned above by adding special inputs that would set the size of the window W, step S and step index number defining the window shift inside the total D period as the number of steps. For example, when the shift is 0, the window starts in the B starting point. When it is equal to 1, the window starts at S and ends at S+W. If the shift is 2, the window starts at 2*S and ends at 2*S+W, etc. We can entrust the search of various shifts to the tester by enabling optimization according to the corresponding parameter. Thus, we are able to arrange multiple tester passes on segments including in-sample and out-of-sample data by moving them along the virtual time axis.

Now, we only need to adapt this mechanism for working as a consecutive forward optimization. To achieve this, make sure that optimization is performed only by trading results in each window W while ignoring all subsequent test periods S. Select the custom optimization criterion in the tester settings and calculate it in the library based on trade within the current window W returning it in the tester using the OnTester event handler afterwards. Besides, the library should calculate and save results of trading at each subsequent test period S. After completing the optimization, we will have multiple sets of parameters for each window W with the shift of i steps. The best set will be defined among them. The pass index number allows us to get trading results at the next test segment S immediately. By combining them together, we will obtain a full report on forward testing for several cycles within D.

Forming the walk forward test

Fig. 1. Forming the walk forward test

W and S sizes may vary at the trader's discretion. For example, you can select the optimization window of 3 months and a forward step of 1 month. If the total verification period D is 12 months, go through the steps S with shifts from 0 to 9 (inclusive) in the tester. 9 is obtained using a simple calculation:

N = (D - W) / S = (12 - 3) / 1 = 9 (1)

The forward step test is to be located to the right of window W on all iterations except the last one. However, when the shift is 9, the window W comes close to the end date and the forward test becomes impossible. If the walk forward optimization is generally successful, the optimal parameters of the last step are used as the recommended set for online trading.

The efficiency of forward optimization can be assessed by different criteria we are going to consider below. We already intuitively understand that the forward test steps put together form the balance curve defined by familiar parameters, like profit factor, Sharpe ratio, mathematical expectation of profit, etc.

However, let us dwell on another question: What are the suitable W window and S step sizes? It would be reasonable to have the tester search for the optimal values. Similar to going through forward test steps using a special input provided by the library, we can also include its parameters specifying the window and step size into the list of optimized ones.

The walk forward optimization performed together with selection of the best window and step size is called the cluster walk forward analysis.

Using the library and the results of optimizing all three parameters, we will be able to form a report containing the table of forward test profitability for various combinations of window and step sizes, as well as a refining report for each table cell containing all successive forward test steps at the corresponding W and S values in the combined form.

In addition to the described operation modes (cluster analysis and consecutive forward test, which is also called rolling walk forward), the library supports the anchored walk forward optimization. It is different from the rolling walk forward one in that the window W starting date never changes but the window size increases at each step including the test period of the previous iteration. For instance, let's go on with our example with the initial window size of 3 months and suppose that the total period D starts from January. At the first step, optimization is performed in January-March, while testing is done in April. The second step enables optimization in January-April with testing in May, while the third one entails optimization in January-May with testing in June, etc.

Now, all we have to do is implement the idea. Programmers and EA developers are able to create such a tool for themselves, since the task is quite transparent despite being quite extensive. If you want to obtain a ready-made product, there is the WalkForwardOptimizer (WFO) library both for MetaTrader 4 and 5. They differ in some nuances that make the version for MetaTrader 5 more attractive. In particular, in the fifth version:

  • the library is implemented as a single module that gathers optimization data and generates a report based on them. In the MetaTrader 4 version, files are generated in tester/Files and should be manually relocated to MQL4/Files. A separate script should then be launched to generate a report (all links are listed below);
  • most routine manual operations are eliminated including deletion of intermediate files before starting a new optimization;
  • names and values are automatically assigned to the EA working parameters (in MetaTrader 4, this data should be explicitly passed by calling the appropriate functions);
  • support for multi-threaded optimization, including network agents and MQL calculation cloud.
In general, MetaTrader 5 version is more efficient and easy to use. This is possible due to a wider range of useful tools provided by the tester's MQL5 API.


Implementation

So, the library program interface should provide the inputs allowing us to configure the tester so that it performs walk forward optimization. They are described in the header file:

input WFO_TIME_PERIOD wfo_windowSize = year;
input int wfo_customWindowSizeDays = 0;
input WFO_TIME_PERIOD wfo_stepSize = quarter;
input int wfo_customStepSizePercent = 0;
input int wfo_stepOffset = 0;
input string wfo_outputFile = "";
input WFO_ESTIMATION_METHOD wfo_estimation = wfo_built_in_loose;
input string wfo_formula = "";

The wfo_windowSize and wfo_stepSize parameters allow setting the window size and optimization step. The WFO_TIME_PERIOD enumeration is used to set them in standard units:

#define DAYS_PER_WEEK    7
#define DAYS_PER_MONTH   30
#define DAYS_PER_QUARTER (DAYS_PER_MONTH*3)
#define DAYS_PER_HALF    (DAYS_PER_MONTH*6)
#define DAYS_PER_YEAR    (DAYS_PER_MONTH*12)

#define SEC_PER_DAY     (60*60*24)
#define SEC_PER_WEEK    (SEC_PER_DAY*DAYS_PER_WEEK)
#define SEC_PER_MONTH   (SEC_PER_DAY*DAYS_PER_MONTH)
#define SEC_PER_QUARTER (SEC_PER_MONTH*3)
#define SEC_PER_HALF    (SEC_PER_MONTH*6)
#define SEC_PER_YEAR    (SEC_PER_MONTH*12)

#define CUSTOM_DAYS     -1

enum WFO_TIME_PERIOD
{
  none = 0,
  year = DAYS_PER_YEAR,
  halfyear = DAYS_PER_HALF,
  quarter = DAYS_PER_QUARTER,
  month = DAYS_PER_MONTH,
  week = DAYS_PER_WEEK,
  day = 1,
  custom = CUSTOM_DAYS
};

A day is the base measurement unit. Smaller steps are not supported. The tester itself allows setting dates only within the accuracy of one day. The alternative working within the accuracy of a bar is offered below for those practicing the intraday forward optimization.

Keep in mind that that a week, a month, a quarter and a year are defined as constants (fixed number of days). Alignment by the calendar boundaries of the periods does not occur. This increases the efficiency of calculations and unifies moving an arbitrary-sized window without binding to weeks or months boundaries. If the month period is selected (30 days) and the count starts from the beginning of any month, the change of each subsequent calendar month may obviously occur before or after the "month" step (since months differ in the number of days). If the count starts from the middle of a month, the step falls into the middle of subsequent months with a shift in the ordinal day of a month.

The 'custom' value in wfo_windowSize or wfo_stepSize allows setting arbitrary window and step size in subsequent parameters — wfo_customWindowSizeDays and wfo_customStepSizePercent accordingly. As we can see from the parameter names, a window is defined in days, while a step — in % of the window.

These parameters allow us to arrange the search of the sizes during the cluster optimization. We should select the sizes so that the minimum (initial) percentage and its changes with a given increment provide us with an integer number of days after being applied to the minimum window. For example, if the window changes from 10 to 50 with a step of 10, there is no point in reducing the step below 10%, since this is 1 day from the minimum window. In addition, the increment for the forward step should not be less than 10%. If it was, for example, 5%, then, at the window size of 30, the second iteration would mean a test on the interval of 15% (initial 10% plus one step of 5%) out of 30, which would give 4.5. Such a configuration, of course, will not lead to a fatal error, and the library will continue to work normally, however, the forward test steps may turn out to be not fitted exactly to each other, which will affect the accuracy of calculations.

Unfortunately, the library cannot offer convenient tools to simplify the configuration and verify its correctness in this context. Users should check the parameters themselves (meaning they should have at least some basic knowledge of programming). One of the possible solutions is implementing another approach to the library arrangement — in particular, working within the accuracy of a bar. We will dwell on this below.

If wfo_windowSize and wfo_stepSize are equal to 'none', the library is disabled.

The wfo_stepOffset parameter (being included into the optimized ones) allows sorting through forward test steps. Its increment should always be 1. The maximum value is calculated using the equation (1) involving the maximum window size W and the minimum step size S.

The wfo_outputFile parameter sets the name of the csv file where financial results of optimization runs are saved. The file is created in MQL5/Files (МТ5) or tester/Files (МТ4).

The wfo_estimation parameter defines the result to be passed to the tester for optimization. The value is one of the WFO_ESTIMATION_METHOD enumeration values:

enum WFO_ESTIMATION_METHOD
{
  wfo_built_in_loose,
  wfo_built_in_strict,
  wfo_profit,
  wfo_sharpe,
  wfo_pf,
  wfo_drawdown,
  wfo_profit_by_drawdown,
  wfo_profit_trades_by_drawdown,
  wfo_average,
  wfo_expression
};
  • wfo_built_in_loose (by default) and wfo_built_in_strict — complex indicators consisting of the Sharpe ratio, profit factor, profit size and number of trades;
  • wfo_profit — profit;
  • wfo_sharpe — Sharpe ratio;
  • wfo_pf — profit factor;
  • wfo_drawdown — inverted relative drawdown (100 - DD) calculated on the balance curve;
  • wfo_profit_by_drawdown — profit divided by the relative drawdown;
  • wfo_profit_trades_by_drawdown — profit multiplied by the number of trades and divided by the relative drawdown;
  • wfo_average — trade's average profit;
  • wfo_expression — custom result equation.

Finally, the wfo_formula parameter is the same custom equation for calculating the result if wfo_estimation is equal to wfo_expression. You can find out more about valid equations and other settings in the library user guide (in Russian).

All parameters have the wfo_ prefix, so that they can easily be distinguished from the EA's working parameters.

Remember that after you include a header file to your EA, the described input parameters are created in it. We may call them meta parameters since they manage the optimization process.

Also, please note that the header only declares the required types and meta parameters. In order for the data to get into the library, we need a set of open functions — the library's programming interface. They are also described in the header file as an import directive (the version for MetaTrader 5 is considered from now on):

#import "WalkForwardOptimizer.ex5"
void wfo_setEstimationMethod(WFO_ESTIMATION_METHOD estimation, string formula);
void wfo_setPFmax(double max);
void wfo_setCloseTradesOnSeparationLine(bool b);
void wfo_OnTesterPass();
int wfo_OnInit(WFO_TIME_PERIOD optimizeWindow, WFO_TIME_PERIOD optimizeStep, int optimizeStepOffset, int optimizeCustomW, int optimizeCustomS);
int wfo_OnTick();
double wfo_OnTester();
void wfo_OnTesterInit(string optimizeLog);
void wfo_OnTesterDeinit();
#import

The functions having the wfo_set prefix are optional. They allow setting the operation mode, but if you do not call them, the default values will be used. The functions with the wfo_On prefix handle the appropriate events. They should be added to the EA's source code.

Below is an example of the EA's source code with a built-in library. All function parameters are taken directly from the input meta parameters.

#include <WalkForwardOptimizer.mqh>

...

int OnInit(void)
{
  // your working code here
  ...

  // optional, the default is wfo_built_in_loose
  wfo_setEstimationMethod(wfo_estimation, wfo_formula);

  // optional, the default is DBL_MAX
  wfo_setPFmax(100);

  // optional, the default is false
  // wfo_setCloseTradesOnSeparationLine(true);
  
  // obligatory, all parameters from the header file
  int r = wfo_OnInit(wfo_windowSize, wfo_stepSize, wfo_stepOffset, wfo_customWindowSizeDays, wfo_customStepSizePercent);
  
  return(r);
}

void OnTesterInit()
{
  wfo_OnTesterInit(wfo_outputFile); // obligatory
}

void OnTesterDeinit()
{
  wfo_OnTesterDeinit(); // obligatory
}

void OnTesterPass()
{
  wfo_OnTesterPass(); // obligatory
}

double OnTester()
{
  return wfo_OnTester(); // obligatory
}

void OnTick(void)
{
  int wfo = wfo_OnTick();
  if(wfo == -1)
  {
    // wait till the window starts
    // do not trade
    return;
  }
  else if(wfo == +1)
  {
    // wait for the test end after the window and forward
    // do not trade
    return;
  }

  // your working code here
  ...
}

wfo_OnInit passes all necessary data to the library: window size, step, step number, custom window size in days, custom step size in % of the window. It returns 0 in case of success or error code (for example, INIT_PARAMETERS_INCORRECT) if the incorrect parameters have been set.

wfo_OnTick manages EA optimization inside the optimization window and forward test. It returns 0 if the current tick (bar) falls within the moving frame where the EA is allowed trading, or -1/+1 if the tick is outside of the window and trading should be temporarily disabled (-1 means the window has not arrived yet, while +1 means the window has already passed).

wfo_OnTester calculates and returns the given efficiency parameter to the tester.

wfo_setCloseTradesOnSeparationLine sets the mode of closing all market orders and removing all pending ones when crossing the border between the optimization window and the forward test.


Practice

When the EA with the built-in library is compiled, it is time to configure the tester.

Let's choose a specific date range in the Interval fields group. This is the same general period D described above. Usually, the end date is the current day or something close to it.

In the Forward field, select No (the built-in forward test is not suitable for us).

Set Execution mode to Normal, using bars or control points. Keep in mind that our walk forward involves the meta parameters included into optimization (in addition to the EA's operating parameters) and thereby increasing the computational load.

In the Optimization mode, you are able to select the slow (full sorting) or the fast mode (using genetics), while the Optimization criterion should always be custom.

The use of the genetic optimization algorithm is allowed, but it is necessary to bear in mind some nuances. The genetic algorithm skips many combinations of input parameters, including combinations of meta parameters specifying the size of the window, the size of the forward step and the step number. This is why some forward tests may be absent. This issue is noticeable if the search space is very large (if there are many EA working parameters or their increments), but otherwise it can be neglected. Omissions are marked in the generated report allowing us to decide on whether we should try to reduce the optimization space.

This issue often occurs during a cluster optimization. Sequential or anchor forward optimizations are less susceptible to it.

The genetic algorithm may "prioritize" unevenly between optimization windows with different shifts depending on their profitability. For example, if the first month of trading is objectively more difficult than the second one, the tester is likely to pay more attention to the wfo_stepOffset parameter with the value of 1 rather than 0. In other words, genetic optimization based on multiple windows within the date range D does not yield the same optimal results as genetic optimization based on a particular window W (with the library turned off). The only solution is to use a slow full search of all parameters and meta parameters.

On the other hand, the walk forward checks the stability of the algorithm on out-of-sample data and also selects the best depth of history for optimization and the step of re-optimization (how often to look for the new settings). These functions are normally performed without searching for the optimal parameters.

Configure the EA working parameters requiring optimization in the usual way. The configuration of the meta parameters depends on which mode of walk forward optimization you want to enable.

Sequential walk forward optimization on pre-defined periods
  1. Select the optimization window from the list using wfo_WindowSize
  2. Select the forward step size from the list in wfo_stepSize
  3. Enable optimization for wfo_stepOffset in the range from 0 to any number of steps fitting to the available history with a step of 1.
Sequential walk forward optimization on arbitrary periods
  1. Select 'custom' from the wfo_WindowSize list of parameters
  2. Enter the number of days to wfo_customWindowSizeDays
  3. Select the 'custom' size for the wfo_stepSize parameter
  4. Enter the size to wfo_customStepSizePercent as a % of the window size
  5. Enable optimization for wfo_stepOffset in the range from 0 to any number of steps fitting to the available history with a step of 1.
Cluster walk forward optimization
  1. Select the optimization window size in wfo_WindowSize as 'custom'.
  2. Enable optimization for wfo_customWindowSizeDays for any suitable range and increment in days.
  3. Select the forward step size in wfo_stepSize as 'custom'.
  4. Enable optimization for wfo_customStepSizePercent for any suitable range and increment in % of the window size (recommended range of values is 5-30%, step is 5-10%).
  5. Enable optimization for wfo_stepOffset in the range from 0 to any number of steps fitting to the available history with a step of 1.
If you have a preferred optimization window size, you can run the cluster analysis only for a varying step, and if you have already selected the step size, you can only change the window size.

Anchor walk forward optimization
  1. Select the optimization window size in wfo_WindowSize as 'custom'.
  2. Enable optimization for wfo_customWindowSizeDays on a desired range. As an increment, select the number of days equal to the length of the predefined period to be set on the next step (for example, enter an increment of 30 days if you are going to use the "month" step).
  3. Select the step size from the wfo_stepSize list of predefined constants. The constant should be equal to the increment specified for the window size above.
  4. Disable the optimization for wfo_stepOffset and set its value to 0.

When everything is set up, run the optimization and wait for its completion. Unlike the standard optimization, we cannot pause and then continue the process when dealing with the library. This is due to the fact that the suspension and continuation of the tester do not have the corresponding program events in MQL5 API. Therefore, the library data cache cannot be synchronized with the tester cache. In other words, each pressing of the Start button causes a complete initialization of the library regardless of the internal state of the tester, and the library starts collecting the data on passes from scratch. If a previously suspended optimization is resumed, all data collected by the library before the pause are lost. I recommend clearing the tester/cache folder before starting the walk forward optimization.

During the optimization, WFO creates special global variables (saved in the "archive" file with the GVF extension) and a CSV file with data in the MQL5/Files folder. After that, an html page decoding the results is automatically formed based on them. GVF and HTML file names coincide with the name of the CSV file set in the library via the wfo_outputFile parameter.

Let's take a simple EA and have a look at what reports we can obtain using the library in different modes. The EA was generated by the MQL5 wizard based on the two trading strategies — Envelopes and WPR. It is available in the Market as a free product.

Attention! The EA is not a grail. It is an average sample with the sole objective to act as a lab rat for the library. 

We will conduct our experiments on the EURUSD D1 chart. First, let's try to get a simple rolling walk forward report. Set the total testing period 2015.01.01-2017.06.01.

The tester settings

Fig. 2. The tester settings

The EA has the EnableWFO parameter, which is 'false' by default. In this case, the library is disabled, and the EA trades normally. To enable the library, set the flag to 'true'.

Leave the default values of wfo_windowSize (year) and wfo_stepSize (quarter). They specify the movement of the optimization window of 1 year with shifts of 1 quarter, and the quarter is a single forward test. This provides us with (2.5 years - 1 year) / 3 months = (30 - 12) / 3 = 6 forward testing steps.

Set the demo.csv file name to wfo_outputFile.

Among the EA's working parameters to be optimized are Stop Loss and Take Profit levels, period and Envelopes deviation, as well as WPR period. The set of parameters (wfo-demo-rolling.set) is attached at the end of the article.

The EA settings

Fig. 3. The EA settings

After the optimization, we obtain the demo.html report looking as follows.

Rolling walk forward report

Fig. 4. Rolling walk forward report

As we can see, the EA behaves very badly at forward periods. However, the negative result can also be useful.

Now let's try to get a cluster report and choose the optimization window and step size, in which the profit is stable. To achieve this, set wfo_windowSize and wfo_stepSize to 'custom' and configure wfo_customWindowSizeDays for optimization from 90 to 180 days with a step of 30 and wfo_customStepSizePercent — from 10 to 30% with the step of 10. The maximum number of steps in wfo_stepOffset is received as a ratio from (2.5 years - 90 days) / (90 days * 10%) = 810 / 9 = 90. The set of parameters (wfo-demo-cluster.set) is attached at the end of the article.    

A sample report is displayed below (the parameters are examined in more details in the next section — Analysis).

Cluster walk forward report

Fig. 5. Cluster walk forward report

Many table cells show satisfactory results. Let's clarify what means the configuration of the window of 120 days and the step of 30%. To do this, click on the appropriate cell and see the details of the forward test.

Clarifying rolling walk forward report

Fig. 6. Clarifying rolling walk forward report

Despite the positive result, the balance curve is not impressive. Looking at other versions, we can conclude that the EA is not stable enough with the currently selected optimization parameters. It requires either adjusting the set of trading strategies or optimizing other parameters we have not used.

Obtaining suitable results always takes a long time and the use of the walk forward solution simplifies the task only by allowing us to sort out many options, which would require much more efforts to check with conventional methods. The search for ways to improve the EA characteristics remains mostly intuitive. The walk forward does not provide any help here. It is most suitable when we already have more or less profitable EA, and we need to find out whether its results have actually been achieved by fitting and if they have been thoroughly checked.


Analysis

The generated report contains various data depending on the selected library mode. In the cluster analysis, the report starts with several tables containing the final parameters of a set of consecutive walk forward tests. In each table, the columns correspond to the size of the window W in days, and the rows correspond to the step size S in %. Each cell in the table is a hyperlink leading to the corresponding report of the consecutive walk forward test. Thus, it is possible to clarify how any final parameter was calculated.

The following parameters are displayed in the cluster analysis tables:

  • Annualized profit/loss is a hypothetical profit of the EA for a year when re-calculating the profit proportional to the periods of optimization and testing.
  • Efficiency is a ratio of annual profit in the test and optimization periods within the same run.
  • Consistency is a percentage of profitable passes among all test passes of the combined forward.
  • Completeness is a number of forward steps performed for specific combinations of window size and forward step. It may be less than the requested number during a genetic optimization due to missing some parameter values. The number of skipped steps is indicated in small print in parentheses.
  • Days in step is a number of days in a step for each combination of window size and step to convert the step size from % to days.

Annualized profit, efficiency and consistency are the main criteria for assessing the success of forward testing. It is clear that the higher they are, the better. It is recommended to have a consistency above 50%. The best options are highlighted in green in the cluster analysis tables.

In addition, it makes sense to pay attention to the drawdown, mathematical expectancy and standard deviation of profit — they are available in the refining standard reports.

Reports of standard (consecutive) tests are built not only as refining ones for the cluster analysis versions, but also as the results of a simple rolling walk forward optimization.

In case of a standard (consecutive) or anchor walk forward test, the report is a table containing all the runs of the tester that have generated this combined forward. Each row contains trading parameters — profit, profit factor, total number of trades and profitable trades, drawdown, Sharpe ratio — displayed separately for the periods of optimization and testing. Optimization parameters are highlighted in blue, while test period ones — in yellow. If the last step captures the "current" time (the end date of testing), it is highlighted in green indicating that these are the last known parameters and therefore they are applicable to the "current" trading. Of course, the "current" time is actually current only if the end date of the optimization is set for today.

The first three columns of the forward report show the index number of the tester pass, the start date of the optimization window (in-sample), as well as the start and end dates of the test period (out-of-sample). The last column of the report displays the values ​​of the parameters found as a result of optimization within the window. Tooltips with the names of the parameters can be obtained by hovering the mouse over the column header.

In case of the genetic optimization method, the pass index numbers in the built-in report are displayed not in numerical form but as a "generation number, instance number". This means you can match the rows of the built-in report with the rows of the WFO library report only by the parameters. We are able to avoid this issue when using a slow optimization method, since the pass index numbers in both reports are the same in that case. This is a feature of the MetaTrader 5 platform, not the library.

By double-clicking the corresponding row of the built-in tester report, we can reproduce the EA trading in a certain walk forward optimization window and the subsequent walk forward testing step. Please note that there is no trading outside this range of dates. If you want to see how the EA would trade with this set outside the window, you should disable the library or set wfo_windowSize to 'none'.

The schematic diagram of the balance curve is displayed after the table.    

Let's sum up the intermediate results. We have managed to arrange the walk forward optimization directly in the MetaTrader tester in a simplified form. It works and gives interesting results. However, setting the library parameters has turned out to be tricky. For some users, selection of correct meta parameters causes difficulties. Another issue is related to performance. Since the library operation is based on additional meta parameters that participate in optimization, the search space is substantially increased requiring more computing resources. Is it possible to somehow simplify the situation? Yes, it is. But to achieve this, we will have to reinvent the wheel by revising the library operation principles and, in fact, implementing a different library. 


Walk forward for the lazy and busy

The new library is also built into the EA but it does not expose the parameters and does not imply configuring. The EA is launched for optimization on the common (increased) period D. The difference from the usual optimization here is only in this period since the usual optimization is performed by a user on the selected window W. During the optimization on D, the new library collects information about all trades performed by the EA (for different sets of parameters). In other words, for each pass of the tester, a file is formed where the current balance is recorded on each bar, together with a floating profit and the number of open positions. It turns out that after completing the optimization, you can build various walk forward reports based on this data. The reports are similar to those discussed above. In the case of MetaTrader 4, this can be done by a separate script, and in the case of MetaTrader 5 - by the library itself.

This library also has versions for MetaTrader 4 and MetaTrader 5. Let's consider here the implementation for MetaTrader 4 for a change. The complete documentation with the nuances of the differences in the versions (in Russian) is published in the blog.

Let us explain the operation principle of the simplified library.

When using it, the tester does not actually perform optimization as such, but it sorts through various combinations of input parameters. Optimal sets for each window are selected during the report generation. The script allocates the required in-sample W window from the total D period, calculates the performance parameters for all tester passes (each pass is a separate set of parameters) and finds the best option. Then it calculates the trading efficiency parameters at the subsequent out-of-sample step S on the same pass.

This algorithm implements walk forward in a non-standard way. This allows for ease of use, but has its side effects. In particular, when using the genetic optimization method, some bias is introduced due to the fact that the parameter sets being tested are optimal in the global sense (for the entire period D, and not for the current window W). This can be regarded as a glimpse into the future. However, on the other hand, the best global parameters are likely to produce smaller profits than the parameters that could be found by local optimization on the W window.

In any case, this problem does not exist in case of slow full search of the parameters.

It should also be noted that the EA trades on the entire period D, and there are two consequences arising from that.

First, the balance may be arbitrary at the beginning of a particular window W. Similar to WFO, this means that the new library is only applicable to strategies with a fixed lot.

Secondly, some positions may cross the initial or final window borders during their existence, i.e. an open position may already exist and have a floating profit at the start of the window, or the position may be opened within the window and closed at the forward test stage. This inaccuracy is the payment for simplifying the process. With the increase in the number of trades, the negative effect from this decreases down to a negligible value. For example, if you use a netting account, a maximum of one position may distort the numbers at the start of the window, and a maximum of one position may do that at its end. If there are 100 double entry/exit trades in the W window, the average error in the calculations is no more than 2% of the average trade size.

The library interface in the wfL.mqh header file is very simple. 

#import "wfL.ex4"
  int wfl_OnInit(const int cleanUpTimeout);
  void wfl_OnTick();
#import

Embedding in the EA code is also greatly simplified.

#include <wfL.mqh>

int OnInit()
{
  // ... working code
  wfl_OnInit(60);
}

void OnTick()
{
  // ... working code
  wfl_OnTick();
}

Optimization is performed using the same procedure described above for the WFO library.

The optimization period should contain at least 200 bars, but 1000 or more is recommended. This is due to the fact that the division of the general period into windows and forward test steps is done on bars, and sets of checked window sizes and offsets are predefined in the library code: the size of the windows varies from 10% to 50% in increments of 10% (note that the window size is set as a percentage of the total test range D here), and the step size S is from 5% to 30% in increments of 5%.

After the optimization is complete, the directory of the following form is created in the Tester/Files folder:

<EA name>-<Symbol>-<Timeframe>-<Date>-<Time>

It contains csv files with meta data collected by the library during each pass of the tester. Each entry in the file contains information on one bar: date and time, balance, floating profit and the number of open trades. Using this data, you can calculate the profit and loss on any window within the period. Information about individual trades is not stored or analyzed.

By moving the specified folder along with all the files from Tester/Files to MQL4/Files, you can run the report generation script — specify the folder name in the input parameter. The optimization criterion, according to which the best parameter sets within specific windows are to be selected, is specified as well. The available criteria are the same as in the full version of the WFO library. As a result, we obtain a clustered report with refining consecutive walk forward tests (its example is shown above).

All minor drawbacks mentioned above are easily mitigated by exceptional productivity and ease of use. Since there are no meta parameters here, the walk forward optimization does not introduce any overhead costs in comparison with the usual optimization based on the selected working parameters of the EA.


Conclusion

We have considered possible principles for constructing and implementing walk forward optimization technology within the currently available means of the built-in tester. The ready-made libraries described above allow you to test the approach with minimal effort. Some simplifications and limitations of the libraries distinguish the resulting walk forward from the conventional one providing ease of use and not requiring any external applications. Until MetaTrader has the built-in ability to conduct walk forward optimization, such libraries provide an efficient alternative.


Product summary table

Product MetaTrader 4 MetaTrader 5

WFO: WalkForwardOptimizer & WalkForwardReporter

WalkForwardOptimizer
Library
https://www.mql5.com/en/market/product/17683 https://www.mql5.com/en/market/product/23068
WalkForwardReporter
Script
https://www.mql5.com/en/market/product/17750 (not required,
MT5 WFO library generates reports automatically)
WalkForwardDemo
EA
(none) https://www.mql5.com/en/market/product/23069

WFL: WalkForwardLight & WalkForwardBuilder

WalkForwardLight
Library
https://www.mql5.com/en/market/product/23223 https://www.mql5.com/en/market/product/23224
WalkForwardBuilder
Script
https://www.mql5.com/en/market/product/23225 https://www.mql5.com/en/market/product/23226
(option)

Clicking on the icon leads to the page of the corresponding product.



Parameters for the consecutive (rolling) WF analysis of the demo EA — wfo-demo-rolling.set

Parameters for the cluster WF analysis of the demo EA — wfo-demo-cluster.set