mql5言語の特徴、微妙なニュアンスとテクニック - ページ 30

 

全く理解できない...。

インジケータで標準的なAOのハンドルを作成するが、タイムフレームを設定する。AOから現在のタイムフレームと一致しないデータを受信した場合、 ...エラー4806が表示されます。

質問:現在の指標と一致しない時間枠を持つ標準的な指標からデータを取得する正しい方法は何ですか?

//+------------------------------------------------------------------+
//|                                                      iMTF_AO.mq5 |
//|              Copyright 2017, Artem A. Trishkin, Skype artmedia70 |
//|                       https://login.mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, Artem A. Trishkin, Skype artmedia70"
#property link      "https://login.mql5.com/ru/users/artmedia70"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1
//--- plot Label1
#property  indicator_label1  "AO"
#property  indicator_type1   DRAW_LINE
#property  indicator_color1  clrRed
#property  indicator_style1  STYLE_SOLID
#property  indicator_width1  1
//--- input parameters
sinput   ENUM_TIMEFRAMES   PeriodForWork  =  PERIOD_H4;  // Таймфрейм, с которого берём данные AO
//--- indicator buffers
double         Buffer[];
int   handle, error=ERR_SUCCESS;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,Buffer,INDICATOR_DATA);
   IndicatorSetInteger(INDICATOR_DIGITS,Digits());
   handle=iAO(NULL,PeriodForWork);
   if(handle==INVALID_HANDLE) return(INIT_FAILED);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
   ArraySetAsSeries(Buffer,true);
   if(rates_total<1) return(0);
   int limit=rates_total-prev_calculated;
   if(limit>1) {
      limit=rates_total-1;
      }
   //---
   static string txt="";
   for(int i=limit; i>=0; i--) {
      Buffer[i]=AO(i);
      if(i<11 && i>0) {
         string ao=(Buffer[i]==EMPTY_VALUE?"EMPTY_VALUE":DoubleToString(AO(i),Digits()));
         txt+="\nAO("+(string)i+")="+ao;
         }
      }
   Comment("handle AO: ",handle,", TIMEFRAME AO: ",GetNameTF(PeriodForWork),", error: ",error,"\n-----------",txt,"\n-----------");
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
double AO(int shift){
   double array[1];
   error=ERR_SUCCESS;
   ResetLastError();
   if(CopyBuffer(handle,0,shift,1,array)==1) return(array[0]);
   else error=GetLastError();
   return(EMPTY_VALUE);
}
//+------------------------------------------------------------------+
string GetNameTF(int timeframe=PERIOD_CURRENT) {
   if(timeframe==PERIOD_CURRENT) timeframe=Period();
   switch(timeframe) {
      //--- MQL4
      case 1: return("M1");
      case 5: return("M5");
      case 15: return("M15");
      case 30: return("M30");
      case 60: return("H1");
      case 240: return("H4");
      case 1440: return("D1");
      case 10080: return("W1");
      case 43200: return("MN");
      //--- MQL5
      case 2: return("M2");
      case 3: return("M3");
      case 4: return("M4");      
      case 6: return("M6");
      case 10: return("M10");
      case 12: return("M12");
      case 16385: return("H1");
      case 16386: return("H2");
      case 16387: return("H3");
      case 16388: return("H4");
      case 16390: return("H6");
      case 16392: return("H8");
      case 16396: return("H12");
      case 16408: return("D1");
      case 32769: return("W1");
      case 49153: return("MN");      
      default: return("UnknownPeriod");
   }
}
//+------------------------------------------------------------------+
ファイル:
iMTF_AO.mq5  9 kb
 
アルチョム・トリシキン

全く理解できない...。

インジケータで標準的なAOのハンドルを作成しますが、タイムフレームを設定します。AOから現在のタイムフレームと一致しないデータを受信した場合、 ...エラー4806が表示されます。

質問ですが、現在とタイムフレームが一致しない標準的な指標からデータを取得する正しい方法は何でしょうか?


INDICATORの値の取得について。

トレーディング、自動売買システム、ストラテジーテストに関するフォーラム

インディケータで他のインディケータからデータを取得する方法

ウラジミール・カルプトフ, 2016.12.27 08:41

MQL5のインジケーターでは、インデックス「0」のバーがデフォルトでチャート上のLEFTバーになることを念頭に置き、他の2つのインジケーター、MAとAlligatorからインジケーターにデータを取得してみましょう(この例は、インジケーター「IndicatorFromIndicators.mql5内に あります

インデックスが「0」「1」「2」のバーでMAとAlligatorからデータを受信してみましょう。

  {
//---
   Comment("Проверка: time[0]=",time[0],"\n",
           "rates_total-1: ",rates_total,"\n",
           "BarsCalculated(iMA): ",BarsCalculated(handle_iMA),"\n",
           "BarsCalculated(iAlligator): ",BarsCalculated(handle_iAlligator),"\n",
           "MA[",0,"]=",StringFormat("%."+IntegerToString(Digits()+1)+"f",iMAGet(0)),"\n",
           "MA[",1,"]=",StringFormat("%."+IntegerToString(Digits()+1)+"f",iMAGet(1)),"\n",
           "MA[",2,"]=",StringFormat("%."+IntegerToString(Digits()+1)+"f",iMAGet(2)),"\n",
           "Jaws[",0,"]=",StringFormat("%."+IntegerToString(Digits())+"f",iAlligatorGet(GATORJAW_LINE,0)),"\n",
           "Jaws[",1,"]=",StringFormat("%."+IntegerToString(Digits())+"f",iAlligatorGet(GATORJAW_LINE,1)),"\n",
           "Jaws[",2,"]=",StringFormat("%."+IntegerToString(Digits())+"f",iAlligatorGet(GATORJAW_LINE,2)));
//--- return value of prev_calculated for next call
   return(rates_total);
  }

テスト用インジケータIndicatorFromIndicators.mql5」をチャートに取り付け、十字線をRIGHTESTバー、つまりゼロバーでないところにセットして みましょう。このような感じです。

インジケータ(IndicatorFromIndicators)

十字線は右端のバー、つまりインデックス "0" のバーには設定されていませんが、CopyBuffer を 使用する場合、CopyBuffer は現在から過去にデータをコピーすることに注意する必要があります。


CopyBuffer: コピーされるデータ要素(buffer_numをインデックスとする指標バッファ)は、開始位置から現在から過去に向かってカウントされます。つまり、開始位置0は現在のバー(現在のバーの指標値)を意味します。


つまり、MQL5というインジケータでは、CopyBufferという操作を使う場合、配列を反転させて(ArraySetAsSeries)、チャートの一番右のバーがインジケータバッファのインデックス「0」に対応するようにしなければなりません(現在、「iMTF_AO.mq5」の例では、チャートの一番右のバーがrates_total-1に相当します)。

 
ウラジーミル・カルプトフ


INDICATORでのINDICATOR値の取得について。


CopyBuffer: コピーされたデータ(buffer_numをインデックスとする指標バッファ)の要素は、開始位置から現在から過去に向かってカウントされる、つまり、開始位置が0に等しい場合は現在のバー(現在のバーの指標値)を意味する。


つまり、MQL5のインジケーターで、CopyBufferという操作を使う場合、配列を反転させて(ArraySetAsSeries)、チャートの一番右のバーがインジケーターバッファーのインデックス「0」に対応するようにしなければなりません(現在、例「iMTF_AO.mq5」では、チャートの一番右のバーがrates_total-1に相当します)。

バーが1本しか 出ない。そして、「ネイティブ」タイムフレーム上のインジケーターは、データを正常に表示します。非ネイティブ」-空白の値について。経験的に、AOからデータを受け取る時間枠の履歴がすべて読み込まれるまでは、空の値が返されることを突き止めました。

//+------------------------------------------------------------------+
//|                                                      iMTF_AO.mq5 |
//|              Copyright 2017, Artem A. Trishkin, Skype artmedia70 |
//|                       https://login.mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, Artem A. Trishkin, Skype artmedia70"
#property link      "https://login.mql5.com/ru/users/artmedia70"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1
//--- plot Label1
#property  indicator_label1  "AO"
#property  indicator_type1   DRAW_LINE
#property  indicator_color1  clrRed
#property  indicator_style1  STYLE_SOLID
#property  indicator_width1  1
//--- input parameters
sinput   ENUM_TIMEFRAMES   PeriodForWork  =  PERIOD_H4;  // Таймфрейм, с которого берём данные AO
//--- indicator buffers
double         Buffer[];
int   handle, error=ERR_SUCCESS;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,Buffer,INDICATOR_DATA);
   IndicatorSetInteger(INDICATOR_DIGITS,Digits());
   handle=iAO(NULL,PeriodForWork);
   if(handle==INVALID_HANDLE) return(INIT_FAILED);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
   ArraySetAsSeries(Buffer,true);
   int bars=Bars(NULL,PeriodForWork);
   datetime time_limit=GetTime(Symbol(),PeriodForWork,bars-1);
   int limit_p=GetBarShift(Symbol(),Period(),time_limit);
   if(rates_total<1) return(0);
   int limit=(PeriodForWork==Period()?rates_total-prev_calculated:limit_p);
   if(limit>1) {
      limit=rates_total-1;
      }
   //---
   static string txt="";
   for(int i=limit; i>=0; i--) {
      Buffer[i]=AO(i);
      if(i<6 && i>0) {
         string ao=(Buffer[i]==EMPTY_VALUE?"EMPTY_VALUE":DoubleToString(AO(i),Digits()));
         txt+="\nAO("+(string)i+")="+ao;
         }
      }
   Comment("handle AO: ",handle,", TIMEFRAME AO: ",GetNameTF(PeriodForWork),", error: ",error,"\n-----------",(error>0?"\nLoading history":txt),
           "\n-----------",
           "\nAO(1)=",DoubleToString(AO(1),Digits()),
           "\nAO(",limit_p,")=",DoubleToString(AO(limit_p),Digits())
          );
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
double AO(int shift){
   double array[];
   ArrayResize(array,1);
   ArrayInitialize(array,EMPTY_VALUE);
   error=ERR_SUCCESS;
   ResetLastError();
   if(CopyBuffer(handle,0,shift,1,array)==1) {
      ArraySetAsSeries(array,false);
      return(array[0]);
      }
   else error=GetLastError();
   return(EMPTY_VALUE);
}
//+------------------------------------------------------------------+
datetime GetTime(const string symbol_name, const ENUM_TIMEFRAMES timeframe, const int shift) {
   datetime array[1];
   ResetLastError();
   if(CopyTime(symbol_name,timeframe,shift,1,array)==1) return(array[0]);
   Print(__FUNCTION__," > Ошибка получения времени бара ",shift,": ",GetLastError());
   return(0);
}
//+------------------------------------------------------------------+
int GetBarShift(const string symbol_name, const ENUM_TIMEFRAMES timeframe, const datetime time) {
   int res=WRONG_VALUE;
   datetime last_bar;
   if(SeriesInfoInteger(symbol_name,timeframe,SERIES_LASTBAR_DATE,last_bar)) {
      if(time>last_bar) res=0;
      else {
         const int shift=Bars(symbol_name,timeframe,time,last_bar);
         if(shift>0) res=shift-1;
         }
      }
   return(res);
}
//+------------------------------------------------------------------+
string GetNameTF(int timeframe=PERIOD_CURRENT) {
   if(timeframe==PERIOD_CURRENT) timeframe=Period();
   switch(timeframe) {
      //--- MQL4
      case 1: return("M1");
      case 5: return("M5");
      case 15: return("M15");
      case 30: return("M30");
      case 60: return("H1");
      case 240: return("H4");
      case 1440: return("D1");
      case 10080: return("W1");
      case 43200: return("MN");
      //--- MQL5
      case 2: return("M2");
      case 3: return("M3");
      case 4: return("M4");      
      case 6: return("M6");
      case 10: return("M10");
      case 12: return("M12");
      case 16385: return("H1");
      case 16386: return("H2");
      case 16387: return("H3");
      case 16388: return("H4");
      case 16390: return("H6");
      case 16392: return("H8");
      case 16396: return("H12");
      case 16408: return("D1");
      case 32769: return("W1");
      case 49153: return("MN");      
      default: return("UnknownPeriod");
   }
}
//+------------------------------------------------------------------+

そこで問題となるのが、「時間軸の履歴を読み込んでいる間にループに入らないようにするにはどうしたらよいか」ということです。あくまでテストですが、一般的にインジケーターは指定した時間枠の履歴に従って計算を行うので、履歴がなくなるまで実行しようとする必要はないのですが。

ファイル:
iMTF_AO.mq5  12 kb
 
アルチョム・トリシキン

バーが1本しか ないんです。そして、「ネイティブ」タイムフレームのインジケーターは、データを正常に表示します。非ネイティブ」のほうは、空白の値が表示されます。経験的に、AOからデータを受け取る時間枠の履歴がすべて読み込まれるまでは、空の値が返されることがわかりました。

では、どうすればループに入らないか、時間枠の履歴を読み込んでいる間、問題は違って聞こえるでしょう。これはあくまでテストであり、一般的にインジケータは指定した時間枠の履歴に従って計算を行うため、履歴がなくなるまで計算を行おうとする必要はありません。

同期を試されましたか?また、タイマーにより、必要なTF/シンボルのデータを常に最新の状態に保つよう、開発者は助言しています。
 
これです。
      Buffer[i]=AO(i);

i」は「0」ではなく、何らかの法外な値である。結論:この例をM15で実行するとします - この期間には5000本のバーがあります。H4からデータを要求していますが、400本しかありません。そこで、"AO(4999) "を要求しようとする。

つまり、期間H4からインデックス「4999」のバーを要求しようとしますが、H4にはそのようなバーは全くなく、そこには400のバーしかありませんが、バー「0」を要求し、もしインディケータがコピーバッファ操作を使用するなら、チャート上の右端のバーがインディケータバッファの インデックス「0」に対応するように配列を回転(ArraySetAsSeries)すべきです(現在例「iMTF_AO.mq5」でチャート上の右端のバーはレート_合計-1に対応します)。

 

トレーディング、自動売買システム、トレーディング戦略のテストに関するフォーラム

バグ、バグ、質問

fxsaber さん 2017.04.12 08:38

ちょっとだけ脱帽。代入演算 子のバイパス
template <typename T>
struct STRUCT_COPY
{
  T Value;
  
  STRUCT_COPY( const T& tValue)
  {
    this = (STRUCT_COPY)tValue;
  }  
};

struct STRUCT
{
  int i;
  
  void operator =( const STRUCT& )
  {
    this.i = 5;
  }
};

#define  PRINT(A) ::Print(#A + " = " + (string)(A));

void OnStart()
{
  STRUCT Struct;  
  Struct.i = 1;  
  PRINT(Struct.i);
  
  STRUCT StructCopy1 = Struct;
  PRINT(StructCopy1.i);
  
  // Обходим void STRUCT::operator=(const STRUCT&)
  STRUCT_COPY<STRUCT> StructCopy2(Struct);
  PRINT(StructCopy2.Value.i);  
}

結果

Struct.i = 1
StructCopy1.i = 5
StructCopy2.Value.i = 1
 
ウラジーミル・カルプトフ
ここで..:

i」は「0」ではなく、何らかの法外な値である。結論:この例をM15で実行するとします - この期間には5000本のバーがあります。H4からデータを要求していますが、400本しかありません。そこで、"AO(4999) "を要求しようとする。

例えば、期間H4から、インデックス「4999」のバーを要求しようとしますが、H4にはそのようなバーはなく、そこには400のバーしかありませんが、バー「0」を要求し、もしインディケータがコピーバッファ操作を使用するなら、我々は配列を逆にして(ArraySetAsSeries)、チャートの右端のバーがインディケータバッファの インデックス「0」に相当するようにしなければなりません(例えば「iMTF_AO.mq5」のように、チャートの右端のバーは、rates_total-1に相当するようになりました)。

いや、もちろん限界まで 計算してみましたよ。

   int bars=Bars(NULL,PeriodForWork);                         
   datetime time_limit=GetTime(Symbol(),PeriodForWork,bars-1);
   int limit_p=GetBarShift(Symbol(),Period(),time_limit);     
   if(rates_total<1) return(0);
   int limit=(PeriodForWork==Period()?rates_total-prev_calculated:limit_p);
   if(limit>1) {          
      limit=rates_total-1;
      }                   

...しかし、私は急いでねじ込む ことを参照してください - それは、現在の時間枠にのみ適切である

 
アルチョム・トリシキン

いや、もちろん限界まで 計算してみましたよ。

...でも、なるほど、慌ててねじ 込んでしまいました。今の時間軸にのみふさわしい


  1. バッファの配列を反転させる (ArraySetAsSeries) - インジケータがCopyBufferを使用する場合、これは必須です。
  2. コピーされたデータ buffer_numをインデックスとするインジケータバッファ)のCopyBuffer:要素は、開始位置から現在から過去 に向かってカウントされる、つまり開始位置0は現在のバー(現在のバーのインジケータ値)を意味して いることに留意してください。
その後、AO(スタート "0 "はRIGHTESTバーを意味する)で、法外な値でなく。
 
ウラジーミル・カルプトフ

  1. バッファの配列を反転させる (ArraySetAsSeries) - インジケータがCopyBufferを使用する場合、これは必須です。
  2. コピーされたデータ buffer_numのインデックスを持つインジケータバッファ)のCopyBuffer: 要素は、現在から過去への 開始位置からカウントされること、つまり、0に等しい開始位置は現在のバー(現在のバーのインジケータ値)を意味 することに留意してください。
その後、AO(ラン "0 "はRIGHTESTバーを意味する)で、法外な値でなく。

私が示したコードを見たことがありますか?それとも実行したのでしょうか?

インジケータのバッファを埋める方法を聞いたのではなく、現在のバーからではなくAOから値を取ると空の値が返ってくるのはなぜか。
履歴はなく、読み込み中で、読み込み中にネイティブでないタイムフレームからのAOは「データがない」というエラーを返しました。

さて、問題は、必要な時間枠の履歴が完全にロードされ、指標サイクルに入らないようにするには、どうすればよいのでしょうか?

 
このトピックに関係のないコメントは、「MQL5 MT5 MetaTrader5初心者からの質問」に移動しました。
理由: