0

I just finished building my algorithm but now I need to export data from the MetaTrader terminal every minute to a CSV file that my algorithm can read and run predictions on.

There are multiple ways online to export MetaTrader data to a CSV file in real-time but I can't find anything that will let me export even just the open price of the new candle as soon as it forms.

I'd like to export the last 10 OHLC candles on a minute timeframe and the open price of the current 11th candle. The open price of the current candle that's STILL forming and hasn't closed yet. I just need the open price for this as soon as the candle starts.

Any ideas? I'm stuck here

UPDATE

I added the code.
This current code is a MetaTrader script, that fetches the past 10 OHLCV candles and the 11th candle as I mentioned.
However, I have three problems with this script:

  1. It does not allow me to overwrite the existing csv.
  2. It does not run realtime and update constantly.
  3. The 11th candle is not the latest (the candle still in formation).

Any help?

//+------------------------------------------------------------------+
#include <stdlib.mqh>
#include <stderror.mqh>
//+------------------------------------------------------------------+
//| Input Parameters Definition                                      |
//+------------------------------------------------------------------+
extern int    BarCount = 11;
extern string Pairs = "EURUSD";
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);
    }
}
  //------------------------------------------------------------------
  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
NOIX
  • 23
  • 7
  • Please explain which bit you are stuck on with a [mcve](https://stackoverflow.com/help/mcve) of what you have tried. Is the problem with writing to csv or getting the last 10 OHLC variables? – rgunning Jun 29 '17 at 13:53
  • The [example](https://docs.mql4.com/files/filewrite) in the MQL4 docs does a very similar job to what you are asking. – rgunning Jun 29 '17 at 14:02
  • Hi all, please checked my updated code. I explained the exact problems and what Im asking to solve if possible. Thanks! – NOIX Jun 30 '17 at 01:41
  • Your code has major failure inside the `Split(){...}` as it would never assign there. You seem to have performed zero diagnostics with `Print()` or `Comment()` so as to debug your code before asking. **This is not a welcome practice on StackOverflow**, as a due amount of one's own preliminary research & debugging efforts are mandatory part of the Asker's responsibility, before **shouting on the Community sponsoring members "Hi ... check my code ... Any ideas?" is considered impolite**, if not rude. Anyway, welcome to this Great Community of Knowledge and become an active contributing member. – user3666197 Jul 11 '17 at 11:36

1 Answers1

0

A long story to go. A quick-fix of a conceptually wrong idea in an inappropriate algorithmisation listed with remarks below.

Never, indeed NEVER, do anything like this as a CustomIndicator:

Why? After some internal re-designs MetaQuote, Inc., has conformed, that all, yes ALL CustomIndicator code-execution units, that operate inside the MT4-platform, SHARE one SINGLE solo THREAD.

Never attempt to place any kind of slow ( high-latency / low-throughput ) activity like fileIO into CustomIndicator. NEVER. 10~15 ms for fileIO are killing the Real-Time-ness as TLP-durations are well under 20 ms for Majors in prime-time ( ref. picture ).

enter image description here

( For more details, you may check other posts on ).

The less any BLOCKING one. Alert() being such example.


The best thing for RealTime?

Better use a Script-type of MQL4 code, not a CustomIndicator.

Use a process-to-process low-latency messaging like or .

I started to use ZeroMQ wrapper for MQL4 many years ago for moving aDataSEGMENT[] into an external AI/ML-predictor engine and to return predictions back, having a net-turn-around-time well under 80 ms, incl. the AI/ML-prediction computing.


This code if less wrong:

//+------------------------------------------------------------------+
#include <stdlib.mqh>
#include <stderror.mqh>
//+------------------------------------------------------------------+
extern int      BarCount  =  11;
extern string   Pairs     =  "EURUSD";
extern string   delimiter =  ",";
       datetime lastExport[];
       string   fileNAME[];                                         // USE INSTEAD OF REPETITIVE RE-ASSIGNMENTS
       string   pairs[];
//+------------------------------------------------------------------+
int init() {
    //--------------------------------------------------------------
    Split( Pairs, pairs, "," );                                     // REF. BELOW FOR A PROPER APPROACH
    //--------------------------------------------------------------
    if (   0 == ArraySize( pairs )
       || "" == StringTrimLeft( StringTrimRight( pairs[0] ) )
          ){    Alert( "WARN: Pairs are not entered correctly please check it..." ); // !BLOCKS!
                return( 0 );
    }
    //--------------------------------------------------------------
    ArrayResize(     lastExport, ArraySize( pairs ) );
    ArrayInitialize( lastExport, 0 );
    ArrayResize(     fileNAME,   ArraySize( pairs ) );              // POPULATE
    for ( int j = 0;         j < ArraySize( pairs ); j++ ) fileNAME = StringFormat( "%s_M1.CSV", pairs[j] );
    //--------------------------------------------------------------
    Comment( "INF: Script started. A quote exporter is active :)" );
    //--------------------------------------------------------------
    return( 0 );
}
//+------------------------------------------------------------------+
int deinit() {                                                      // USE OnDeinit(){...} SYNTAX WITH REASON PARAMETER
    //--------------------------------------------------------------
    Comment( "INF: Script will terminate." );
    //--------------------------------------------------------------
    return( 0 );
}
//+------------------------------------------------------------------+
int start() {
    //--------------------------------------------------------------
    if (  0  == ArraySize( pairs )
       || "" == StringTrimLeft( StringTrimRight( pairs[0] ) )
          ) return( 0 );
    //--------------------------------------------------------------
    for ( int j  = 0;
              j <  MathMin( ArraySize( pairs ), CHART_MAX - 1 );
              j++ ) //--------------------------------------------------iterateOverAllListedINSTRUMENTs:
        ChartOpen( pairs[j], PERIOD_M1 );                            // enforce MT4 DataPumps to pre-load & collect QUOTEs
    //------------------------------------------------------------------
    while ( True ) { //-------------------------------------------------iterateINFINITELY: 
            ulong loopSTART = GetMicrosecondCount();
            for ( int j = 0; j < ArraySize( pairs ); j++ ) { //---------iterateOverAllListedINSTRUMENTs:
                  if (            "" == StringTrimLeft( StringTrimRight( pairs[j] ) ) )                                        continue;   // .LOOP-NEXT INSTRUMENT
                  else                  RefreshRates();                                                                                    // .REFRESH   MT4 DataPumps
                  if (             0 == MarketInfo( pairs[j], MODE_BID ) ) { Alert( "symbol " + pairs[j] + " is not loaded" ); continue; } // .LOOP-NEXT INSTRUMENT         // !BLOCKS!
                  if ( lastExport[j] ==      iTime( pairs[j], PERIOD_CURRENT, 0 ) )                                            continue;   // .LOOP-NEXT INSTRUMENT
                  else lastExport[j]  =      iTime( pairs[j], PERIOD_CURRENT, 0 );
                  int         digits  = MarketInfo( pairs[j], MODE_DIGITS );
                  //----------------------------------------------------
                  int    logFH   = FileOpen(     fileNAME[j], FILE_CSV|FILE_WRITE, delimiter );
                  if (   logFH  == INVALID_HANDLE ) { Alert( StringFormat( "INF: Can not create / overwrite csv file(%s)! Errno(%d)", fileNAME[j], GetLastError() ) ); continue; } // !BLOCKS!
                  //----------------------------------------------------fileIO RTO:
                                                    FileWrite( logFH, "Date", "Time", "Open", "High", "Low", "Close", "Volume" );
                  for ( int i    = MathMin( BarCount,                                 iBars( pairs[j], PERIOD_CURRENT ) ); i >= 1; i-- )
                                                    FileWrite( logFH,  TimeToStr(     iTime( pairs[j], PERIOD_CURRENT, i ), TIME_DATE    ),
                                                                       TimeToStr(     iTime( pairs[j], PERIOD_CURRENT, i ), TIME_MINUTES ),
                                                                       DoubleToStr(   iOpen( pairs[j], PERIOD_CURRENT, i ), digits ),
                                                                       DoubleToStr(   iHigh( pairs[j], PERIOD_CURRENT, i ), digits ),
                                                                       DoubleToStr(    iLow( pairs[j], PERIOD_CURRENT, i ), digits ),
                                                                       DoubleToStr(  iClose( pairs[j], PERIOD_CURRENT, i ), digits ),
                                                                       DoubleToStr( iVolume( pairs[j], PERIOD_CURRENT, i ), 0      )
                                                                       );
                  //----------------------------------------------------fileIO DONE
                                                    FileClose( logFH );// @ a cost ~ 15-18 [ms]
            }
            //----------------------------------------------------------loopIO DONE
            Comment( StringFormat( "INF: Last loopIO-TAT took %d [us]. Will sleep past aNewBarEVENT( M1 )... ~ %s ( + %d [s] )",
                                    GetMicrosecondCount()-loopSTART,
                                    TimeToStr(      TimeLocal(), TIME_MINUTES ),
                                    ( 60 - MathMod( TimeLocal(), 60 ) )
                                    )
                     );
            Sleep( 250 + 1000 * ( 60 - MathMod( TimeLocal(), 60 ) ) );
            //----------------------------------------------------------loopWAIT past aNewBarEVENT
    }
    //------------------------------------------------------------------
    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          // a case, when (string) buffer[i] is actually a next (string) separator
                  || StringLen(    buffer )       == i                  // a case, when (string) buffer does not end with   a (string) separator
                     ){ //----------------------------------------------// ONCE A MANUAL FIX ENABLED TO PARSE A SINGLE-INSTRUMENT (string) buffer:
                     ArrayResize( splitted, index + 1 );
                     splitted[index] = StringTrimLeft( StringTrimRight( value ) );
                     index++;
                     value = "";
               }
               else
                     value = value + StringSubstr( buffer, i, 1 );

     /* **************************************************************** WORTH READING THE DOCUMENTATION:
     USING A BUILT-IN FUNCTION WOULD BE MUCH SIMPLER AND SAFER:
     >          
     >      int  StringSplit(  const string   string_value,             // A string to search in
     >                         const ushort   separator,                // A separator using which substrings will be searched
     >                         string        &result[]                  // An array passed by reference to get the found substrings
     >                         );

     int SplitINSTRUMENTs( string buffer, string &splitted[], string separator ){
         return( StringSplit(     buffer,
                                  StringGetCharacter( separator ),
                                  splitted
                                  )
                 ); // -------------------------------------------------WOULD LOVELY FIX THE WHOLE CIRCUS
     }
     */
}
//+------------------------------------------------------------------+
halfer
  • 19,824
  • 17
  • 99
  • 186
user3666197
  • 1
  • 6
  • 50
  • 92