fc2ブログ

FXDDのヒストリカルデータの更新が1ヶ月以上行われていません

FXDDのヒストリカルデータですが、2016/4/9の更新を最後に更新されていません。
(→ダウンロードページ
このまま、FXDDのヒストリカルデータ提供サービスはフェードアウトしていくのでしょうか?
 
FXDDのヒストリカルデータでEAを開発されている場合、ヒストリカルデータの見直しに迫られそうですね。
 
長期ヒストリカルデータについて、国内のMT4業者では、楽天証券でAPIを使って長期ヒストリカルデータを取得可能です。
僕は、とある試用版のソフトウェアで楽天証券からヒストリカルデータを取得していますが、このソフトウェアは開発中止になっており、エラーが出てもサポートを受けられません。
(エラー覚悟でも試して見たい方は、ここ を参照してみて下さい)
また、FXCMが提供していたヒストリカルデータ取得ツールについては、楽天証券からは提供されてないようですので、ヒストリカルデータの提供は非公式と考えたほうが良いでしょう。
 
FXTFでは口座開設ユーザー向けにヒストリカルデータを提供していますが、2012年~の提供であるうえに更新がやたら遅いです。
 
MT4業者に拘らなければ、GMOクリック証券も口座開設ユーザー向けに2007年~のヒストリカルデータを提供しているようですが、僕は口座を持っていないので詳細は判りません。
最近、サービス変更の影響でダウンロードファイルが変わったとか何とか…?
 
結局、長期バックテストのヒストリカルデータは海外のMT4業者に頼るしか無く、最近はAlpariのヒストリカルデータに回帰しつつあるあります。
Alpariの場合、ヒストリーセンターから直接ダウンロードできるので、便利性は絶大です。
ただし、以前アルパリジャパンがあった頃に使っていたとき、唐突にヒストリカルデータがおかしくなる事象に何度か遭遇したことがあるので、今でも注意しながら使っています。
 
あとは、MT4に拘らなければDukascopyのヒストリカルデータも信頼性が高いほうですが、Tickstoryを使うのは止めました。
モデリング品質99%という数値に根拠がないのに、言葉だけが一人歩きしていますからね。
最近はJForexからダウンロードするようにしています。
 
Forexiteのヒストリカルデータは、桁数が少ないのでレート精度は劣るものの、提供期間の長さやレートの時間の正確さなど、FXDDのヒストリカルデータに比べれば使えると思っています。
 
そういえばOANDAもAPIを提供していますが、僕は試したことがありません。
(口座が複数に分散しているのでAPI使用条件の口座残高を満たしていない)
もしかしたら、APIでヒストリカルデータを取得できるのかもしれませんね。
 

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

FXDDのヒストリカルデータが2週連続で更新されず…

FXDDのヒストリカルデータは、いつも週末に更新されていたのですが、ここ2週間ばかり更新が滞っています。(→ダウンロードページ
 
それと関連するのかは不明ですが、FXDDは、JForexとミラートレーダーのサービスを今月いっぱいで終了するとのアナウンスを行っています。(→FXDD公式ブログ
 
個人的には、FXDDのヒストリカルデータ提供が滞っても困ることはない(ここのデータはあまり信用していない)です。
 
しかし一般的な話として、FXDDのヒストリカルデータでバックテストする方が多いのも事実で、仮にFXDDがヒストリカルデータの提供を打ち切るような事態に直面すると、大きな反響を呼ぶことになるでしょう。
 
暫くはFXDDの動向に注目ですね。
 

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

週足・月足が正しく作成されるように、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(外国為替証拠金取引)
ジャンル : 株式・投資・マネー

案外知られていない、MT4添付スクリプト「PeriodConverter」のバグ(正しくは制約)

MT4に添付されているスクリプト「PeriodConverter」は、主に1分足から上位時間足を作成するために使われています。
このスクリプトはパラメータ「Period multiplier factor」の設定を必要としますが、この設定を省き、5分足~月足まで一度に生成する「Period_ConverterALL」や「all_period_converter」などの派生スクリプトも多数公開されています。
 
しかし、これら「PeriodConverter」と派生スクリプトにバグ(正しくは制約)があることは、案外知られていません。
 
それにはまず、MT4添付スクリプト「PeriodConverter」の目的を理解する必要があります。
 
「PeriodConverter」の本来の目的は、オンラインのチャートに常駐させて、パラメータで指定した倍率の上位時間足をリアルタイムで生成していくものです。
ですので、オフラインチャートの5分足~月足を生成して終わり、という使い方は、スクリプトの本来の目的から外れています
 
この弊害がどこに現れるかというと、最新時間足の生成が行われない問題と、週足・月足のOpen時間が正しく設定されない問題が発生します。
 
「PeriodConverter」や派生スクリプトで、オフラインチャート1分足から上位時間足を生成した場合、下図のようになります。
period_converter_weekly_monthly_bug.png
 
どこが間違っているか分かりますか?
 
まず、1分足の終了が23時45分ですので、5分足と15分足の23時45分にも足が生成されているべきですが、生成されていません。
 
次に、週足の差出人(開始日時)が2005年1月6日になっていますが、この日は木曜日です。 
週足は日曜日から始まりますので、本来の週足は2005年1月9日(日)から始まります。
月足も同様で、本来は2005年1月1日から始まります。
 
よって、下図が正しいバー生成結果となります。
period_converter_weekly_monthly_fixed.png
(ForexStudioのDatacenterを使って出力したヒストリカルデータ)
 
MTF系のインジケーターやEAでは、週足を参照しているケースもあります。
MTF系ロジックのバックテストを行う際、PeriodConverterや派生スクリプトで生成したヒストリカルデータでは、正しい週足が生成されていないことを認識しておきましょう。
 

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

UTC+0のヒストリカルデータを、UTC+2/+3や日本時間(UTC+9)にするVBスクリプト

前回の記事でJForexを使ってDukascopyのヒストリカルデータをダウンロードしましたが、時間はUTC+0固定になっています。
これをUTC+2夏時間有(UTC+2/+3)や、日本時間(UTC+9)に変換するVBスクリプトを作成しました。 
 
UTC+0のhstファイルをUTC+2夏時間有に変換.vbs
Option Explicit

'----------------------------------------------------------------------------
' UTC+0のヒストリカルデータ(.hst)を、UTC+2夏時間有に変換するVBScript
' スクリプトファイルに.hstファイルをドラッグアンドドロップして使用する
' 出力先はスクリプト実行フォルダに作成される work フォルダの中
'
' ※作成された.hstで上書きする前にオリジナルの.hstをバックアップしましょう。
'----------------------------------------------------------------------------

Const adTypeBinary = 1
Const adTypeText = 2
Const adSaveCreateOverWrite = 2
Const adReadAll = -1

Dim lngDatetime, binDatetime    ' bar start timeの整数値とバイナリ配列
Dim dteDatetime                 ' bar start timeの日付型変換後
Dim workFolder, workFile        ' 出力フォルダ、出力ファイル
Dim objFs                       ' ファイル操作(FileSystemObject)
Dim objStBin, objStIn, objStOut ' バイナリ操作(ADODB.Stream)
Dim lngStPos                    ' ファイル操作位置
Dim intVersion                  ' Version番号
Dim intBarsStructSize           ' Bars構造体のサイズ
Dim intStructPosition           ' 構造体のデータ位置
Dim i

' 引数が無いなら終了
If WScript.Arguments.Count < 1 Then WScript.Quit

Set objFs = CreateObject("Scripting.FileSystemObject")
Set objStBin = CreateObject("ADODB.Stream")
Set objStIn = CreateObject("ADODB.Stream")
Set objStOut = CreateObject("ADODB.Stream")

' 出力フォルダ作成
workFolder = objFs.BuildPath(objFs.GetFile(WScript.ScriptFullName).ParentFolder.Path, "work")
If Not objFs.FolderExists(workFolder) Then objFs.CreateFolder (workFolder)

' hstファイル書き換え
For i = 0 To WScript.Arguments.Count - 1
  If Right(WScript.Arguments(i), 4) = ".hst" Then
    If objFs.FileExists(WScript.Arguments(i)) Then
      
      ' .hstファイルを開く
      objStIn.Type = adTypeBinary
      objStIn.Open
      objStIn.LoadFromFile WScript.Arguments(i)
      
      ' 出力側のストリームを開く
      objStOut.Type = adTypeBinary
      objStOut.Open
      
      ' 出力ファイル名を指定
      workFile = objFs.GetFileName(WScript.Arguments(i))
      workFile = objFs.BuildPath(workFolder, workFile)
      
      ' 出力側ストリームへコピー
      objStIn.Position = 0
      objStOut.Write objStIn.Read(adReadAll)
      
      ' バージョン取得(400 or 401)
      objStIn.Position = 0
      intVersion = CLng("&H" & Hex(AscW(objStIn.Read(2))))
      If intVersion = 400 Then
          intBarsStructSize = 44  ' 構造体サイズ
          intStructPosition = 0   ' 書込位置
      Else
          intBarsStructSize = 60  ' 構造体サイズ
          intStructPosition = 0   ' 書込位置
      End If
      
      ' バー配列のbar start timeを書き換える
      ' ※ヘッダー部148bytes、バー構造体は44 or 60bytes
      For lngStPos = (148 + intStructPosition) To objStIn.Size - 1 Step intBarsStructSize
        
        ' 時間の読み取り
        objStIn.Position = lngStPos
        lngDatetime = CLng("&H" & Hex(AscW(objStIn.Read(2))))
        lngDatetime = lngDatetime + CLng("&H" & Hex(AscW(objStIn.Read(2)))) * &H10000
        dteDatetime = 25569 + lngDatetime / 86400
        
        ' アメリカ東部夏時間(EDT)の期間は1時間進める (UTC+0/+0 → UTC+0/+1)
        If Year(dteDatetime) >= 2007 Then
          If dteDatetime >= DateSerial(Year(dteDatetime), 3, 14 - (Weekday(DateSerial(Year(dteDatetime), 3, 1)) + 5) Mod 7) Then
            If dteDatetime < DateSerial(Year(dteDatetime), 11, 7 - (Weekday(DateSerial(Year(dteDatetime), 11, 1)) + 5) Mod 7) Then
              dteDatetime = dteDatetime + TimeSerial(1, 0, 0)
            End If
          End If
        Else
          If dteDatetime >= DateSerial(Year(dteDatetime), 4, 7 - (Weekday(DateSerial(Year(dteDatetime), 4, 1)) + 5) Mod 7) Then
            If dteDatetime < DateSerial(Year(dteDatetime), 11, 0 - (Weekday(DateSerial(Year(dteDatetime), 11, 1)) + 5) Mod 7) Then
              dteDatetime = dteDatetime + TimeSerial(1, 0, 0)
            End If
          End If
        End If
        
        ' さらに2時間進める (UTC+0/+1 → UTC+2/+3)
        dteDatetime = dteDatetime + TimeSerial(2, 0, 0)
        lngDatetime = CLng((dteDatetime - 25569) * 86400)
        
        ' 時間のバイナリ配列作成
        objStBin.Type = adTypeText
        objStBin.Charset = "unicode"
        objStBin.Open
        objStBin.WriteText ChrW(lngDatetime Mod &H10000)
        objStBin.WriteText ChrW(lngDatetime \ &H10000)
        objStBin.Position = 0
        objStBin.Type = adTypeBinary
        objStBin.Position = 2               ' 先頭2bytesはBOMなので読まない
        binDatetime = objStBin.Read(4)
        objStBin.Close
        
        ' 時間を更新
        objStOut.Position = lngStPos
        objStOut.Write binDatetime
        
      Next
      
      ' 出力ファイル保存
      objStOut.SaveToFile workFile, adSaveCreateOverWrite
      objStOut.Close
      objStIn.Close
      
    End If
  End If
Next

Set objStBin = Nothing
Set objStOut = Nothing
Set objStIn = Nothing
Set objFs = Nothing

MsgBox "出力しました。workフォルダを確認して下さい", vbInformation

 
UTC+0のhstファイルを日本時間に変換.vbs
Option Explicit

'----------------------------------------------------------------------------
' UTC+0のヒストリカルデータ(.hst)を、日本時間(UTC+9)に変換するVBScript
' スクリプトファイルに.hstファイルをドラッグアンドドロップして使用する
' 出力先はスクリプト実行フォルダに作成される work フォルダの中
'
' ※作成された.hstで上書きする前にオリジナルの.hstをバックアップしましょう。
'----------------------------------------------------------------------------

Const adTypeBinary = 1
Const adTypeText = 2
Const adSaveCreateOverWrite = 2
Const adReadAll = -1

Dim lngDatetime, binDatetime    ' bar start timeの整数値とバイナリ配列
Dim dteDatetime                 ' bar start timeの日付型変換後
Dim workFolder, workFile        ' 出力フォルダ、出力ファイル
Dim objFs                       ' ファイル操作(FileSystemObject)
Dim objStBin, objStIn, objStOut ' バイナリ操作(ADODB.Stream)
Dim lngStPos                    ' ファイル操作位置
Dim intVersion                  ' Version番号
Dim intBarsStructSize           ' Bars構造体のサイズ
Dim intStructPosition           ' 構造体のデータ位置
Dim i

' 引数が無いなら終了
If WScript.Arguments.Count < 1 Then WScript.Quit

Set objFs = CreateObject("Scripting.FileSystemObject")
Set objStBin = CreateObject("ADODB.Stream")
Set objStIn = CreateObject("ADODB.Stream")
Set objStOut = CreateObject("ADODB.Stream")

' 出力フォルダ作成
workFolder = objFs.BuildPath(objFs.GetFile(WScript.ScriptFullName).ParentFolder.Path, "work")
If Not objFs.FolderExists(workFolder) Then objFs.CreateFolder (workFolder)

' hstファイル書き換え
For i = 0 To WScript.Arguments.Count - 1
  If Right(WScript.Arguments(i), 4) = ".hst" Then
    If objFs.FileExists(WScript.Arguments(i)) Then
      
      ' .hstファイルを開く
      objStIn.Type = adTypeBinary
      objStIn.Open
      objStIn.LoadFromFile WScript.Arguments(i)
      
      ' 出力側のストリームを開く
      objStOut.Type = adTypeBinary
      objStOut.Open
      
      ' 出力ファイル名を指定
      workFile = objFs.GetFileName(WScript.Arguments(i))
      workFile = objFs.BuildPath(workFolder, workFile)
      
      ' 出力側ストリームへコピー
      objStIn.Position = 0
      objStOut.Write objStIn.Read(adReadAll)
      
      ' バージョン取得(400 or 401)
      objStIn.Position = 0
      intVersion = CLng("&H" & Hex(AscW(objStIn.Read(2))))
      If intVersion = 400 Then
          intBarsStructSize = 44  ' 構造体サイズ
          intStructPosition = 0   ' 書込位置
      Else
          intBarsStructSize = 60  ' 構造体サイズ
          intStructPosition = 0   ' 書込位置
      End If
      
      ' バー配列のbar start timeを書き換える
      ' ※ヘッダー部148bytes、バー構造体は44 or 60bytes
      For lngStPos = (148 + intStructPosition) To objStIn.Size - 1 Step intBarsStructSize
        
        ' 時間の読み取り
        objStIn.Position = lngStPos
        lngDatetime = CLng("&H" & Hex(AscW(objStIn.Read(2))))
        lngDatetime = lngDatetime + CLng("&H" & Hex(AscW(objStIn.Read(2)))) * &H10000
        dteDatetime = 25569 + lngDatetime / 86400
        
        ' 9時間進める (UTC+0 → UTC+9)
        dteDatetime = dteDatetime + TimeSerial(9, 0, 0)
        lngDatetime = CLng((dteDatetime - 25569) * 86400)
        
        ' 時間のバイナリ配列作成
        objStBin.Type = adTypeText
        objStBin.Charset = "unicode"
        objStBin.Open
        objStBin.WriteText ChrW(lngDatetime Mod &H10000)
        objStBin.WriteText ChrW(lngDatetime \ &H10000)
        objStBin.Position = 0
        objStBin.Type = adTypeBinary
        objStBin.Position = 2               ' 先頭2bytesはBOMなので読まない
        binDatetime = objStBin.Read(4)
        objStBin.Close
        
        ' 時間を更新
        objStOut.Position = lngStPos
        objStOut.Write binDatetime
        
      Next
      
      ' 出力ファイル保存
      objStOut.SaveToFile workFile, adSaveCreateOverWrite
      objStOut.Close
      objStIn.Close
      
    End If
  End If
Next

Set objStBin = Nothing
Set objStOut = Nothing
Set objStIn = Nothing
Set objFs = Nothing

MsgBox "出力しました。workフォルダを確認して下さい", vbInformation

 
テキストをコピペし、ファイル拡張子.vbsとして保存して下さい。
使い方はスクリプトのコメントに記載したとおりです。
.hstファイル(複数可)を.vbsファイルへドラッグ&ドロップ後、暫く待つと処理終了のダイアログが表示されますので、workフォルダに作成された.hstファイルを元の.hstファイルと差し替えて下さい。
 
なおスクリプトで修正可能な時間足は、1分足~1時間足までです。
それ以上の長時間足では正しく修正できません。
長時間足は、Period ConverterなどのMT4スクリプトで作成し直して下さい。
 
ちなみに、2003年~2016年の1分足ヒストリカルデータを変換する場合、1ファイルあたり数分掛かります。
 

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

プロフィール

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