0

我刚刚完成了算法的构建,但现在我需要每分钟将数据从 MetaTrader 终端导出到我的算法可以读取和运行预测的 CSV 文件。

有多种在线方式可以将 MetaTrader 数据实时导出到 CSV 文件,但我找不到任何可以让我导出的方法,甚至只是新蜡烛的开盘价。

我想导出一分钟时间范围内的最后 10 支 OHLC 蜡烛以及当前第 11 支蜡烛的开盘价。当前仍在形成且尚未收盘的蜡烛的开盘价。我只需要蜡烛开始时的开盘价。

有任何想法吗?我被困在这里

更新

我添加了代码。
当前代码是一个 MetaTrader脚本,它获取过去 10 根 OHLCV 蜡烛和我提到的第 11 根蜡烛。
但是,我对这个脚本有三个问题:

  1. 它不允许我覆盖现有的 csv。
  2. 它不会实时运行并不断更新。
  3. 第 11 根蜡烛不是最新的(蜡烛仍在形成中)。

有什么帮助吗?

//+------------------------------------------------------------------+
#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);
}
//+------------------------------------------------------------------+
4

1 回答 1

0

说来话长。在下面列出的不适当算法中快速修复概念上的错误想法。

从来没有,实际上从来没有,做这样的事情CustomIndicator

为什么?在 MetaQuote, Inc. 进行了一些内部重新设计之后,所有在 MT4 平台内运行的所有 CustomIndicator代码执行单元都符合这一要求,共享一个单独线程。

切勿尝试将任何类型的缓慢(高延迟/低吞吐量)活动(如 fileIO)放入CustomIndicator. 绝不。fileIO 的 10~15 毫秒正在扼杀实时性,因为黄金时段的专业的 TLP 持续时间远低于 20 毫秒(参考图片)。

在此处输入图像描述

其他帖子)。

任何阻塞的越少。Alert()就是这样的例子。


RealTime 的最佳选择是什么?

最好使用Script- 类型的 MQL4 代码,而不是CustomIndicator.

使用进程到进程的低延迟消息传递,例如

多年前,我开始为 MQL4 使用 ZeroMQ 包装器,用于移动aDataSEGMENT[]到外部 AI/ML 预测引擎并返回预测,净周转时间远低于 80 毫秒,包括。AI / ML预测计算。


如果错误较少,则此代码:

//+------------------------------------------------------------------+
#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
     }
     */
}
//+------------------------------------------------------------------+
于 2017-06-30T23:19:31.450 回答