English Русский 中文 Español Deutsch Português
「穴」のないチャート

「穴」のないチャート

MetaTrader 4 | 18 3月 2016, 12:25
1 187 0
Andrey Khatimlianskii
Andrey Khatimlianskii

動機

MT4のチャート構築システムは、期間中に1つの変更でもあったバーのみ描かれるよう設計されています。もし1分間の間に変化がなかった場合、1分足チャートでは1つのバーが飛ばされます。

開発者は意図的にこのチャート構築法を選んでおり、それは既存の価格のみ含むチャートを好むユーザーが多い為です。少なくとも、連続チャートのファンは存在します。彼らはたとえ価格の変化が無かったとしても、始値が前のバーの終値と同じバーは描かれるべきであると考えています。このようにして、チャート上には時間のスケールの抜けが無くなり、分足チャートでの100のバーは常に100分間に相応することになります。現在の実装ではこの数字は異なる場合があります。例えば、もし100分間の間に2分間相場の情報がなかった場合、100分は98のバーで『収まって』しまいます。

幸いなことに、MQL4にはこのようなチャートを自力で実装する為に必要なツールが全て揃っています。



実装

まず初めに、課題を2つのステップに分けましょう。

  • ヒストリカルデータの処理。
  • 最新のバーの更新。

最初のステップでは、私たちはシンボル名に接頭辞"ALL"を持つ新しい履歴ファイルを作成("ALL" – "全て"というのは、私たちの場合"全てのバー"という意味です)し、そこに追加されたバーで履歴を書き込みます。

同様の問題は、MT4顧客ターミナルにある"period_converter"スクリプトで解決できます。スクリプトは非標準期間のチャートを生成します。この例で、私たちは履歴ファイルを使った作業を覚えます。

プログラムを作成する前に、スクリプト、インディケータ、もしくはエキスパートアドバイザとしてなど、どのような形で形成すべきかを決める必要があります。インディケータは、配列の内容を表示する為に使用されます。これは、私たちには必要ありません。エキスパートアドバイザとスクリプトの基本的な違いは、スクリプトは実行後にすぐにチャートから削除されることです。このステップでは、これが私たちに適しているので、私たちはこのスクリプトを作ることにしましょう。

結果は以下のようになります。(AllMinutes_Step1.mq4):

#property show_inputs

//---- 休日のバー描画の許可/禁止
//---- もしtrueの場合、休日は未記入のままになります
//---- もしfalseの場合、休日はOHLCのバーが描画されます
extern bool  SkipWeekEnd=true;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int start()
  {
   int HistoryHandle=-1,pre_time,now_time,_PeriodSec;
   double  now_close,now_open,now_low,now_high,now_volume,pre_close;

   int    _GetLastError=0,cnt_copy=0,cnt_add=0;
   int    temp[13];

//---- チャートの期間とシンボルを埋めます
   string _Symbol=Symbol();
   int _Period= Period();
   _PeriodSec = _Period * 60;

//---- 履歴を記録するファイルを開きます
   string file_name=StringConcatenate("ALL",_Symbol,_Period,".hst");
   HistoryHandle=FileOpenHistory(file_name,FILE_BIN|FILE_WRITE);
   if(HistoryHandle<0)
     {
      _GetLastError=GetLastError();
      Alert("FileOpenHistory( \"",file_name,"\",FILE_BIN | FILE_WRITE )"," - Error #",_GetLastError);
      return(-1);
     }

//---- ファイルの見出しを書きます
   FileWriteInteger(HistoryHandle,400,LONG_VALUE);
   FileWriteString(HistoryHandle,"Copyright © 2006, komposter",64);
   FileWriteString(HistoryHandle,"ALL"+_Symbol,12);
   FileWriteInteger(HistoryHandle,_Period,LONG_VALUE);
   FileWriteInteger(HistoryHandle,Digits,LONG_VALUE);
   FileWriteInteger(HistoryHandle, 0, LONG_VALUE);       //timesign
   FileWriteInteger(HistoryHandle, 0, LONG_VALUE);       //last_sync
   FileWriteArray(HistoryHandle,temp,0,13);
//+-----------------------------------------------------------------+
//| 履歴を処理します                                            |
//+-----------------------------------------------------------------+
   int bars = Bars;
   pre_time = Time[bars-1];
   for(int i= bars-1; i>= 0; i--)
     {
      //---- バーのパラメータを記憶します
      now_open = Open[i];
      now_high = High[i];
      now_low=Low[i];
      now_close=Close[i];
      now_volume=Volume[i];
      now_time=Time[i]/_PeriodSec;
      now_time*=_PeriodSec;
      //---- もし飛ばされたバーがある場合、
      while(now_time>pre_time+_PeriodSec)
        {
         pre_time += _PeriodSec;
         pre_time /= _PeriodSec;
         pre_time *= _PeriodSec;

         //---- もしそれが休日ではない場合、
         if(SkipWeekEnd)
           {
            if(TimeDayOfWeek(pre_time)<=0 || 
               TimeDayOfWeek(pre_time)>5)
               continue;
            if(TimeDayOfWeek(pre_time)==5)
              {
               if(TimeHour(pre_time)==23 || 
                  TimeHour(pre_time+_PeriodSec)==23)
                 {
                  continue;
                 }
              }
           }

         //---- 飛ばされたバーをファイルへ書き込みます
         FileWriteInteger(HistoryHandle,pre_time,LONG_VALUE);
         FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE);
         FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE);
         FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE);
         FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE);
         FileWriteDouble(HistoryHandle,1,DOUBLE_VALUE);
         FileFlush(HistoryHandle);
         cnt_add++;
        }

      //---- 新しいバーをファイルへ書き込みます
      FileWriteInteger(HistoryHandle,now_time,LONG_VALUE);
      FileWriteDouble(HistoryHandle,now_open,DOUBLE_VALUE);
      FileWriteDouble(HistoryHandle,now_low,DOUBLE_VALUE);
      FileWriteDouble(HistoryHandle,now_high,DOUBLE_VALUE);
      FileWriteDouble(HistoryHandle,now_close,DOUBLE_VALUE);
      FileWriteDouble(HistoryHandle,now_volume,DOUBLE_VALUE);
      FileFlush(HistoryHandle);
      cnt_copy++;

      //---- 記録されたバーの終値と 
      //---- 時間の値を記憶します
      pre_close = now_close;
      pre_time  = now_time / _PeriodSec;
      pre_time*=_PeriodSec;
     }

//---- ファイルを閉じます
   FileClose(HistoryHandle);

//---- 統計を出力します
   Print("< - - - ",_Symbol,_Period,":だった",cnt_copy,"追加されたバー",cnt_add,"バー- - ->");
   Print("< - - - 結果の表示には、\"ALL"チャートを開いてください,_Symbol,_Period,"\" - - - >");
   return(0);
  }

SkipWeekEnd変数に注意してください。もしこの値がfalseの場合、休日にもOHLC(ダッシュ)のバーが描画されます。

それでは、私たちのスクリプトがどう動作するかを確かめてみましょう。単純にこれをGBPUSDの分足チャートに取り付けます。

ここでALLGBPUSD1チャートを『オフライン』で開き、これを初期のチャートと比較します。

ご覧のように、チャートには幾つかの飛ばされた分が加えられました。これは赤い丸で囲まれています。これは私たちが求めていたものではありませんか?

それでは、飛ばされたものが書き込まれたチャートを持って、更新に取り組みたいと思います。今、チャート上には新しい相場は表示されず、同様に、新しい穴も埋められません。

例のために、もう一度"period_converter"スクリプトを使用します。チャートの更新の課題も、このスクリプトで解決することができます。一つの修正のみ行い、飛ばされたバーの記入ブロックを追加します。チャートは各ティックで更新する必要がある為、私たちのコード全てをエキスパートアドバイザに移します。これは新しい相場一つ一つの取得によって起動します。これは一度のみ実行されるべきである為、最初の部分のコードからinit()関数を配置します。そして、各ティックに必要となるので、新しい部分の全てにstart()関数を配置します。その他、ファイルの終了はdeinit()に移します。ここが適切な場所となります。

さて、エキスパートアドバイザのコードは以下のようになります。(AllMinutes_Step2.mq4):

#include <WinUser32.mqh>

//---- 休日のバー描画の許可/禁止
//---- もしtrueの場合、休日は未記入のままになります
//---- もしfalseの場合、休日はOHLCのバーが描画されます
extern bool  SkipWeekEnd=true;

int  HistoryHandle=-1,hwnd=0,last_fpos=0,pre_time,now_time;
int  _Period,_PeriodSec;
double  now_close,now_open,now_low,now_high,now_volume;
double  pre_close,pre_open,pre_low,pre_high,pre_volume;
string  _Symbol;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int init()
  {
   int _GetLastError=0,cnt_copy=0,cnt_add=0;
   int temp[13];

//---- チャートの期間とシンボルを埋めます
   _Symbol = Symbol();
   _Period = Period();
   _PeriodSec=_Period*60;
   hwnd=0;

//---- 履歴を記録するファイルを開きます
   string file_name=StringConcatenate("ALL",_Symbol,_Period,".hst");
   HistoryHandle=FileOpenHistory(file_name,FILE_BIN|FILE_WRITE);
   if(HistoryHandle<0)
     {
      _GetLastError=GetLastError();
      Alert("FileOpenHistory( \"",file_name,"\",FILE_BIN | FILE_WRITE )"," - Error #",_GetLastError);
      return(-1);
     }

//---- ファイルの見出しを書きます
   FileWriteInteger(HistoryHandle,400,LONG_VALUE);
   FileWriteString(HistoryHandle,"Copyright © 2006, komposter",64);
   FileWriteString(HistoryHandle,StringConcatenate("ALL",_Symbol),12);
   FileWriteInteger(HistoryHandle,_Period,LONG_VALUE);
   FileWriteInteger(HistoryHandle,Digits,LONG_VALUE);
   FileWriteInteger(HistoryHandle, 0, LONG_VALUE);       //timesign
   FileWriteInteger(HistoryHandle, 0, LONG_VALUE);       //last_sync
   FileWriteArray(HistoryHandle,temp,0,13);

//+-----------------------------------------------------------------+
//| 履歴を処理します                                            |
//+-----------------------------------------------------------------+
   int bars = Bars;
   pre_time = Time[bars-1];
   for(int i= bars-1; i>= 1; i--)
     {
      //---- バーのパラメータを記憶します
      now_open = Open[i];
      now_high = High[i];
      now_low=Low[i];
      now_close=Close[i];
      now_volume=Volume[i];
      now_time=Time[i]/_PeriodSec;
      now_time*=_PeriodSec;

      //---- もし飛ばされたバーがある場合、
      while(now_time>pre_time+_PeriodSec)
        {
         pre_time += _PeriodSec;
         pre_time /= _PeriodSec;
         pre_time *= _PeriodSec;

         //---- もしそれが休日ではない場合、
         if(SkipWeekEnd)
           {
            if(TimeDayOfWeek(pre_time)<=0 || TimeDayOfWeek(pre_time)>5)
               continue;
            if(TimeDayOfWeek(pre_time)==5)
              {
               if(TimeHour(pre_time)==23 || 
                  TimeHour(pre_time+_PeriodSec)==23)
                  continue;
              }
           }

         //---- 飛ばされたバーをファイルへ書き込みます
         FileWriteInteger(HistoryHandle,pre_time,LONG_VALUE);
         FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE);
         FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE);
         FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE);
         FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE);
         FileWriteDouble(HistoryHandle,1,DOUBLE_VALUE);
         FileFlush(HistoryHandle);
         cnt_add++;
        }

      //---- 新しいバーをファイルへ書き込みます
      FileWriteInteger(HistoryHandle,now_time,LONG_VALUE);
      FileWriteDouble(HistoryHandle,now_open,DOUBLE_VALUE);
      FileWriteDouble(HistoryHandle,now_low,DOUBLE_VALUE);
      FileWriteDouble(HistoryHandle,now_high,DOUBLE_VALUE);
      FileWriteDouble(HistoryHandle,now_close,DOUBLE_VALUE);
      FileWriteDouble(HistoryHandle,now_volume,DOUBLE_VALUE);
      FileFlush(HistoryHandle);
      cnt_copy++;

      //---- 記録されたバーの終値と 
      //---- 時間の値を記憶します
      pre_close= now_close;
      pre_time = now_time/_PeriodSec;
      pre_time*=_PeriodSec;
     }

   last_fpos=FileTell(HistoryHandle);

//---- 統計を出力します
   Print("< - - - ",_Symbol,_Period,": было ",cnt_copy," баров,добавлено ",cnt_add," баров - - - >");
   Print("< - - - 結果の表示には、\"ALL"チャートを開いてください,_Symbol,_Period,"\" - - - >");

//---- 0バーをすぐに描画する為にスタート関数を呼び出します
   start();

   return(0);
  }
//----
int start()
  {
//+---------------------------------------------------------------+
//| 取得されたティックを処理します                                 |
//+---------------------------------------------------------------+

//---- 『カーソル』を最新のバーの前に合わせます
//---- (これは最初を除く、全ての起動で必要です)
   FileSeek(HistoryHandle,last_fpos,SEEK_SET);

//---- バーのパラメータを記憶します
   now_open = Open[0];
   now_high = High[0];
   now_low=Low[0];
   now_close=Close[0];
   now_volume=Volume[0];
   now_time=Time[0]/_PeriodSec;
   now_time*=_PeriodSec;

//---- もしバーが形成された場合、 
   if(now_time>=pre_time+_PeriodSec)
     {
      //---- 形成されたバーを書き込みます
      FileWriteInteger(HistoryHandle,pre_time,LONG_VALUE);
      FileWriteDouble(HistoryHandle,pre_open,DOUBLE_VALUE);
      FileWriteDouble(HistoryHandle,pre_low,DOUBLE_VALUE);
      FileWriteDouble(HistoryHandle,pre_high,DOUBLE_VALUE);
      FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE);
      FileWriteDouble(HistoryHandle,pre_volume,DOUBLE_VALUE);
      FileFlush(HistoryHandle);

      //---- 0バーの記録前にファイル内の場所を記憶します
      last_fpos=FileTell(HistoryHandle);
     }

//---- もし飛ばされたバーが出現した場合、
   while(now_time>pre_time+_PeriodSec)
     {
      pre_time += _PeriodSec;
      pre_time /= _PeriodSec;
      pre_time *= _PeriodSec;

      //---- もしそれが休日ではない場合、
      if(SkipWeekEnd)
        {
         if(TimeDayOfWeek(pre_time)<=0 || 
            TimeDayOfWeek(pre_time)>5)
            continue;
         if(TimeDayOfWeek(pre_time)==5)
           {
            if(TimeHour(pre_time)==23 || 
               TimeHour(pre_time+_PeriodSec)==23)
               continue;
           }
        }

      //---- 飛ばされたバーをファイルへ書き込みます
      FileWriteInteger(HistoryHandle,pre_time,LONG_VALUE);
      FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE);
      FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE);
      FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE);
      FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE);
      FileWriteDouble(HistoryHandle,1,DOUBLE_VALUE);
      FileFlush(HistoryHandle);

      //---- 0バーの記録前にファイル内の場所を記憶します
      last_fpos=FileTell(HistoryHandle);
     }

//---- 現在のバーを書き込みます
   FileWriteInteger(HistoryHandle,now_time,LONG_VALUE);
   FileWriteDouble(HistoryHandle,now_open,DOUBLE_VALUE);
   FileWriteDouble(HistoryHandle,now_low,DOUBLE_VALUE);
   FileWriteDouble(HistoryHandle,now_high,DOUBLE_VALUE);
   FileWriteDouble(HistoryHandle,now_close,DOUBLE_VALUE);
   FileWriteDouble(HistoryHandle,now_volume,DOUBLE_VALUE);
   FileFlush(HistoryHandle);

//---- 記録されたバーのパラメータを記憶します
   pre_open = now_open;
   pre_high = now_high;
   pre_low=now_low;
   pre_close=now_close;
   pre_volume=now_volume;
   pre_time=now_time/_PeriodSec;
   pre_time*=_PeriodSec;

//---- 最新の相場を『送る』ウィンドウを見つけます
   if(hwnd==0)
     {
      hwnd=WindowHandle(StringConcatenate("ALL",_Symbol),_Period);
      if(hwnd!=0)
        {
         Print("< - - - チャート ","ALL"+_Symbol,_Period,"発見しました!- - - >");
        }
     }
//---- そして、もし見つかった場合、これを更新します
   if(hwnd!=0)
     {
      PostMessageA(hwnd,WM_COMMAND,33324,0);
     }
  }
//----
int deinit()
  {
   if(HistoryHandle>=0)
     {
      //---- ファイルを閉じます
      FileClose(HistoryHandle);
      HistoryHandle=-1;
     }
   return(0);
  }

ターミナルはファイルに書き込まれた全てのファイルをダウンロードするので、チャートの更新プロセスは多くのリソースを消費するということをすぐに申し上げておきます。もしファイル内に多くのファイルが存在する場合、ターミナルの動作が著しく遅くなることがあります。この多くは、MT4顧客ターミナルがインストールされているコンピュータの性能によります。いずれにしても、リソースは無尽蔵ではありません。私たちはこの問題を、チャート上に表示するバーの数を1万までにすることで解決したいと思います。(『サービス』ー『設定』ー『チャート』、パラメータ『ウィンドウ内の最大バー』)ここで、ターミナルを再起動し、私たちのエキスパートアドバイザを連結します。

  

エキスパートアドバイザは、すぐに履歴を『補填』し、新しいティックの出現を待ちます。2分後、これらのチャートはこのようになりました。

   

ご覧のように、上のチャートでは一つの『分』が追加され、下のチャートには更に飛ばされたバーが追加されました。

つまり、私たちは望む結果を得たわけです!



スケーリング

一つのチャートでも勿論良いのですが、もし飛ばされたバーのない10のチャートを開かなければならない場合、どうしたらいいのでしょうか?各チャートにエキスパートアドバイザが動作するものをもう一つ開くことは、最善の解決策とは言えません。余分なリソースが消費され、同様に、動作はより快適ではなくなります。

それでは、任意の数のチャートを処理することができるエキスパートアドバイザを作成してみましょう。これは使いやすく、コスト効率の高いものとなります。

さて、エキスパートアドバイザが幾つかのチャートで動作する為には、私たちのコードの何を変えるべきか。

  • チャートのリストを変えることができる外部変数を追加します。
  • 全ての変数を、処理するチャートの数と等しい要素の数を持つ配列と置き換えます。
  • 全てのコードを、これらのチャート自体が取捨されるサイクルに配置します。
  • 更新ブロックを無限ループに配置し、このようにして相場の取得から免れます。もしリスト内に異なるシンボルがある場合、その更新時間は同様に異なる場合があります。

結果は以下のようになります。(AllMinutes.mq4):

#include <WinUser32.mqh>

//---- 処理するべきチャートのリスト 
コンマで区切られた(",")
extern string    ChartList="EURUSD1,GBPUSD1";
//---- 休日のバー描画の許可/禁止
//---- もしtrueの場合、休日は未記入のままになります
//---- もしfalseの場合、休日はOHLCのバーが描画されます
extern bool     SkipWeekEnd=true;
//---- ミリ秒単位のチャート更新頻度
//---- 数値が高ければ高いほど、エキスパートアドバイザが使用する 
//---- リソースは少なくなります
extern int   RefreshLuft=1000;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int init()
  {
   start();
   return(0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int start()
  {
   int _GetLastError=0,cnt_copy=0,cnt_add=0,temp[13];
   int Charts=0,pos=0,curchar=0,len=StringLen(ChartList);
   string cur_symbol="",cur_period="",file_name="";

   string _Symbol[100]; int _Period[100],_PeriodSec[],_Bars[];
   int HistoryHandle[],hwnd[],last_fpos[],pre_time[],now_time[];
   double now_close[],now_open[],now_low[],now_high[],now_volume[];
   double pre_close[],pre_open[],pre_low[],pre_high[],pre_volume[];

//---- 処理する必要のあるチャート数を数えます
   while(pos<=len)
     {
      curchar=StringGetChar(ChartList,pos);
      if(curchar>47 && curchar<58)
         cur_period=cur_period+CharToStr(curchar);
      else
        {
         if(curchar==',' || pos==len)
           {
            MarketInfo(cur_symbol,MODE_BID);
            if(GetLastError()==4106)
              {
               Alert("不明なシンボル",cur_symbol,"!!!");
               return(-1);
              }
            if(iClose(cur_symbol,StrToInteger(cur_period),0)<=0)
              {
               Alert("不明な期間",cur_period,"!!!");
               return(-1);
              }

            _Symbol[Charts] = cur_symbol;
            _Period[Charts] = StrToInteger(cur_period);
            cur_symbol = "";
            cur_period = "";

            Charts++;
           }
         else
            cur_symbol=cur_symbol+CharToStr(curchar);
        }
      pos++;
     }
   Print("< - - - 発見されました",Charts,"正しいチャート- - - >");
   ArrayResize(_Symbol,Charts);
   ArrayResize(_Period,Charts);
   ArrayResize(HistoryHandle,Charts);
   ArrayResize(hwnd,Charts);
   ArrayResize(last_fpos,Charts);
   ArrayResize(pre_time,Charts);
   ArrayResize(now_time,Charts);
   ArrayResize(now_close,Charts);
   ArrayResize(now_open,Charts);
   ArrayResize(now_low,Charts);
   ArrayResize(now_high,Charts);
   ArrayResize(now_volume,Charts);
   ArrayResize(pre_close,Charts);
   ArrayResize(pre_open,Charts);
   ArrayResize(pre_low,Charts);
   ArrayResize(pre_high,Charts);
   ArrayResize(pre_volume,Charts);
   ArrayResize(_PeriodSec,Charts);
   ArrayResize(_Bars,Charts);

   for(int curChart=0; curChart<Charts; curChart++)
     {
      _PeriodSec[curChart]=_Period[curChart] *60;

      //---- 履歴を記録するファイルを開きます
      file_name=StringConcatenate("ALL",_Symbol[curChart],_Period[curChart],".hst");
      HistoryHandle[curChart]=FileOpenHistory(file_name,FILE_BIN|FILE_WRITE);
      if(HistoryHandle[curChart]<0)
        {
         _GetLastError=GetLastError();
         Alert("FileOpenHistory( \"",file_name,"\", FILE_BIN | FILE_WRITE)"," - Error #",_GetLastError);
         continue;
        }

      //---- ファイルの見出しを書きます
      FileWriteInteger(HistoryHandle[curChart],400,LONG_VALUE);
      FileWriteString(HistoryHandle[curChart],"Copyright © 2006, komposter",64);
      FileWriteString(HistoryHandle[curChart],StringConcatenate("ALL",_Symbol[curChart]),12);
      FileWriteInteger(HistoryHandle[curChart],_Period[curChart],LONG_VALUE);
      FileWriteInteger(HistoryHandle[curChart],MarketInfo(_Symbol[curChart],MODE_DIGITS),LONG_VALUE);
      FileWriteInteger(HistoryHandle[curChart], 0, LONG_VALUE);    // timesign
      FileWriteInteger(HistoryHandle[curChart], 0, LONG_VALUE);    // last_sync
      FileWriteArray(HistoryHandle[curChart],temp,0,13);

      //+-----------------------------------------------------------+
      //| 履歴を処理します                                            |
      //+-----------------------------------------------------------+
      _Bars[curChart]=iBars(_Symbol[curChart],_Period[curChart]);
      pre_time[curChart]=iTime(_Symbol[curChart],_Period[curChart],_Bars[curChart]-1);
      for(int i=_Bars[curChart]-1; i>=1; i--)
        {
         //---- バーのパラメータを記憶します
         now_open[curChart] = iOpen(_Symbol[curChart], _Period[curChart], i);
         now_high[curChart] = iHigh(_Symbol[curChart], _Period[curChart], i);
         now_low[curChart]=iLow(_Symbol[curChart],_Period[curChart],i);
         now_close[curChart]=iClose(_Symbol[curChart],_Period[curChart],i);
         now_volume[curChart]=iVolume(_Symbol[curChart],_Period[curChart],i);
         now_time[curChart]=iTime(_Symbol[curChart],_Period[curChart],i)/
                            _PeriodSec[curChart];
         now_time[curChart]*=_PeriodSec[curChart];

         //---- もし飛ばされたバーがある場合、
         while(now_time[curChart]>pre_time[curChart]+_PeriodSec[curChart])
           {
            pre_time[curChart] += _PeriodSec[curChart];
            pre_time[curChart] /= _PeriodSec[curChart];
            pre_time[curChart] *= _PeriodSec[curChart];

            //---- もしそれが休日ではない場合、
            if(SkipWeekEnd)
              {
               if(TimeDayOfWeek(pre_time[curChart])<=0 || 
                  TimeDayOfWeek(pre_time[curChart])>5)
                  continue;
               if(TimeDayOfWeek(pre_time[curChart])==5)
                 {
                  if(TimeHour(pre_time[curChart])==23 || 
                     TimeHour(pre_time[curChart]+
                     _PeriodSec[curChart])==23)
                     continue;
                 }
              }

            //---- 飛ばされたバーをファイルへ書き込みます
            FileWriteInteger(HistoryHandle[curChart],pre_time[curChart],LONG_VALUE);
            FileWriteDouble(HistoryHandle[curChart],pre_close[curChart],DOUBLE_VALUE);
            FileWriteDouble(HistoryHandle[curChart],pre_close[curChart],DOUBLE_VALUE);
            FileWriteDouble(HistoryHandle[curChart],pre_close[curChart],DOUBLE_VALUE);
            FileWriteDouble(HistoryHandle[curChart],pre_close[curChart],DOUBLE_VALUE);
            FileWriteDouble(HistoryHandle[curChart],1,DOUBLE_VALUE);
            FileFlush(HistoryHandle[curChart]);
            cnt_add++;
           }

         //---- 新しいバーをファイルへ書き込みます
         FileWriteInteger(HistoryHandle[curChart],now_time[curChart],LONG_VALUE);
         FileWriteDouble(HistoryHandle[curChart],now_open[curChart],DOUBLE_VALUE);
         FileWriteDouble(HistoryHandle[curChart],now_low[curChart],DOUBLE_VALUE);
         FileWriteDouble(HistoryHandle[curChart],now_high[curChart],DOUBLE_VALUE);
         FileWriteDouble(HistoryHandle[curChart],now_close[curChart],DOUBLE_VALUE);
         FileWriteDouble(HistoryHandle[curChart],now_volume[curChart],DOUBLE_VALUE);
         FileFlush(HistoryHandle[curChart]);
         cnt_copy++;

         //---- 記録されたバーの終値と 
         //---- 時間の値を記憶します
         pre_close[curChart]= now_close[curChart];
         pre_time[curChart] = now_time[curChart]/_PeriodSec[curChart];
         pre_time[curChart]*=_PeriodSec[curChart];
        }

      last_fpos[curChart]=FileTell(HistoryHandle[curChart]);

      //---- 統計を出力します
      Print("< - - - ",_Symbol[curChart],_Period[curChart],":あった",cnt_copy,"バー、追加された",cnt_add,"バー - - - >");
      Print("< - - - 結果の表示には、\"ALL"チャートを開いてください,_Symbol[curChart],_Period[curChart],"\" - - - >");

     }

//+---------------------------------------------------------------+
//| 取得されたティックを処理します                                 |
//+---------------------------------------------------------------+
   while(!IsStopped())
     {
      RefreshRates();
      for(curChart=0; curChart<Charts; curChart++)
        {
         //---- 『カーソル』を最新のバーの前に合わせます
         //---- (これは最初を除く、全ての起動で必要です)
         FileSeek(HistoryHandle[curChart],last_fpos[curChart],
                  SEEK_SET);

         //---- バーのパラメータを記憶します
         now_open[curChart]=iOpen(_Symbol[curChart],_Period[curChart],0);
         now_high[curChart]=iHigh(_Symbol[curChart],_Period[curChart],0);
         now_low[curChart]=iLow(_Symbol[curChart],_Period[curChart],0);
         now_close[curChart]=iClose(_Symbol[curChart],_Period[curChart],0);
         now_volume[curChart]=iVolume(_Symbol[curChart],_Period[curChart],0);
         now_time[curChart]=iTime(_Symbol[curChart],_Period[curChart],0)/_PeriodSec[curChart];
         now_time[curChart]*=_PeriodSec[curChart];

         //---- もしバーが形成された場合、 
         if(now_time[curChart]>=pre_time[curChart]+_PeriodSec[curChart])
           {
            //---- 形成されたバーを書き込みます
            FileWriteInteger(HistoryHandle[curChart],pre_time[curChart],LONG_VALUE);
            FileWriteDouble(HistoryHandle[curChart],pre_open[curChart],DOUBLE_VALUE);
            FileWriteDouble(HistoryHandle[curChart],pre_low[curChart],DOUBLE_VALUE);
            FileWriteDouble(HistoryHandle[curChart],pre_high[curChart],DOUBLE_VALUE);
            FileWriteDouble(HistoryHandle[curChart],pre_close[curChart],DOUBLE_VALUE);
            FileWriteDouble(HistoryHandle[curChart],pre_volume[curChart],DOUBLE_VALUE);
            FileFlush(HistoryHandle[curChart]);

            //---- 0バーの記録前にファイル内の場所を記憶します
            last_fpos[curChart]=FileTell(HistoryHandle[curChart]);
           }

         //---- もし飛ばされたバーが出現した場合、
         while(now_time[curChart]>pre_time[curChart]+_PeriodSec[curChart])
           {
            pre_time[curChart] += _PeriodSec[curChart];
            pre_time[curChart] /= _PeriodSec[curChart];
            pre_time[curChart] *= _PeriodSec[curChart];

            //---- もしそれが休日ではない場合、
            if(SkipWeekEnd)
              {
               if(TimeDayOfWeek(pre_time[curChart])<=0 || TimeDayOfWeek(pre_time[curChart])>5)
                  continue;
               if(TimeDayOfWeek(pre_time[curChart])==5)
                 {
                  if(TimeHour(pre_time[curChart])==23 || TimeHour(pre_time[curChart]+_PeriodSec[curChart])==23)
                     continue;
                 }
              }

            //---- 飛ばされたバーをファイルへ書き込みます
            FileWriteInteger(HistoryHandle[curChart],pre_time[curChart],LONG_VALUE);
            FileWriteDouble(HistoryHandle[curChart],pre_close[curChart],DOUBLE_VALUE);
            FileWriteDouble(HistoryHandle[curChart],pre_close[curChart],DOUBLE_VALUE);
            FileWriteDouble(HistoryHandle[curChart],pre_close[curChart],DOUBLE_VALUE);
            FileWriteDouble(HistoryHandle[curChart],pre_close[curChart],DOUBLE_VALUE);
            FileWriteDouble(HistoryHandle[curChart],1,DOUBLE_VALUE);
            FileFlush(HistoryHandle[curChart]);

            //---- 0バーの記録前にファイル内の場所を記憶します
            last_fpos[curChart]=FileTell(HistoryHandle[curChart]);
           }

         //---- 現在のバーを書き込みます
         FileWriteInteger(HistoryHandle[curChart],now_time[curChart],LONG_VALUE);
         FileWriteDouble(HistoryHandle[curChart],now_open[curChart],DOUBLE_VALUE);
         FileWriteDouble(HistoryHandle[curChart],now_low[curChart],DOUBLE_VALUE);
         FileWriteDouble(HistoryHandle[curChart],now_high[curChart],DOUBLE_VALUE);
         FileWriteDouble(HistoryHandle[curChart],now_close[curChart],DOUBLE_VALUE);
         FileWriteDouble(HistoryHandle[curChart],now_volume[curChart],DOUBLE_VALUE);
         FileFlush(HistoryHandle[curChart]);

         //---- 記録されたバーのパラメータを記憶します
         pre_open[curChart] = now_open[curChart];
         pre_high[curChart] = now_high[curChart];
         pre_low[curChart]=now_low[curChart];
         pre_close[curChart]=now_close[curChart];
         pre_volume[curChart]=now_volume[curChart];
         pre_time[curChart]=now_time[curChart]/
                            _PeriodSec[curChart];
         pre_time[curChart]*=_PeriodSec[curChart];

         //---- 最新の相場を『送る』ウィンドウを見つけます
         if(hwnd[curChart]==0)
           {
            hwnd[curChart]=WindowHandle(StringConcatenate("ALL",_Symbol[curChart]),_Period[curChart]);
            if(hwnd[curChart]!=0)
               Print("< - - - チャート ","ALL"+_Symbol[curChart],_Period[curChart]," 発見しました!- - - >");
           }
         //---- そして、もし見つかった場合、これを更新します
         if(hwnd[curChart]!=0)
            PostMessageA(hwnd[curChart],WM_COMMAND,33324,0);
        }
      Sleep(RefreshLuft);
     }
   for(curChart=0; curChart<Charts; curChart++)
     {
      if(HistoryHandle[curChart]>=0)
        {
         //---- ファイルを閉じます
         FileClose(HistoryHandle[curChart]);
         HistoryHandle[curChart]=-1;
        }
     }
   return(0);
  }

ここで、ChartListパラメータを持つEURUSDの5分足チャートにエキスパートアドバイザを起動し、全ての3つのチャートを『オフライン』で開いてみましょう。

全てうまくいったと思います。

全ての3つのチャートは同時に更新され、穴が出現した際にはそれは『補修』されます。

MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/1407

添付されたファイル |
AllMinutes.mq4 (28.3 KB)
MetaTrader 5にポジション計算のヘッジシステムが追加されました MetaTrader 5にポジション計算のヘッジシステムが追加されました
リテールFXトレーダーの可能性を拡大する為に、プラットフォームに2つ目の計算システムであるヘッジングが追加されました。これからは、シンボルごとに、反対方向のものを含む、多数のポジションを持つことができます。これによって、いわゆる『ロック』を使った取引戦略を実装することができ、つまり、もし価格がトレーダーに反する方向へ向かった場合、反対方向にポジションを開くことができます。
グラフィカルインタフェース  II: 区切り線とコンテキストメニュー要素(チャプター 2) グラフィカルインタフェース II: 区切り線とコンテキストメニュー要素(チャプター 2)
本稿では、区切り線要素を作成します。区切り線要素は、独立したインターフェース要素としてだけでなく、他の多くの構成要素の一部として使用することもできます。本稿ではまた、その後、コンテキストメニュークラスの開発に必要なものすべての詳細を考察します。それに加え、アプリケーションのすべてのグラフィカル・インターフェース要素へのポインタ格納の基本であるクラスに必要なすべての追加をご紹介します。
マーケット理論 マーケット理論
現在のところ、どの商品市場や相場にも適応可能で、ミクロでもマクロでも使うことができるような完璧な相場理論というものは存在していません。この記事では、利益分析に基づいた新しい相場理論のエッセンスを紹介し、現在の価格変化とメカニズムの原則を明らかにします。実際の価格上でコントロール可能なバーチャルプライスの連鎖を形成することにより、最適な値を見つけることができます。相場の形成と変化のメカニズムも紹介します。
グラフィカルインタフェース  II:メニュー項目要素(チャプター1) グラフィカルインタフェース II:メニュー項目要素(チャプター1)
シリーズの第二部では、メインメニュー、コンテキストメニューなどのインターフェイス要素の開発の詳細をお話しします。また、要素の描画にもふれ、そのための特別なクラスを作成します。カスタムイベントを含むプログラムイベントの管理なども詳しく話し合われます。