Bitcoin 裁定取引と自動取引 abitra.netのブログ

Bitcoinの自動売買のあれこれ

バイナリーオプション(ハイローオーストラリア)をMT4でバックテストする方法 その2

先日紹介した方法ではストラテジーテスターでビジュアルモードを利用してCSVに書き込みエクセルで検証といった感じですが、今回はビジュアルモードを使わずに高速でバイナリーオプションのバックテスト検証の方法の案内。

先日の記事
abitra.hatenablog.com


今回の方法は一般的ではない+こんな方法しなくてもいいんじゃないか疑惑ですのでご了承下さいませ。
色々手間が発生するので正直おすすめ出来ないです。
1分足のバックテストはビジュアルモードを利用しないので爆速ですがw


■検証を行うにあたって
MQL4だけでは完結しません。rubyを利用しています。

1分足の検証などは圧倒的に早いのですが、5分以上になると手間とか考えると今までと同じ様なビジュアルモードで動かした方がいいかなーと。



■ビジュアルモードなしでバイナリーオプションのバックテストを行う方法(本題)

●重要
エントリーは注文内容によって把握します。


注文内容の前提を以下に定義します。

Highエントリーの場合の注文内容は"buy"
勝ちはlotを0.01
負けはlotを0.02
コマはlotを0.03(0.02でもいいかも)

Lowエントリーの場合の注文内容は"sell"
勝ちはlotを0.01
負けはlotを0.02
コマはlotを0.03(0.02でもいいかも)

この方法で注文して"結果"からコピーしてCSV保存して集計するといった感じです。
勘の良い方であれば上記定義でやってる事が分かるかと考えます。


残高は気にしません。
エントリーの注文内容が全てそれ以外は気にしなくてもいいです。
※lot数を1とかにしちゃうと残高不足でバックテストが途中で終わる可能性があるので最小の0.01にて。


参考までに前足が陽線陰線で注文を変えるソースで説明。
※勝ち負けはランダムです。

int start()
  {  
    int     StopLoss    = 20;
    int     TakeProfit  = 20;
    int     order_m_number = 99999;

    static datetime time111 = Time[0];
    if(Time[0] != time111) // 一回だけの処理
    {
      time111 = Time[0];
      int num = MathRand() % 2;  // 0 から 1
      if (Open[1] < Close[1]) // 陽線
      {
        if (num == 0) {// 勝ち lot を0.01に
          OrderSend( Symbol(), OP_SELL, 0.01, Bid, 30, Bid+(StopLoss*Point), Bid-(TakeProfit*Point), NULL, order_m_number, 0, clrDeepPink );
        } else if (num == 1) {// 負け lot を0.02
          OrderSend( Symbol(), OP_SELL, 0.02, Bid, 30, Bid+(StopLoss*Point), Bid-(TakeProfit*Point), NULL, order_m_number, 0, clrDeepPink );
        }        
      }
      else if (Open[1] > Close[1]) // 陰線
      {     
        if (num == 0) {// 勝ち lot を0.01に
          OrderSend( Symbol(), OP_BUY, 0.01, Ask, 30, Ask-(StopLoss*Point), Ask+(TakeProfit*Point), NULL, order_m_number, 0, clrDeepPink );
        } else if (num == 1) {// 負け lot を0.02
          OrderSend( Symbol(), OP_BUY, 0.02, Ask, 30, Ask-(StopLoss*Point), Ask+(TakeProfit*Point), NULL, order_m_number, 0, clrDeepPink );
        } 
      }
      else if (Open[1] == Close[1]) // コマ
      {
        OrderSend( Symbol(), OP_BUY, 0.03, Ask, 30, Ask-(StopLoss*Point), Ask+(TakeProfit*Point), NULL, order_m_number, 0, clrDeepPink );
      }
        
    }

    
    return(0);
  }


↑を動かすと注文され"結果"に注文履歴が表示されます。

結果の箇所で右クリックして"すべてコピー"を選択。

f:id:hogehoge_kato:20190618044430p:plain


テキストエディタにコピーしてCSVで保存。

f:id:hogehoge_kato:20190618044454p:plain


このままだと決済のデータが入っていたり日本時間ではないので管理しにくかったり余計な指値の金額など入っているので扱いやすいデータに精製してCSVに再出力します。

f:id:hogehoge_kato:20190618044508p:plain

精製はrubyを利用しています。
※夏時間の計算もしています。

require 'json'
require 'csv'
require 'time'

@csv_file_path = "C:/Users/xxxxxx/test_data/test_data.csv" # 保存したcsvのファイルパス

def summertime(csv_time)
  csv_time = Time.parse(csv_time)
  @time_x = 25200 # 冬時間
  if Time.parse("2005.3.13") <= csv_time && csv_time <= Time.parse("2005.11.6")    
    @time_x = 21600 # 夏時間
  elsif Time.parse("2006.3.12") <= csv_time && csv_time <= Time.parse("2006.11.5") 
    @time_x = 21600
  elsif Time.parse("2007.3.11") <= csv_time && csv_time <= Time.parse("2007.11.4")
      @time_x = 21600
  elsif Time.parse("2008.3.9")  <= csv_time && csv_time <= Time.parse("2008.11.2")
      @time_x = 21600
  elsif Time.parse("2009.3.8")  <= csv_time && csv_time <= Time.parse("2009.11.1")
      @time_x = 21600
  elsif Time.parse("2010.3.14") <= csv_time && csv_time <= Time.parse("2010.11.7")
      @time_x = 21600
  elsif Time.parse("2011.3.13") <= csv_time && csv_time <= Time.parse("2011.11.6")
      @time_x = 21600
  elsif Time.parse("2012.3.11") <= csv_time && csv_time <= Time.parse("2012.11.4")
      @time_x = 21600
  elsif Time.parse("2013.3.10") <= csv_time && csv_time <= Time.parse("2013.11.3")
      @time_x = 21600
  elsif Time.parse("2014.3.9")  <= csv_time && csv_time <= Time.parse("2014.11.2")
      @time_x = 21600
  elsif Time.parse("2015.3.8")  <= csv_time && csv_time <= Time.parse("2015.11.1")
      @time_x = 21600
  elsif Time.parse("2016.3.13") <= csv_time && csv_time <= Time.parse("2016.11.6")
      @time_x = 21600
  elsif Time.parse("2017.3.12") <= csv_time && csv_time <= Time.parse("2017.11.5")
      @time_x = 21600
  elsif Time.parse("2018.3.11") <= csv_time && csv_time <= Time.parse("2018.11.4")
      @time_x = 21600
  elsif Time.parse("2019.3.10") <= csv_time && csv_time <= Time.parse("2019.11.3")
      @time_x = 21600
  elsif Time.parse("2020.3.8")  <= csv_time && csv_time <= Time.parse("2020.11.1")
      @time_x = 21600
  elsif Time.parse("2021.3.14") <= csv_time && csv_time <= Time.parse("2021.11.7")
      @time_x = 21600
  elsif Time.parse("2022.3.13") <= csv_time && csv_time <= Time.parse("2022.11.6")
      @time_x = 21600
  elsif Time.parse("2023.3.12") <= csv_time && csv_time <= Time.parse("2023.11.5")
      @time_x = 21600
  elsif Time.parse("2024.3.10") <= csv_time && csv_time <= Time.parse("2024.11.3")
      @time_x = 21600
  elsif Time.parse("2025.3.9")  <= csv_time && csv_time <= Time.parse("2025.11.2")
      @time_x = 21600
  elsif Time.parse("2026.3.8")  <= csv_time && csv_time <= Time.parse("2026.11.1")
      @time_x = 21600
  elsif Time.parse("2027.3.14") <= csv_time && csv_time <= Time.parse("2027.11.7")
      @time_x = 21600
  elsif Time.parse("2028.3.12") <= csv_time && csv_time <= Time.parse("2028.11.5")
      @time_x = 21600
  elsif Time.parse("2029.3.11") <= csv_time && csv_time <= Time.parse("2029.11.4")
      @time_x = 21600
  elsif Time.parse("2030.3.10") <= csv_time && csv_time <= Time.parse("2030.11.3")
      @time_x = 21600
  elsif Time.parse("2031.3.9")  <= csv_time && csv_time <= Time.parse("2031.11.2")
      @time_x = 21600
  elsif Time.parse("2032.3.14") <= csv_time && csv_time <= Time.parse("2032.11.7")
      @time_x = 21600
  elsif Time.parse("2033.3.13") <= csv_time && csv_time <= Time.parse("2033.11.6")
      @time_x = 21600
  elsif Time.parse("2034.3.12") <= csv_time && csv_time <= Time.parse("2034.11.5")
      @time_x = 21600
  elsif Time.parse("2035.3.11") <= csv_time && csv_time <= Time.parse("2035.11.4")
      @time_x = 21600
  elsif Time.parse("2036.3.9")  <= csv_time && csv_time <= Time.parse("2036.11.2")
      @time_x = 21600
  elsif Time.parse("2037.3.8")  <= csv_time && csv_time <= Time.parse("2037.11.1")
      @time_x = 21600
  elsif Time.parse("2038.3.14") <= csv_time && csv_time <= Time.parse("2038.11.7")
      @time_x = 21600
  end
end #summertime end


def refining #CSVの精製
  new_data = []
  CSV.foreach(@csv_file_path).each_with_index do |row, i| # mt4のバックデータ読み込み処理
    array = []
    if row[0].include?("buy")
        row = row[0].gsub!(/\t/, ',').split(',')
        summertime(row[1]) # 夏時間検証
        array << Time.parse(row[1]) + @time_x
        array << "high"
        if row[4] == "0.01"     #0.01は勝ち
            array << "win"
        elsif row[4] == "0.02"  # 0.02は負け
            array << "lose"
        elsif row[4] == "0.03"  #コマ
            array << "lose"
        end
        new_data << array
    elsif row[0].include?("sell")
        row = row[0].gsub!(/\t/, ',').split(',')
        summertime(row[1])
        array << Time.parse(row[1]) + @time_x
        array << "low"
        if row[4] == "0.01"     #0.01は勝ち
            array << "win"
        elsif row[4] == "0.02"  # 0.02は負け
            array << "lose"
        elsif row[4] == "0.03"  #コマ
            array << "lose"
        end
        new_data << array
    end
  end #CSV.foreach end
 

  CSV.open("refined.csv","wb") do |csv| #精製したデータの書き込み処理
    new_data.each do |csvArray|
      csv << csvArray
    end
  end

end

refining


f:id:hogehoge_kato:20190618044615p:plain

コマは負けにしています。



精製した後のcsvデータはエクセル(google スプレッドシート)などで自由に検証してやれば完了。

f:id:hogehoge_kato:20190618044630p:plain




■懸念点
途中で面倒になったのでプログラム書いていませんが、注文時間とエントリー時間は1足分ズレているのでそれを考慮してやる必要があります。ruby プログラムで修正してやればいいかなーと。

勝敗しか取得できないので値幅など取得したい他のデータなどが取得出来ません。注文のコメントが使えればなー
何かほかに良い方法がありそうだけど。。。うーん。とりまビジュアルモードを利用しなでもバイナリーオプションのバックテスト(過去検証)出来たって事で。