Metatrader 4 Indicator with Data Series from File

If you use Metatrader platform for price behavior analysis, especially if you tend to rely on fundamentals, quite often you may want to see some external data along the price on a chart. Let’s say, for a example, you want to examine possible correlation between exchange rate of a currency pair and its respected interest rate difference, or use this data as a confirmation for your entries in some way. This article shows you step by step how to create an indicator displaying time series data from an external file using MQL4 language.

Before we start, a few words on possible alternative solution. Metatrader 4 allows you to import/edit time series from external file via its so called History Center. In order to do that your data need to be in a specific format and there are some other issues. It is possible also to get external data from a database or other application via some interface layer written in a general purpose programming language. Although the latter method may be preferable in some cases, here we are going to take a relatively simple approach using MQL4 for the task.

First, we need data files. We are going to have a separate file for each currency interest rate history. Interest rate history for major currencies can be found on this page. Select a table on the page with a mouse and copy it to a text file. Say, we want to analyze EURUSD pair, then you’ll need to create two files named “eur.txt” and “usd.txt”. As a result, your file will contain tab-delimited text, with date and rate on each line. Put the files into the following folder of your Metatrader installation: experts\files\, so Metatrader can access them.

The indicator will display three lines, one for base currency, one for a terms currency and third one for the difference between two. Once we start our indicator we want it to read the appropriate files. For each currency it will store both date and rate series data in a pair of global arrays, so that the code in the start() function could access those values later with each tick. Thus we get the following code for init() function:

int init()
{
   //---- indicator lines
   SetIndexStyle(0, DRAW_LINE, 0, 1, Green);
   SetIndexBuffer(0, ExtMapBuffer1);
   SetIndexStyle(1, DRAW_LINE, 0, 1, Red);
   SetIndexBuffer(1, ExtMapBuffer2);
   SetIndexStyle(2, DRAW_LINE, 0, 3, Blue);
   SetIndexBuffer(2, ExtMapBuffer3);

   // get current currency symbols
   string symbol = Symbol();
   string baseCurrency = StringSubstr(symbol, 0, 3);
   string termsCurrency = StringSubstr(symbol, 3);

   //---- read file
   if (ReadSeriesFromFile(StringConcatenate(baseCurrency, ".", FileExtention), 
       Delimiter, baseDate, baseRate) < 0)
   {
      return(Terminate());
   }

   if (ReadSeriesFromFile(StringConcatenate(termsCurrency, ".", FileExtention), 
       Delimiter, termsDate, termsRate) < 0)
   {
      return(Terminate());
   }

   return(0);
}

If related data file is not found function Terminate() will attempt to divide by zero, thus preventing the indicator from executing start() function on every tick. Now let’s have a look at ReadSeriesFromFile() function.

int ReadSeriesFromFile(string filename, int delimiter, 
                       datetime &keys[], double &values[])
{
   int h = FileOpen(filename, FILE_CSV || FILE_READ, delimiter);
   if (h < 1)
   {
      Print("File ", filename, 
            " not found, the last error is ", GetLastError());
      return(-1);
   }
   Print("File ", filename, " open.");

   int i = 0;
   while (!FileIsEnding(h))
   {
      string s = StringTrimRight(FileReadString(h));
      if (s == "")
      {
         continue;   // ignore blank lines
      }
      datetime date = StrToTime(s);

      // value = FileReadNumber(h);
      s = FileReadString(h);
      double value = StrToDouble(s);

      // Print(TimeToStr(date, TIME_DATE), ": ", value, "%");

      ArrayResize(keys, i + 1);
      keys[i] = date;
      ArrayResize(values, i + 1);
      values[i] = value;
      i++;
   }

   FileClose(h);
   SortDictionary(keys, values);

   return(i);
}

A few comments.

  • We pass two arrays by reference so that the data the function populated them with were available outside the function.
  • Next, we use standard MQL4 function FileOpen() to open file in \experts\files\ folder where we put our files.
  • We read the file line by line till the end, converting each line into date-rate pair. You may notice that FileReadNumber() is commented out. It didn’t work for me despite the MQL4 documentation said it should, so I had to read the value as a string and then convert it to a number.
  • Each date and rate value from the pair is saved to an appropriate array.
  • When we’re done with the file we want to sort our series arrays as we are not sure that the entries in a file are successive or in the right order. Now this is not too straightforward, as we need to reorder items in both arrays uniformly based on values of one of them.

Let’s see what these arrays are. Essentially, what we need here is a list of key-value pairs, which is called dictionary or hash-table in most programming languages. The dates represent keys and the rates represent values of the dictionary. Then if we wanted to get a rate for a specific date we would just refer to our dictionary passing in a key, something like value = dictionary[key]. Here comes the problem, MQL4 does not support dictionaries or hash-tables, this is why we use a pair of arrays. For its own standard time series MQL4 uses a set of connected “series arrays”, which are sorted and indexed automatically. And here’s how we are going to do the same programmatically:

void SortDictionary(datetime &keys[], double &values[], 
                    int sortDirection = MODE_ASCEND)
{
   datetime keyCopy[];
   double valueCopy[];
   ArrayCopy(keyCopy, keys);
   ArrayCopy(valueCopy, values);
   ArraySort(keys, WHOLE_ARRAY, 0, sortDirection);
   for (int i = 0; i < MathMin(ArraySize(keys), ArraySize(values)); i++)
   {
      //values[i] = valueCopy[ArrayBsearch(keyCopy, keys[i])];
      values[ArrayBsearch(keys, keyCopy[i])] = valueCopy[i];
   }
}

Notice that the commented out line values[i] = valueCopy[ArrayBsearch(keyCopy, keys[i])]; reads more naturally, but can’t be used as ArrayBsearch() function requires array to be sorted. Now our own “series arrays” are ready to be used. The code for start() function is rather typical and straightforward. For each bar, no matter what timeframe is selected, it populates respected indicator line arrays.

int start()
{
   int Counted_bars = IndicatorCounted();
   int i;

   i = Bars - Counted_bars - 1;
   while(i >= 0)
   {
      int iBase = ArrayBsearchCorrect(baseDate, Time[i]);
      int iTerms = ArrayBsearchCorrect(termsDate, Time[i]);

      if (iBase >= 0)
      {
         ExtMapBuffer1[i] = baseRate[iBase];
      }
      if (iTerms >= 0)
      {
         ExtMapBuffer2[i] = termsRate[iTerms];
      }
      if (iBase >= 0 && iTerms >= 0)
      {
         ExtMapBuffer3[i] = baseRate[iBase] - termsRate[iTerms];
      }

      i--;
   }

   return(0);
}

Why do we need all those “IFs”? Say, our EUR interest rate data start with year 1999, when euro was introduced. What should our indicator display for year 1998? Nothing, no line. Here I’m using a function ArrayBsearchCorrect(), which is what standard MQL4 function ArrayBsearch() should be, in my opinion. Unlike ArrayBsearch(), it will return -1, thus letting us know that we are trying to get a rate for a date earlier than the data we have.

int ArrayBsearchCorrect(datetime array[], datetime value, 
                        int count = WHOLE_ARRAY, int start = 0, 
                        int direction = MODE_ASCEND)
{
   int i = ArrayBsearch(array, value, count, start, direction);
   if (value < array[i])
   {
      i = -1;
   }
   return (i);
}

Our indicator is ready now. Here we go:

Interest rates in Metatrader 4

Interest rates in Metatrader 4

From the MQL4 code of the indicator you may notice:

  • Indicator will try to pick up the appropriate files depending on the instrument chosen.
  • Indicator will work with any timeframe
  • Time series data in your files may extend into the future, future values will be displayed as the time goes on.

The full code of the indicator: InterestRates.mq4

Leave a Reply