「穴」のないチャート
動機
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
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索