【FX研究】ゴトー日EAを休日対応する

FX研究

以前のブログでゴトー日EAを作成して優位性を確認しました。

しかし、ゴトー日トレードを行う上で考慮すべき点がもう一つあります。

休日です。

仮に5日が休日で休みならその前日の4日がゴトー日となります。

また、その5日が月曜日なら、その前の金曜日の2日がゴトー日となります。

要はゴトー日が土日祝日の場合は、その前営業日が実質的なゴトー日になるということです。

これをEAに判断させてより精度の高いゴトー日EAを作成します。

ゴトー日EAを休日対応する

休日テーブル(配列)を作る

EAを記述しているmql4言語には日本の休日を判別する機能はないので、自分で判別しなければいけません。判別には以下の2種類の方法が考えられます。

1.休日のリストを作って、それからゴトー日を判断するロジックを作成する。

2.ゴトー日のリストを作って、その日にトレードするようにする

プログラミングが簡単なのは2.のほうだと思いますが、一般的に世間に流通しているのは休日のリストなので、今回は1.の方法で判別ロジックを作成します。

こちらのサイトに2017年からの日本の祝日一覧がありました。このデータをもとに休日のリスト(配列)を作成します。

// 休日のリスト
int holidays[][3] =
  {
    {2017,01,01},{2017,01,02},{2017,01,09},{2017,02,11},
  {2017,03,20},{2017,04,29},{2017,05,03},{2017,05,04},
    {2017,05,05},{2017,07,17},{2017,08,11},{2017,09,18},
  {2017,09,23},{2017,10,09},{2017,11,03},{2017,11,23},
    {2017,12,23},……// 中略
  ……{2046,11,23}
  };

必要なのは休日の日付のみなので、休日名、曜日の情報は削除しています。

休日を判定する関数を作る

このリストを使って休日を判定する関数を作ります。

// 指定の日が祝日の場合trueを返す
// 引数 targetday : 祝日か判断する日時
bool isHoliday(datetime targetday){
  // 休日のリスト
  int holidays[][3] =
  {
    {2017,01,01},{2017,01,02},……// 中略
    ……,{2046,11,23}
  };
  
  // 祝日の数だけループ
  for(int i=0;i<ArraySize(holidays)/3;i++){
   // 休日リストに年月日が一致する日があればtrueを返す
    if(TimeYear(targetday)==holidays[i][0]
      && TimeMonth(targetday)==holidays[i][1]
      && TimeDay(targetday)==holidays[i][2]
      ){
      return true;
    }
  }
 // リストにない場合falseを返す
  return false;
}

休日の配列の数だけループを回し、引数(targetday)と一致する年月日がある場合trueを返します。

ループ回数が ArraySize(holidays)/3 になっているのは、休日のリスト holidays[][3] が二次元配列で、休日数×3のサイズを持っているからです。

ゴトー日を判断する

前述のとおり、ゴトー日が土日祝日の場合は、その前営業日が実質的なゴトー日になるという判別をする必要があります。

いくつか方法はあると思いますが、以下の方法で判別を行います。

 ① 次のゴトー日(5で割り切れる日)を取得する

 ② 次のゴトー日を含む、その日まで土日祝日が続く場合は今日が実質ゴトー日

 ③ それ以外の場合、今日はゴトー日ではない

これで祝日を考慮したゴトー日判断ができると思います。

次のゴトー日(5で割り切れる日)を取得する

次のゴトー日をdatetime型で取得する関数を作りました。

// 次のゴトー日を取得する
datetime getNextFiveDay(){

  // チェックする日付。初期値に今の時間を入れる
  datetime checkday = japanTime;
  
  while(true){

    // チェック対象の日が5で割り切れる場合、その日を返す
    if(!MathMod(TimeDay(checkday),5))return checkday;
    
    // 一日分の秒数を足す
    checkday += 86400;
  }
}

ちょっと複雑になりました。

最初にdatetime型で今日の時間を設定し、while文の中で5で割り切れるかをチェックします。

割り切れなかった場合、checkday に86400秒(一日分)足して、再度5で割り切れるかのチェックを行う、という処理を5で割り切れるまで続けます。

datetime型は1970/1/1からの秒を格納する8bytesの型で、秒数を足し引きすることで上記プログラムのように1日後の日付を取得したりすることができます。
例えば、60を足せば1分後の時間が、120を引けば2分前の時間が取得できます。
日付を取り扱う上でこれを覚えておくと非常に便利です。
datetimeとlongの相互変換についてはこちら

土曜祝日を判定する関数を作る

無事、祝日を判別できるようになったので、今回のメインであるゴトー日が土日祝日の場合は、その前営業日が実質的なゴトー日になるという部分のロジックを作成します。

// 指定された日まで土日祝日が続く(今日がゴトー日)場合trueを返す
bool checkWeekendHoliday(datetime targetday){
  
  // 今日が祝日の場合はエントリーしないためfalseを返して処理を終了する。
  if(isHoliday(japanTime))return false;
  
  // 翌日から指定された日までループ
  for(long i=japanTime+86400;i<=targetday;i+=86400){
      
    // 土曜祝日ではない場合falseを返す
    if(
      !(TimeDayOfWeek(datetime(i))==SATURDAY
        || TimeDayOfWeek(datetime(i))==SUNDAY
        || isHoliday(datetime(i))
        )
      ){
      return false;
    }
  }
  // ループ内で土日祝日でないものがなかった場合(すべて土日祝日だった場合)trueを返す
  return true;
}

ちょっと複雑になりました。

まず、今日が祝日の場合、ゴトー日ではないのでfalseを返して処理を終了します。

次に翌日(先と同様、今日の日付に86400秒足した値)から指定の日(引数 targetday)まで、一日おき(i+=86400)にfor文で土日祝日か確認します。

確認には先ほど作成した isHoliday() 関数を使用します。

土日祝日じゃない日があった場合は、今日が次のゴトー日の前日ではないのでfalseを返して処理を終了します。

for 文の中でfalseにならなかった場合、次のゴトー日まですべて土日祝日であるため、trueを返します。

これで、今日が休日を考慮したゴトー日かを判別することができました。

ゴトー日を判別するメイン関数部分は以下のようになります。

// 最初にゴトー日フラグをfalseにする
isFiveDay=false;
      
// 次のゴトー日を取得する
datetime nextFiveDay = getNextFiveDay();


// ゴトー日判定をする
if(checkWeekendHoliday(nextFiveDay)){
  isFiveDay=true;
}

改良前と比較してみる

祝日対応版のバックテストは以下のようになりました。

期間:2017/1/1~2021/12/31

スプレッド=5で、PF=2.10でした。

前回作成したゴトー日EAとの比較は以下のようになりました。

取引総数が減っているのに純益、PF、期待利得、勝率すべてにおいて成績が向上しました。

やはりゴトー日の値動きは実需によるものなので休日の影響を大きく受けるようです。

おわりに

休日を考慮したゴトー日を判断するようになったので、より実用的になったと思います。

今回は休日テーブルからプログラムでゴトー日を判別するようにしましたが、自分でゴトー日テーブルを作ったほうがプログラミングは楽だったと思います。

それなりのものができたと思うので、実際に使ってみようかと考えています。

コメント

タイトルとURLをコピーしました