週足・月足が正しく作成されるように、PeriodConverterを改造する
前回の記事で、MT4添付スクリプト「PeriodConverter」と、これを元にした派生スクリプトでは、週足・月足が正しく作成されないことを説明しました。
このまま放置するのも何なので、PeriodConverterを改造して、週足・月足が正しく作成されるようにしてみましょう。
ついでに、ALL版に改造しちゃいます!
ポイントは3点、
・最終足が保存されるようにする
・週足、月足のOpen時間を正しく計算する
・月足はOpen~Closeの期間が不定になることに留意する
と、ALL版のループ処理になります。
PeriodConverterAllEx.mq4
テキストをコピペして.mq4ファイルで保存し、MT4でコンパイルして下さい。
PeriodConverterの著作権はMetaQuotes社にあるので、コンパイル済ファイルの配布は行いません。
まぁ、MQL5ライブラリに登録する程度なら問題無いかもしれませんが…
PeriodConverterAllExの実行結果は下図のとおりです。

5分足と15分足の最終足、週足と月足とも正しく生成されています。
最後にWinMergeでのソースコード比較結果を添付します。ご参考まで。
> PeriodConverterからAllExへの変更箇所
このまま放置するのも何なので、PeriodConverterを改造して、週足・月足が正しく作成されるようにしてみましょう。
ついでに、ALL版に改造しちゃいます!
ポイントは3点、
・最終足が保存されるようにする
・週足、月足のOpen時間を正しく計算する
・月足はOpen~Closeの期間が不定になることに留意する
と、ALL版のループ処理になります。
PeriodConverterAllEx.mq4
//+------------------------------------------------------------------+
//| PeriodConverter.mq4 |
//| Copyright 2006-2015, MetaQuotes Software Corp. |
//| http://www.metaquotes.net |
//+------------------------------------------------------------------+
#property copyright "2006-2015, MetaQuotes Software Corp."
#property link "http://www.mql4.com"
#property description "Period Converter to updated format of history base"
#property strict
//#property show_inputs
//input int InpPeriodMultiplier=3; // Period multiplier factor
int InpPeriodMultiplier;
int ExtHandle=-1;
//+------------------------------------------------------------------+
//| script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
datetime time0;
ulong last_fpos=0;
long last_volume=0;
int i,start_pos,periodseconds;
int cnt=0;
//---- History header
int file_version=401;
string c_copyright;
string c_symbol=Symbol();
// int i_period=Period()*InpPeriodMultiplier;
int i_period;
int i_digits=Digits;
int i_unused[13];
MqlRates rate;
int all_period[8]={5,15,30,60,240,1440,10080,43200};
int j;
datetime next_bar_time;
//---
if(Period() != PERIOD_M1)
{
Print("Start Period Must be M1.");
return;
}
//---
for(j=0;j<ArraySize(all_period);j++)
{
InpPeriodMultiplier=all_period[j];
i_period=Period()*InpPeriodMultiplier;
Comment(i_period,"min. write...");
//---
ExtHandle=FileOpenHistory(c_symbol+(string)i_period+".hst",FILE_BIN|FILE_WRITE|FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_ANSI);
if(ExtHandle<0)
return;
c_copyright="(C)opyright 2003, MetaQuotes Software Corp.";
ArrayInitialize(i_unused,0);
//--- write history file header
FileWriteInteger(ExtHandle,file_version,LONG_VALUE);
FileWriteString(ExtHandle,c_copyright,64);
FileWriteString(ExtHandle,c_symbol,12);
FileWriteInteger(ExtHandle,i_period,LONG_VALUE);
FileWriteInteger(ExtHandle,i_digits,LONG_VALUE);
FileWriteInteger(ExtHandle,0,LONG_VALUE);
FileWriteInteger(ExtHandle,0,LONG_VALUE);
FileWriteArray(ExtHandle,i_unused,0,13);
//--- write history file
periodseconds=i_period*60;
start_pos=Bars-1;
rate.open=Open[start_pos];
rate.low=Low[start_pos];
rate.high=High[start_pos];
rate.tick_volume=(long)Volume[start_pos];
rate.spread=0;
rate.real_volume=0;
//--- normalize open time
// rate.time=Time[start_pos]/periodseconds;
// rate.time*=periodseconds;
next_bar_time=SetBarTime(rate.time,Time[start_pos],periodseconds);
for(i=start_pos-1; i>=0; i--)
{
if(IsStopped())
break;
time0=Time[i];
/*
//--- history may be updated
if(i==0)
{
//--- modify index if history was updated
if(RefreshRates())
i=iBarShift(NULL,0,time0);
}
*/
//---
// if(time0>=rate.time+periodseconds || i==0)
if(time0>=next_bar_time || i==0)
{
// if(i==0 && time0<rate.time+periodseconds)
if(i==0 && time0<next_bar_time)
{
rate.tick_volume+=(long)Volume[0];
if(rate.low>Low[0])
rate.low=Low[0];
if(rate.high<High[0])
rate.high=High[0];
rate.close=Close[0];
}
last_fpos=FileTell(ExtHandle);
last_volume=(long)Volume[i];
FileWriteStruct(ExtHandle,rate);
cnt++;
// if(time0>=rate.time+periodseconds)
if(time0>=next_bar_time)
{
// rate.time=time0/periodseconds;
// rate.time*=periodseconds;
next_bar_time=SetBarTime(rate.time,time0,periodseconds);
rate.open=Open[i];
rate.low=Low[i];
rate.high=High[i];
rate.close=Close[i];
rate.tick_volume=last_volume;
if(i==0)
{
FileWriteStruct(ExtHandle,rate);
cnt++;
}
}
}
else
{
rate.tick_volume+=(long)Volume[i];
if(rate.low>Low[i])
rate.low=Low[i];
if(rate.high<High[i])
rate.high=High[i];
rate.close=Close[i];
}
}
FileFlush(ExtHandle);
PrintFormat("%d record(s) written",cnt);
/*
//--- collect incoming ticks
datetime last_time=LocalTime()-5;
long chart_id=0;
//---
while(!IsStopped())
{
datetime cur_time=LocalTime();
//--- check for new rates
if(RefreshRates())
{
time0=Time[0];
FileSeek(ExtHandle,last_fpos,SEEK_SET);
//--- is there current bar?
if(time0<rate.time+periodseconds)
{
rate.tick_volume+=(long)Volume[0]-last_volume;
last_volume=(long)Volume[0];
if(rate.low>Low[0])
rate.low=Low[0];
if(rate.high<High[0])
rate.high=High[0];
rate.close=Close[0];
}
else
{
//--- no, there is new bar
rate.tick_volume+=(long)Volume[1]-last_volume;
if(rate.low>Low[1])
rate.low=Low[1];
if(rate.high<High[1])
rate.high=High[1];
//--- write previous bar remains
FileWriteStruct(ExtHandle,rate);
last_fpos=FileTell(ExtHandle);
//----
rate.time=time0/periodseconds;
rate.time*=periodseconds;
rate.open=Open[0];
rate.low=Low[0];
rate.high=High[0];
rate.close=Close[0];
rate.tick_volume=(long)Volume[0];
last_volume=rate.tick_volume;
}
//----
FileWriteStruct(ExtHandle,rate);
FileFlush(ExtHandle);
//--- target chart is not found yet. it can be opened via Main menu - File - Open offline
if(chart_id==0)
{
long id=ChartFirst();
while(id>=0)
{
//--- find appropriate offline chart
if(ChartSymbol(id)==Symbol() && ChartPeriod(id)==i_period && ChartGetInteger(id,CHART_IS_OFFLINE))
{
chart_id=id;
ChartSetInteger(chart_id,CHART_AUTOSCROLL,true);
ChartSetInteger(chart_id,CHART_SHIFT,true);
ChartNavigate(chart_id,CHART_END);
ChartRedraw(chart_id);
PrintFormat("Chart window [%s,%d] found",Symbol(),i_period);
break;
}
//--- enumerate opened charts
id=ChartNext(id);
}
}
//--- refresh window not frequently than 1 time in 2 seconds
if(chart_id!=0 && cur_time-last_time>=2)
{
ChartSetSymbolPeriod(chart_id,Symbol(),i_period);
last_time=cur_time;
}
}
Sleep(50);
}
*/
//---
if(ExtHandle>=0)
{
FileClose(ExtHandle);
ExtHandle=-1;
cnt=0;
}
Comment(i_period,"min. fin!");
}
//---
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
if(ExtHandle>=0)
{
FileClose(ExtHandle);
ExtHandle=-1;
}
//---
}
//+------------------------------------------------------------------+
//| バーの開始時間を計算する ※戻り値は次のバー開始時間 |
//+------------------------------------------------------------------+
datetime SetBarTime(datetime &bar_time,datetime current_time,int periodseconds)
{
datetime next_bar_time;
MqlDateTime mql_date_time;
switch(periodseconds)
{
case 604800: // Weekly
bar_time=current_time-current_time%86400; // Daily
bar_time=bar_time-TimeDayOfWeek(bar_time)*86400;
next_bar_time=bar_time+periodseconds;
break;
case 2592000: // Monthly
bar_time=current_time-current_time%86400; // Daily
bar_time=bar_time-(TimeDay(bar_time)-1)*86400;
TimeToStruct(bar_time,mql_date_time);
if(mql_date_time.mon!=12)
mql_date_time.mon++;
else
{
mql_date_time.year++;
mql_date_time.mon=1;
}
next_bar_time=StructToTime(mql_date_time);
break;
default:
bar_time=current_time-current_time%periodseconds;
next_bar_time=bar_time+periodseconds;
break;
}
return(next_bar_time);
}
//+------------------------------------------------------------------+
テキストをコピペして.mq4ファイルで保存し、MT4でコンパイルして下さい。
PeriodConverterの著作権はMetaQuotes社にあるので、コンパイル済ファイルの配布は行いません。
まぁ、MQL5ライブラリに登録する程度なら問題無いかもしれませんが…
PeriodConverterAllExの実行結果は下図のとおりです。

5分足と15分足の最終足、週足と月足とも正しく生成されています。
最後にWinMergeでのソースコード比較結果を添付します。ご参考まで。
> PeriodConverterからAllExへの変更箇所
テーマ : FX(外国為替証拠金取引)
ジャンル : 株式・投資・マネー