Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano Türkçe
Continuous futures contracts in MetaTrader 5

Continuous futures contracts in MetaTrader 5

MetaTrader 5Indicators | 6 June 2014, 15:26
6 165 1
Vladimir Karputov
Vladimir Karputov

Introduction

Trader can't create his own charts in MetaTrader 5 as it can be constructed only with the broker's symbols. The trader requires a synthetic product – the continuous futures contract. The problem is that only a broker can make splicing of contracts and only the broker decides whether he will connect futures on the given symbol.

Fortunately, the history of the closed futures is always available in the terminal. Use this history to splice futures contracts in the terminal.


Conventions:

  1. All data, drawings and screenshots in the article are based on the real Ukrainian Stock index futures.
  2. Code sections replaced or added into the article will be marked with color. For example:
    //+------------------------------------------------------------------+
    //|                                               This is an example |
    //|                                               of the edited code |
    //+------------------------------------------------------------------+

The first problem: dates overlap

Nearby futures are traded with dates overlapping.

It means, that the futures is put on trading while another futures has still two months to be closed.

Fig. 1. Dates overlap in the futures contracts

Fig. 1. Dates overlap in the futures contracts

The figure shows that 2013.09.16 is the start date of the UX-3.14 futures trading, although the UX-12.13 futures is still open.


The second problem: choosing the splicing way

There are two methods of splicing:

  • The simple addition – when the date of circulation of the current instrument has expired and the next instrument is opened in another bar. During the simple addition the prices on the chart will match their history values, but at the same time there will always be price gaps in the spliced places, i.e. the chart will not be smooth. 

Fig. 2. Splicing. Simple addition.

Fig. 2. Splicing. Simple addition

  • addition with shift: the current instrument has 5-10 days before it will be closed and we begin to replace these 5-10 bars with the next instrument bars. The 5-10 bars interval is called the transition period. During the addition with shift prices will show wrong values (they will not correspond to the current instrument) but in comparison to the simple addition method, the chart will be more smooth.

Fig. 3. Splicing. Addition with shift

Fig. 3. Splicing. Addition with shift


Settings in the terminal

In the "Market watch" window futures should be placed in the descending order:

Dib. 4. Observación del mercado

Fig. 4. Market watch


Writing an indicator

Default indicator should be placed in the terminal_data_folder\MQL5\Indicators folder. Create Synthetics folder in MyIndicators (which you open in the \Indicators). It allows you to save the space in the \Indicators folder in the Standard Library and facilitates MQL5 Storage launch synchronization of indicators. The final path of the folder looks like this: terminal_data_folder\MQL5\Indicators\MyIndicators\Synthetics.

In the Synthetics folder create a new file:

Dib. 5. Creamos el nuevo archivo del indicador

Fig. 5. The indicator new file creation

Set the new file type - "Custom indicator":

Dib. 6. Tipo del nuevo archivo - "Indicador personalizado"

Fig. 6. The new file type - "Custom indicator"

Press "Next" and open the "General properties of the custom indicator" window. Enter the name of the indicator - "SYNT", add two options. The first option "Number of futures for splicing" determines the number of the instruments to be connected. Note, that 2 is the minimum possible value of the "Number of futures for splicing". The second option "Gluing type" determines the splicing type in the default indicator - "simple addition":

Dib. 7. Parámetros del indicador personalizado

Fig. 7. The custom indicator parameters

Pay attention to the "Gluing type" option: the splicing can be "simple addition" or "addition with shift". At this stage you can't add the list of these two splicing types. That is why leave the default "simple addition". During the "SYNT" indicator code writing switch on the Later option to see the dropdown list with the splicing types.

In the next window select the indicator event handlers:

Dib. 8. Operador informático de los eventos para el indicador

Fig. 8. The indicator event handlers

Note, that the OnTimer() function will be used in the "SYNT" indicator. The main functionality of the indicator is set in the OnTimer() . The indicator can be attached both to the symbol chart with the finished trade (this symbol will not include OnCalculate events), and to the symbol chart with an active trade.

Press "Next" and in the "General properties of the Custom indicator program" tick "Indicator in separate window":

Dib. 9. Elegir la opción del "indicador en una ventana por separado"

Fig. 9. "Indicator in separate window" option

Press the "Done" button and you will see the "SYNT" indicator template.


Organizing the dropdown list

In order to see the splicing types list as the dropdown list you need to declare the ENUM_GLUING_TYPE enumeration in the indicator options.

Declare enumeration in the global area at the beginning of the input parameters block:

#property indicator_separate_window
//+------------------------------------------------------------------+
//|  Splicing types enumeration                                      |
//+------------------------------------------------------------------+
enum ENUM_GLUING_TYPE
  {
   simple_addition,        // simple addition||simple addition
   addition_with_shift     // addition with shift||addition with shift
  };  
//--- input parameters || input parameters
input ENUM_GLUING_TYPE  gluing_type=simple_addition;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+

Now you can check how the dropdown list is displayed.

You should compile the indicator (F7) file. Now, after you have attached the indicator, you can see in the options that the dropdown list launches:

Dib. 10. Ahora tenemos una lista desplegable en los parámetros

Fig. 10. Now you have the
dropdown list in the parameters
 

Add the description of the indicator which will be displayed in the "General" tab when it will be attached to the chart the first time or when its properties will be changed:

#property version   "1.00"
//+------------------------------------------------------------------+
//| version   "1.00": The timer history swapping                     |
//+------------------------------------------------------------------+
#property description "Indicator for several futures splicing."
#property description "Is drawn in the latest futures window"
#property description "Uses N first symbols for drawing"
#property description "which were taken from the \"Market review\"."

#property indicator_separate_window 

The indicator construction method - DRAW_COLOR_CANDLES - colored candles.

You need 4 indicator buffers and 1 buffer for the color index store. The style of the line, indicator - STYLE_SOLID - continuous line. Display everything in the indicator code:

#property description "taken from the \"Market review\"."

//--- indicator settings || indicator settings
#property indicator_separate_window
#property indicator_buffers 5 
#property indicator_plots   1
//--- plot Bars || bars plotting
#property indicator_label1    "SYNT"
#property indicator_type1     DRAW_COLOR_CANDLES
#property indicator_style1    STYLE_SOLID
#property indicator_width1    1
//+------------------------------------------------------------------+
//|  enumeration of splicing methods                                 |
//+------------------------------------------------------------------+

Enter the "number_futures_gluing" input parameter - number of instruments required for construction. The default "number_futures_gluing" value equals 2:

//--- input parameters || input parameters
input int               numder_futures_gluing=2;
input ENUM_GLUING_TYPE  gluing_type=simple_addition;

Declare 4 indicator buffers, 1 buffer for the color index storing and the LoadHistory[] auxiliary array:

#property indicator_style1    STYLE_SOLID
#property indicator_width1    1
//--- indicator buffers || indicator buffers
double            OpenBuffer[];
double            HighBuffer[];
double            LowBuffer[];
double            CloseBuffer[];
double            ColorCandlesColors[];
double            LoadHistory[];
//+------------------------------------------------------------------+
//|  enumeration of splicing methods                                 |
//+------------------------------------------------------------------+

Attach indicator buffers to the one-dimension dynamic arrays, set buffers indexing as in timeseries:

//--- indicator buffers mapping
//--- indicator buffers mapping
   SetIndexBuffer(0,OpenBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,HighBuffer,INDICATOR_DATA);
   SetIndexBuffer(2,LowBuffer,INDICATOR_DATA);
   SetIndexBuffer(3,CloseBuffer,INDICATOR_DATA);
   SetIndexBuffer(4,ColorCandlesColors,INDICATOR_COLOR_INDEX);
   SetIndexBuffer(5,LoadHistory,INDICATOR_CALCULATIONS);
//--- set buffer indexing as timeseries
//--- set buffer indexing as in timeseries
   ArraySetAsSeries(OpenBuffer,true);
   ArraySetAsSeries(HighBuffer,true);
   ArraySetAsSeries(LowBuffer,true);
   ArraySetAsSeries(CloseBuffer,true);
   ArraySetAsSeries(ColorCandlesColors,true);
//---
   return(INIT_SUCCEEDED);

To display the name of the indicator series ("Open", "High", "Low" and "Close") in the "Data window" you need the s_symbol variable:

input int               numder_futures_gluing=2;
input ENUM_GLUING_TYPE  gluing_type=simple_addition;
//--- symbol name
string s_symbol;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+

To activate the indicator you need the shft_array variable and two good_history and indicator_rendered flags:

input ENUM_GLUING_TYPE  gluing_type=simple_addition;
//--- symbol name
string   s_symbol;
int      shift_array=0;
bool     good_history=false;        //history is not prepared||history not prepared
bool     indicator_rendered=false;  // indicator is not drawn
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+

Then set up the indicator and connect the buffer color index to the chosen color:

   ArraySetAsSeries(CloseBuffer,true);
   ArraySetAsSeries(ColorCandlesColors,true);
//--- set accuracy || accuracy of the indicator values 
   IndicatorSetInteger(INDICATOR_DIGITS,0);
//--- set drawing line empty value || empty value of the drawing line 
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
//--- set labels for the line || displayed name in the DataWindow
   PlotIndexSetString(0,PLOT_LABEL,s_symbol+" Open;"+s_symbol+" High;"+s_symbol+" Low;"+s_symbol+" Close");
   IndicatorSetString(INDICATOR_SHORTNAME,"SYNT");
//--- set number of colors in color buffer || number of colors in the buffer
   PlotIndexSetInteger(0,PLOT_COLOR_INDEXES,9);
//--- set line color || set the line color
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,0,clrBlue);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,1,clrOrange);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,2,clrRed);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,3,clrGreen);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,4,clrPink);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,5,clrIndigo);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,6,clrPaleVioletRed);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,7,clrDarkViolet);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,8,clrDimGray);
//---
   return(INIT_SUCCEEDED);

Add the initialization of the timer with 3 seconds interval and the random number generator into the OnInit() function:

   PlotIndexSetInteger(0,PLOT_LINE_COLOR,7,clrDarkViolet);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,8,clrDimGray);
//---
   EventSetTimer(3);
//--- random number generator initializor
   MathSrand(GetTickCount());
//---
   return(INIT_SUCCEEDED);

It is required at least two symbols to process the splicing.

Check the number of instruments for splicing in the OnCalculate() function:

                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//--- checking the number of instruments || checking the number of instruments
   if(numder_futures_gluing<=1)
     {
      //--- create the message line
      string comm=StringFormat("For the indicator choose not less than %d symbols",numder_futures_gluing);
      //--- display the message in comment in the chart main window
      Comment(comm);
      return(0);
     }
//--- return value of prev_calculated for next call
   return(rates_total);

After you have checked the number of symbols for splicing you check whether the indicator has been already drawn. If the indicator is drawn, then you can quit the OnCalculate() :

      Comment(comm);
      return(0);
     }
   if(indicator_rendered==true) return(rates_total);
//--- return value of prev_calculated for next call
   return(rates_total);

As the "SYNT" indicator is mainly used to analyze the day bars development tendency, I consider, that there is no need to proceed recalculations in each tick. There will not be calculations of the "SYNT" indicator on each tick.

Moreover, you need to calculate the indicator only in the following cases:

  • if the indicator was launched the first time;
  • if the history was changed (for example, there were additions).
   if(indicator_rendered==true) return(rates_total);
//--- if calculations were started the first time
//--- or if we need to calculate the indicator for two or more bars (changes in history)
//--- remember, that the "0" bar - is the left-most
   if(prev_calculated==0 || rates_total>prev_calculated+1)
     {
     }
//--- return value of prev_calculated for next call
   return(rates_total);


Forced indicator buffers initialization

The indicator "SYNT" buffers are connected dynamic arrays.

When the indicator is launched the first time, buffers are initialized forcibly. Proceed with the initialization in the OnCalculate(). Why do you need to conduct it in the OnCalculate(), not in the OnInit? The explanation is in the figure below:

Fig. 11. The array initialization in the OnCalculate()

As you can see in the Fig.11, the OnCalculate() event will occur in any case, whereas the OnInit() is enabled when you launch the chart updating through the "Update" command. Therefore, the arrays initialization will be conducted in the OnCalculate():

//--- remember, that the "0" bar - is the left-most
   if(prev_calculated==0 || rates_total>prev_calculated+1)
     {
      //--- arrays initialization
      ArrayInitialize(OpenBuffer,0);
      ArrayInitialize(HighBuffer,0);
      ArrayInitialize(LowBuffer,0);
      ArrayInitialize(CloseBuffer,0);
     }
//--- return value of prev_calculated for next call
   return(rates_total);

The ArrayInitialize() function initializes the indicator buffer. In this case the initialization shows zeros.

If you try to initialize the buffer indicator by the EMPTY_VALUE , you will not be able to splice indicators on the "SYNT".


Algorithm of Simple addition

Dib. 12. Algoritmo del añadido simple

Fig. 12. Algorithm of Simple addition

 

Dates in the picture are the start and end dates of UX-9.13, UX-12.13 and UX-3.14 futures circulation. These data are presented in the table:

SymbolCirculation startsCirculations finishes
UX-9.132013.03.152013.09.16
UX-12.132013.06.172013.12.16
UX-3.142013.09.162014.03.17

 

In the Fig. 10 2013.12.25 date - is a real calendar date. The UX-3.14 symbol is still valid.

"Simple addition" splicing method will be implemented in the SimpleAddition function:

//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
//---
  }
//+------------------------------------------------------------------+
//| Simple addition                                                  |
//| Simple addition. Add in the indicator array                      |
//| sibmUP symbol                                                    |
//+------------------------------------------------------------------+
bool SimpleAddition(string simbUP,string simbDOWN,ENUM_TIMEFRAMES period,int Color)
  {
  }
//+------------------------------------------------------------------+

simbUP is the up futures, simbDOWN is the down futures, both of them are located in the "Market review" window. Color - color used to draw futures. 

The full code of the SimpleAddition() function is given below:

//+------------------------------------------------------------------+
//| Simple addition                                                  |
//| Simple addition. Add in the indicator array                      |
//| sibmUP symbol                                                    |
//+------------------------------------------------------------------+
bool SimpleAddition(string simbUP,string simbDOWN,ENUM_TIMEFRAMES period,int Color)//////
  {
   datetime expiration_time_UP;     // simbUP symbol expiration date
   datetime expiration_time_DOWN;   // simbDOWN expiration date

   expiration_time_UP=int(SymbolInfoInteger(simbUP,SYMBOL_EXPIRATION_TIME));
   if(expiration_time_UP>TimeLocal())
     {
      expiration_time_UP=TimeLocal();
     }
   if(simbDOWN!="")
     {
      expiration_time_DOWN=int(SymbolInfoInteger(simbDOWN,SYMBOL_EXPIRATION_TIME));
     }
   else
     {
      expiration_time_DOWN=int(SymbolInfoInteger(simbUP,SYMBOL_START_TIME));
     }
//--- Open, High, Low and Close prices will be copied in the rates[] array 
   MqlRates rates[];
   ArraySetAsSeries(rates,true);
   int copied=0;           //--- copied number
   copied=CopyRates(simbUP,period,expiration_time_DOWN,expiration_time_UP,rates);
   if(copied>0)
     {
      for(int j=shift_array;j<shift_array+copied;j++)
        {
         //--- write prices in buffers
         OpenBuffer[j]=rates[j-shift_array].open;
         HighBuffer[j]=rates[j-shift_array].high;
         LowBuffer[j]=rates[j-shift_array].low;
         CloseBuffer[j]=rates[j-shift_array].close;
         ColorCandlesColors[j]=Color;
        }
      shift_array=shift_array+copied;
      indicator_rendered=true;
      ChartRedraw();
     }
   else
     {
      Print("Unable to get the symbol history data",simbUP);
      indicator_rendered=false;
      return(false);
     }
//---  Simple addition end
   return(true);
  }
//+------------------------------------------------------------------+


Addition with shift algorithm


Dib. 13. Algoritmo de pegado - añadido con desplazamiento

Fig. 13. Addition with shift splicing algorithm 

Splicing in this algorithm, compared to the simple addition, begins 10 days before the symbol is closed. The "Addition with shift" splicing method is processed in the AdditionWithShift() function:

//--- Simple addition end
   return(true);
  }
//+------------------------------------------------------------------+
//| Addition With Shift                                              |
//| Addition with Shift. Add in the indicator array only             |
//| sibmUP symbol                                                    |
//+------------------------------------------------------------------+
bool AdditionWithShift(string simbUP,string simbDOWN,ENUM_TIMEFRAMES period,int Color)
  {
//--- 
   return(true);
  }
//+------------------------------------------------------------------+

The difference between the AdditionWithShift() and the SimpleAddition() functions is in two lines - you subtract 10 days from dates:

   .
   .
   .
   expiration_time_UP=int(SymbolInfoInteger(simbUP,SYMBOL_EXPIRATION_TIME))-86400*10;
   .
   .
   .
   expiration_time_DOWN=int(SymbolInfoInteger(simbDOWN,SYMBOL_EXPIRATION_TIME))-86400*10;
   .
   .
   .

Due to small difference in codes, I will not show the complete code of the AdditionWithShift() function, you can find the code in the indicator file of the article.

Despite such small difference between the AdditionWithShift() and SimpleAddition() functions, it is better if you don't splice them to make one universal function (in case of further changes in the algorithm or, for example, launches of testings).


Symbols history preloading

The CheckLoadHistory() function copies all symbol history into the auxiliary buffer tmp_rates.

If the copying process is successful the true value is assigned to the good_history flag, which means you can start drawing the indicator:

//--- Addition With Shift end
   return(true);
  }
//+------------------------------------------------------------------+
//| Request to receive all history from a trade server               |
//| Request to recieve all history from a trade server               |
//+------------------------------------------------------------------+
bool CheckLoadHistory(string symbol,ENUM_TIMEFRAMES period)
  {
   MqlRates tmp_rates[];      // the Open, High, Low and Close prices will be copied in the rates[]array 
   datetime start_time;       // start time of the instrument trades
   datetime expiration_time;  // expiration time of the instrument trade
   start_time=int(SymbolInfoInteger(symbol,SYMBOL_START_TIME));
   expiration_time=int(SymbolInfoInteger(symbol,SYMBOL_EXPIRATION_TIME));
   if(CopyRates(symbol,period,start_time,expiration_time,tmp_rates)>0)
     {
      good_history=true;
     }
   else
     {
      good_history=false;
     }
//--- 
   return(true);
  }
//+------------------------------------------------------------------+

You can copy all symbol history as futures life is very short and all history copying will not take much space.


OnTimer - the main function of the indicator

Now you have the code for two splicing methods and the code for the history load, so you can change the OnTimer() function:

//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
   if(indicator_rendered==true) return;
   if(good_history==true)
     {
      int t=0;       // color || color
      int number;
      switch(gluing_type)
        {
         case simple_addition:
            for(int n=0;n<numder_futures_gluing;n++)
              {
               //--- get the random number
               number=MathRand();
               //--- get the color index as the modulo
               t=number%(PlotIndexGetInteger(0,PLOT_COLOR_INDEXES)-1);
               SimpleAddition(SymbolName(n,true),SymbolName(n+1,true),PERIOD_D1,t);
              }
            break;
         case addition_with_shift:
            for(int n=0;n<numder_futures_gluing;n++)
              {
               //--- get random number
               number=MathRand();
               //--- get the color index as the modulo
               t=number%(PlotIndexGetInteger(0,PLOT_COLOR_INDEXES)-1);
               AdditionWithShift(SymbolName(n,true),SymbolName(n+1,true),PERIOD_D1,t);
              }
            break;
        }
     }
   else
     {
      for(int n=0;n<numder_futures_gluing;n++)
        {
         CheckLoadHistory(SymbolName(n,true),PERIOD_D1);
        }
     }
  }
//+------------------------------------------------------------------+

The indicator is constructed. You can compile it and attach to the chart. It is better to choose the closed trade symbol and set the H1 period.


Initial output of the "SYNT" indicator

After you have attached the two "SYNT" indicator templates of different splicing methods to the chart, you can compare these methods:

  Fig. 14. Two methods of futures splicing comparison


The possibility to splice indicators (standard and custom)

Custom indicators can be spliced with the OnCalculate first call and the "SYNT" indicator:

int OnCalculate (const int rates_total,      // size of the array price[]
                 const int prev_calculated,  // calculated bars during the previous call
                 const int begin,            // tangible data starting point
                 const double& price[]       // calculation array
   );

In the "Navigator" window open the list "Custom's indicators". Then open the list "Examples", choose the indicator and place it into "SYNT". In the "Parameters" tab choose "Previous indicator data" in the dropdown list. 

Here is the list with indicators which you can splice on the "SYNT" indicator, they launch on the "SYNT" without mistakes:

The indicator "SYNT" which spliced three futures with the attached Custom Moving Average indicator:

Dib. 15. Ejemplo de pegado de tres símbolos

Fig. 15. An example of three spliced symbols


Conclusion

It is easier to analyze the behaviour of older chart symbols opened within day timeframes. Although the number of the technical indicators is restricted, this method helps to trace the price behaviour on continuous futures.


Translated from Russian by MetaQuotes Ltd.
Original article: https://www.mql5.com/ru/articles/802

Attached files |
synt.mq5 (24.66 KB)
Last comments | Go to discussion (1)
Charles Stangor
Charles Stangor | 20 Mar 2018 at 13:00
So it seems that the main use for the continuous futures contract is in backtesting.  I'm not sure if this indicator will help with that.  In the backtesting settings screen I must indicate which symbol I wish to backtest. A new continuous symbol has not been created. Am I missing something?  Thanks for your work on this.
Indicator for Renko charting Indicator for Renko charting
The article describes an example of Renko charting and its implementation in MQL5 as an indicator. Modifications of this indicator distinguish it from a classic chart. It can be constructed both in the indicator window and on the main chart. Moreover, there is the ZigZag indicator. You can find a few examples of the chart implementation.
Why Is It Important to Update MetaTrader 4 to the Latest Build by August 1? Why Is It Important to Update MetaTrader 4 to the Latest Build by August 1?
From August 1, 2014, MetaTrader 4 desktop terminals older than build 600 will no longer be supported. However, many traders still work with outdated versions and are unaware of the updated platform's features. We have put a lot of effort into development and would like to move on with traders and abandon the older builds. In this article, we will describe the advantages of the new MetaTrader 4.
Building a Social Technology Startup, Part I: Tweet Your MetaTrader 5 Signals Building a Social Technology Startup, Part I: Tweet Your MetaTrader 5 Signals
Today we will learn how to link an MetaTrader 5 terminal with Twitter so that you can tweet your EAs' trading signals. We are developing a Social Decision Support System in PHP based on a RESTful web service. This idea comes from a particular conception of automatic trading called computer-assisted trading. We want the cognitive abilities of human traders to filter those trading signals which otherwise would be automatically placed on the market by the Expert Advisors.
MQL5 Cookbook: Development of a Multi-Symbol Indicator to Analyze Price Divergence MQL5 Cookbook: Development of a Multi-Symbol Indicator to Analyze Price Divergence
In this article, we will consider the development of a multi-symbol indicator to analyze price divergence in a specified period of time. The core topics have been already discussed in the previous article on the programming of multi-currency indicators "MQL5 Cookbook: Developing a Multi-Symbol Volatility Indicator in MQL5". So this time we will dwell only on those new features and functions that have been changed dramatically. If you are new to the programming of multi-currency indicators, I recommend you to first read the previous article.