2

I am new in MQL5 and I am trying to capture the values of Open, High, Low and Close of each new candle.

For now I am using a one minute TimeFRAME for each candle.

I read the documentation and have not figured out how can I do it.

My only clue was the CopyOpen() functions, but I am still stuck.

user3666197
  • 1
  • 6
  • 50
  • 92
ViniciusArruda
  • 970
  • 12
  • 27

2 Answers2

1

Let's split the task:

  1. How to read OHLC-values?
  2. How to detect (each) new candle?

A1: MQL4/MQL5 syntax reports OHLCV-values straight in Open[], High[], Low[], Close[], Volume[] time-series arrays. As a rule of thumb, these arrays are time-series, reverse-stepping indexed, so that the most recent cell ( The Current Bar ( candle ) ) always has cell-index == 0. So Open[1], High[1], Low[1], Close[1] are values for the "current instrument" ( _Symbol ), retrieved from the "current TimeFRAME" for a candle, that was already closed right before the "current Candle" has started. Complex? Well, just on the first few reads. You will get acquainted with this.

If your code does not want to rely on "current" implicit contexts, the syntax allows one to use explicit, indirect, specifications:

/* iVolume( ||| ... )
   iTime(   ||| ... )
   iClose(  ||| ... )
   iLow(    ||| ... )
   iHigh(   vvv ... )                   */

   iOpen(   aTradingSymbolNameSTRING,   // Broker specific names, "DE-30.." may surprise
            PERIOD_M1,                  // explicit reference to use M1 TimeFRAME
            1                           // a Cell-index [1] last, closed Candle
            )

A2: There is neat way how to detect a new Candle, indirectly, the same trick allows one to thus detect a moment, when the previous Candle stops evolving ( values do not change anymore ) which thus makes sense to report "already frozen" OHLCV-values to be reported anywhere else.

Remeber, the "current" OHLCV-registers-[0] are always "hot" == continuously changing throughout the time of the "current" TimeFRAME Candle duration, so one has to wait till a new Candle starts ( indirectly meaning the "now-previous" Candle [0] has ended and has thus got a reverse-stepping index "re-indexed" to become [1], a frozen one ).

For detecting a new candle it is enough to monitor changes of a system register int Bars, resp. an indirect, context aware, int iBars( ... ).

One may realise, that there are some "theoretical" Candles, that do not happen and are thus not "visible" / "accessible" in data of time-series -- whence a market was not active during such period of time and no PriceDOMAIN change has happened during such administratively-framed epoch in time -- for such situations, as there was no price-change, there was no QUOTE and thus such candle did not happen and is "missing" both in linear counting and in data-cells. The first next QUOTE arrival is thus painted right "besides" a candle, that was principally "older" than a "previous"-neighbour ( the missing candles are not depicted, so due care ought be taken in processing ). This typically happens even on major instruments near the Friday EoB/EoWk market closing times and around midnights UTC +0000 during the 24/5-cycles.

user3666197
  • 1
  • 6
  • 50
  • 92
1

In case you become too frustrated, here is a script that will export selected chart contents the second a new candle appears. Just choose the pair you want and attach this to the chart and you will get exported a .csv file on each new candle.

//+------------------------------------------------------------------+
#include <stdlib.mqh>
#include <stderror.mqh>
//+------------------------------------------------------------------+
//| Input Parameters Definition                                      |
//+------------------------------------------------------------------+
extern int    BarCount = 500;
extern string Pairs = "EURAUD,EURCAD,EURCHF,EURGBP,EURNZD,EURUSD,EURJPY,AUDCAD,AUDCHF,AUDJPY,AUDNZD,AUDUSD,GBPAUD,GBPCAD,GBPCHF,GBPJPY,GBPNZD,GBPUSD,CADCHF,CADJPY,USDCAD,USDCHF,USDJPY,NZDCAD,NZDCHF,NZDJPY,NZDUSD,CHFJPY";
extern string delimiter = ",";
//+------------------------------------------------------------------+
//| Local Parameters Definition                                      |
//+------------------------------------------------------------------+
datetime lastExport[];
string pairs[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
{
  //------------------------------------------------------------------
  Split(Pairs, pairs, ",");
  //------------------------------------------------------------------
  if (ArraySize(pairs) == 0 || StringTrimLeft(StringTrimRight(pairs[0])) == "")
  {
    Alert("Pairs are not entered correctly please check it...");
    return (0);
  }
  //------------------------------------------------------------------
  ArrayResize(lastExport, ArraySize(pairs));
  ArrayInitialize(lastExport, 0);
  //------------------------------------------------------------------
  Comment("quote exporter is active :)");
  //------------------------------------------------------------------
  return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
{
  //------------------------------------------------------------------
  Comment("");
  //------------------------------------------------------------------
  return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
{
  //------------------------------------------------------------------
  if (ArraySize(pairs) == 0 || StringTrimLeft(StringTrimRight(pairs[0])) == "") return (0);
  //------------------------------------------------------------------
  BarCount = MathMin(Bars, BarCount);
  //------------------------------------------------------------------
  for (int j = 0; j < ArraySize(pairs); j++)
  {
    if (lastExport[j] == Time[0]) continue;
    lastExport[j] = Time[0];
    if (StringTrimLeft(StringTrimRight(pairs[j])) == "") continue;
    if (MarketInfo(pairs[j], MODE_BID) == 0) { Alert("symbol " + pairs[j] + " is not loaded!!!"); continue; }
    //------------------------------------------------------------------
    string file = pairs[j] + "_" + GetTimeFrameName(0) + ".csv";
    int log = FileOpen(file, FILE_CSV|FILE_WRITE, "~");
    if (log < 0) { Alert("can not create/overwrite csv file " + file + "!!!"); continue; }
    string buffer;
    buffer = "Date"+delimiter+"Time"+delimiter+"Open"+delimiter+"High"+delimiter+"Low"+delimiter+"Close"+delimiter+"Volume";
    FileWrite(log, buffer);
    int digits = MarketInfo(pairs[j], MODE_DIGITS);
    for (int i = BarCount; i >= 1; i--)
    {
      buffer = TimeToStr(Time[i], TIME_DATE)+delimiter+TimeToStr(Time[i], TIME_MINUTES)+delimiter+DoubleToStr(iOpen(pairs[j], 0, i), digits)+delimiter+DoubleToStr(iHigh(pairs[j], 0, i), digits)+delimiter+DoubleToStr(iLow(pairs[j], 0, i), digits)+delimiter+DoubleToStr(iClose(pairs[j], 0, i), digits)+delimiter+DoubleToStr(iVolume(pairs[j], 0, i), 0);
      FileWrite(log, buffer);
    }

    buffer = "0"+delimiter+"0"+delimiter+"0"+delimiter+"0"+delimiter+"0"+delimiter+"0"+delimiter+"0";
    FileWrite(log, buffer);
    FileClose(log);
  }
  //------------------------------------------------------------------
  return(0);
}
//+------------------------------------------------------------------+
string GetTimeFrameName(int TimeFrame)
{
  switch (TimeFrame)
  {
    case PERIOD_M1: return("M1");
    case PERIOD_M5: return("M5");
    case PERIOD_M15: return("M15");
    case PERIOD_M30: return("M30");
    case PERIOD_H1: return("H1");
    case PERIOD_H4: return("H4");
    case PERIOD_D1: return("D1");
    case PERIOD_W1: return("W1");
    case PERIOD_MN1: return("MN1");
    case 0: return(GetTimeFrameName(Period()));
  }
}
//+------------------------------------------------------------------+
void Split(string buffer, string &splitted[], string separator)
{
  string value = "";
  int index = 0;
  ArrayResize(splitted, 0);
  if (StringSubstr(buffer, StringLen(buffer) - 1) != separator) buffer = buffer + separator;
  for (int i = 0; i < StringLen(buffer); i++)
    if (StringSubstr(buffer, i, 1) == separator)

    {
      ArrayResize(splitted, index + 1);
      splitted[index] = value;
      index ++;
      value = "";
    }
    else
      value = value + StringSubstr(buffer, i, 1);
}
//+------------------------------------------------------------------+
user3666197
  • 1
  • 6
  • 50
  • 92
ajsp
  • 2,512
  • 22
  • 34
  • 1
    It should be fair to note, the proposed **code is 1) not `MQL5`** ( it uses ***old*-`MQL4`-syntax** v/s `OnInit()`, `OnDeinit()`, `OnStart()` ) and is **2) `fileIO` very inefficient** - both **on low-level** ( does not use any form of smart-buffering so as to systematically avoid a penalty of about ~ 15 [ms] per loop per HDD-I/O access time ( better to use about a 64k-smart buffer and write in bigger chunks ( at least a way >> `N*FileSystemSectorSIZE` )) - and **on high-level** ( it re-writes **all bar-depth on each loop** - may have +1.000.000 bars, so everybody ought **smell the issue** ) – user3666197 Jun 04 '16 at 17:19
  • Thanks to **`MQL5` updated abilities**, one may profile / micro-benchmark the critical code-sections down to a resolution of microseconds **`[us]`** using `ulong aStringAssemblyUSEC = GetMicrosecondCount();` and `ulong aFileIoAccessPlusWriteUSEC = GetMicrosecondCount();` to have quantitative data available from a in-vivo live-test. Claiming that SSD media will "*avoid*" the issue is wrong, as the wear-&-tear will devastate the media re-FLASH-ing cycles without any fair benefit ( use-less-ly ) -- a proper algorithmisation is due in SSD case either, undoubtfully. – user3666197 Jun 04 '16 at 17:29
  • @user3666197 Thanks, it's just an old script I had lying around, I don't actually use metatrader anymore, moved on to pastures new. – ajsp Jun 04 '16 at 19:56