勝率65.83%のバイナリーオプションツールのバックテスト その2
前回の記事にて勝率65.83%のバイナリーオプションツールのアラートログとヒストリカルデータのDBが用意出来たので検証をしていきます。
前回の記事
abitra.hatenablog.com
検証内容と検証方法について
検証方法としてはエントリーの時刻とエントリー方向(High or Low)のログ(CSV)から各エントリー情報を取得して、そのデータを元にヒストリカルデータから同時刻のDBのIDを取得します。
エントリーの足データは 次足になるので ID + 1, 利益確定は ID + 2 になります。
そしてエントリー条件と内容と勝敗を判定した内容をCSVにて保存します。
※ついでに夏時間の反映もさせます。
検証プログラム rubyにて
プログラム的にはこんな感じです。
require 'sqlite3' require '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 writing db = SQLite3::Database.new 'usdjpy5m.db' csv_file_name = "tmusdjpy_backtest.csv" csv = "C:/Users/あなたのPCのパス/" + csv_file_name new_data = [] CSV.foreach(csv).each_with_index do |row, i| array = [] if row[2] == "lower" #lowエントリー puts "*****************************" sql_select = "select * from historical_data where date = '#{row[0]}' and time = '#{row[1]}'" p arrow_time = db.execute(sql_select.to_s)[0] entry_time = arrow_time[0].to_i + 1 #エントリー足 sql_select = "select * from historical_data where id = '#{entry_time}'" p entry_time = db.execute(sql_select.to_s)[0] judgment_time = arrow_time[0].to_i + 2 #判定足 sql_select = "select * from historical_data where id = '#{judgment_time}'" p judgment_time = db.execute(sql_select.to_s)[0] s_time = row[0] + " " + row[1] summertime(s_time) # 夏時間検証 ttt = Time.parse(s_time) + @time_x array << ttt.strftime("%Y/%m/%d") array << ttt.strftime("%H:%M:%S") array << "low" if entry_time[3] > judgment_time[6] puts "win" array << "win" else puts "lose" array << "lose" end new_data << array elsif row[2] == "upper" #highエントリー puts "*****************************" sql_select = "select * from historical_data where date = '#{row[0]}' and time = '#{row[1]}'" p arrow_time = db.execute(sql_select.to_s)[0] entry_time = arrow_time[0].to_i + 1 #エントリー足 sql_select = "select * from historical_data where id = '#{entry_time}'" p entry_time = db.execute(sql_select.to_s)[0] judgment_time = arrow_time[0].to_i + 2 #判定足 sql_select = "select * from historical_data where id = '#{judgment_time}'" p judgment_time = db.execute(sql_select.to_s)[0] s_time = row[0] + " " + row[1] summertime(s_time) # 夏時間検証 ttt = Time.parse(s_time) + @time_x array << ttt.strftime("%Y/%m/%d") array << ttt.strftime("%H:%M:%S") array << "high" if entry_time[3] < judgment_time[6] puts "win" array << "win" else puts "lose" array << "lose" end new_data << array end end db.close # p new_data CSV.open("tm_biynary_refined.csv","wb") do |csv| #精製したデータの書き込み処理 new_data.each do |csvArray| csv << csvArray end end end writing
メソッドは細かく分ける事も出来ますが面倒なのでとりま今回はこんな感じでザクっと流していきます。
やってる事は夏時間の計算、エントリーログから時刻取得してDBでヒストリカルデータ確認して判定してCSVに書き込み。
動かすとこんな感じです。
作成されたデータはこれ。
エントリー時間、分、エントリー方向、勝敗を記録しています。
集計方法及びエクセル検証など
上記そ作成されたデータを時間帯、High、 Low側の各勝率、 曜日による勝率、エントリー分足の勝率などで集計。
私の場合はここでエクセル登場(google スプレッドシート)
上記プログラムで作成されたデータをスプレッドシートに挿入して曜日や足などを別途計算、High、Low側なども計算
この辺はバックテスト時に全て自動で計算出来る様にスプレッドシートを組んでます。
キャプチャーみて頂ければを分かりますが勝率65.83%は嘘ではないです。
個人的にも色々バックテストをしてきた中でも優秀な部類に入るバックテストの結果かなーと考えます。
私の中の基準ですが逆張りは60%超えるとOK、順張りは40以下でOK。
総括(まとめ)
お勧めかと言われると試してもいいかもと考えています。
但し注意事項があります。
1. ダウンロードしたインジゲータのロジックが分からないので信用出来ない問題
矢印の出る条件が不明なため不安が付きまといます。(これは自身でロジック及びプログラムを作成出来る人のみの悩みかもしれませんがw)
検証してからバタバタしているのでエントリー条件を探し切れていませんが現状ではRSIの65%以上、30%以下ってのは一つの条件かと考えます。
それ以外にもブログや動画内の発言を見ている限りでは3つほどのインジゲータの条件をエントリーとしているかなーと。
2. 過度なオーバーフィッテイングの可能性問題
無料での提供なので、ばらまき様の為に調整されたインジゲータの可能性。
無料でばらまく理由は色々あるかと考えますが一つに有料のインジゲータへの導線で、私の様にバックテストしてもらい好成績を期待させて有料への流れといった感じ。
またタニアキラさんのスタイルは過去バックテストを大量にする事により高い成績を出していくスタイルなので過去チャートのオーバーフィッテイングは簡単かと。
3. 取引回数少ない問題
上記キャプチャーではモザイク掛けていますが時間帯でみると取引回数が少ない時間帯も多くあります。
取引回数が多ければ多いほど良いといったものでは御座いませんが個人的には100回以上エントリーしての勝率が欲しいかなーと。
まぁこれは私が2014年~2018年(5年程)で検証したのが原因でもありますが、あまりにも古い(2010年とか遡る)と違うかなーってものあり、どうしようかな。。。
4. 自動売買組めない可能性問題。
有料を前提とした話になりますが、基本的には裁量での運用が前提なのかと考えるので自動売買をこのインジゲータで行うのが難しい可能性があります。
メール通知の仕組みがあればサーバ立てて解決出来るかとは考えますが、メールの通知内容によってはめちゃくちゃ手間が必要。
●追記 2019年7月1日
iCustomで解決出来る可能性大。後日詳細の記事書きます。
とはいえ優秀なインジゲータの可能性が高いので引き続き様子をみてみたいと考えます。
併せて誰かインジゲータの分析できる方いませんか?w
一緒にエントリータイミングを分析しませんか?インジゲータの組み合わせがすごく気になる。
有料を買って全ての通貨のバックテストしようかな。。。きちんと評価及び検証するので無料で提供してくれないかなーw