週足・月足が正しく作成されるように、PeriodConverterを改造する

前回の記事で、MT4添付スクリプト「PeriodConverter」と、これを元にした派生スクリプトでは、週足・月足が正しく作成されないことを説明しました。
 
このまま放置するのも何なので、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の実行結果は下図のとおりです。
period_converter_all_ex_weekly_monthly.png
 
5分足と15分足の最終足、週足と月足とも正しく生成されています。
 
最後にWinMergeでのソースコード比較結果を添付します。ご参考まで。
PeriodConverterからAllExへの変更箇所
 

テーマ : FX(外国為替証拠金取引)
ジャンル : 株式・投資・マネー

コメント

Secret

No title

今日、週足を使った検証をしていてズレに気づき、対策をググってみたら、やっぱりnekonoteさんのブログに書いてありました…本当にさすがです!
さっそくスクリプト使わせていただきました。ありがとうございました。

No title

素晴らしいプログラム、ありがとうございます!
感謝していますm(_ _)m

No title

素晴らしいスクリプトですね、ありがたく使わせていただきます
プロフィール

nekonote

Author:nekonote

EAを作るのが趣味になってしまったらしい。

あとマニアックな運用とかetc...その時の気分で書き殴る(?)
そんなブログ

※当ブログ記事へのリンクはご自由にどうぞ

 
運用は…fx-onのみんなのMT4に公開しているかも?
fx-on 通常会員ページ
fx-on 出品者ページ

最新記事
最新コメント
月別アーカイブ
カテゴリ
検索フォーム
ブログランキング
にほんブログ村 為替ブログ システムトレード 自作EA派へ





QRコード
QR
RSSリンクの表示
リンク
FX情報サイト
 優秀トレーダーの投資法をゲット!
FX投資情報コミュニティfx-on.com


国内MT4取扱会社
外為ファイネスト カコテン iOsMA (type DI) EURAUD タイアップキャンペーン

アヴァトレード・ジャパン株式会社 カコテン iOsMA (type DI) EURAUD タイアップキャンペーン

FOREX.com×タイアップキャンペーン☆Beatrice-07 FXTF×ForexSolidタイアップキャンペーン



自作EA紹介


EAフォワード集計結果
海外MT4業者
海外業者を選ぶ際は、まず金融庁の「注意喚起」を熟読して下さい。無登録業者で事故っても自己責任ですよ!
自分はゲムトレード&GEMFOREXに突撃してみましたw




自分もカコテンシリーズを幾つか出品しています。 運用結果でネタが集まれば時々記事にします。

ゲムトレードはEAの将来価値をリスクヘッジするには良い仕組みを提供していると思います。ただし本当に実力のあるEAはfx-on等から買った方が良いでしょう。
取引明細には現れませんがIBのような仕組みでゲムトレードへ報酬が渡っていますので、単一EAの長期運用ではデメリットが成績に現れると思われます。

※繰り返しますが海外業者でトラブっても自己責任です。お忘れなく!
FX専用VPS
レンタルサーバーなら使えるねっと



みんなのMT4
紫色:リアル口座
水色:デモ口座
ねこぱんち | fx-on.com
ねこぱんちMAXでも | fx-on.com
ねこのまえあし | fx-on.com
€$ XM demo | fx-on.com
£$ FxPro demo | fx-on.com
€¥ IFC Markets demo 2nd! | fx-on.com
£¥ IC Markets demo  | fx-on.com
$¥ MGK Global demo | fx-on.com
BigBoss demo AUDJPY | fx-on.com
€x LandFX demo | fx-on.com
KAKO10 iIchimoku リアル OANDA | fx-on.com
KAKO10 iIchimoku デモ FXTF | fx-on.com
KAKO10_iMA(H27.5~) | fx-on.com
KAKO10 iMA デモ Axiory(運用終了) | fx-on.com
KAKO10 iMA デモ Axiory新鯖 | fx-on.com
Ava demo iOsMA方向性スイング(運用終了) | fx-on.com
カコテン iOsMA (type DI) デモ Centrade | fx-on.com
カコテン iMomentum (type DI) デモ Arena | fx-on.com
瞬殺!!! NCSEC demo ※運用終了 | fx-on.com
GEMFOREX demo 新サーバーお試し ※破綻 | fx-on.com
 | fx-on.com
 | fx-on.com
 | fx-on.com
 | fx-on.com