• カテゴリー別アーカイブ MetaTrader5/MQL5
  • MT5のストラテジーテスターのモデルについて

    相変わらず、MT5のブレイクする兆しは感じられないGWです。皆さん、お元気ですか?

    今回の記事は、そんななかでも、MT5のバックテストについてです。

    まず、MT4のストラテジーテスターでは、モデルとして「始値のみ」、「コントロールポイント」、「全ティック」の3つが用意されています。

    確定したバーの値のみを利用するEAでは「始値のみ」、最新のバーの値を利用するEAでは「全ティック」を選ぶのが普通です。「コントロールポイント」は、一つ下のタイムフレームまで使うモデルですが、なんか中途半端な感じで、個人的にはあまり使っていません。

    一方、MT5では、ストラテジーテスターのモデルは、「始値のみ」、「1分足OHLC」、「全ティック」、「リアルティック」の4つが用意されています。もう一つ「数値計算」というのがありますが、これはバックテスト用のモデルではありません。

    これらのモデルの詳細については、メタクォーツ社の以下の記事に詳しく説明されていますので、そちらをご覧ください。

    メタトレーダー5における検証の原則
    実際ティックでの取引ストラテジーのテスト

    ここで、「始値のみ」と「全ティック」はMT4と同じなので、MT4と同じように考えればよいでしょう。「リアルティック」はMT4にはなかったもので、実際のティックの履歴を使い、テストの精度も高いのですが、ティックの履歴はそんなに長く保存されるものではないので、テストする期間が長くなると品質が下がるという問題があります。

    そこで、残った「1分足OHLC」はどうか?というのが、今回のテーマです。

    「1分足OHLC」は、その名の通り、1分足の4本値を使うモデルです。参照するデータが少ない分、「全ティック」に比べると何十分の1かの時間でテストできます。最適化など何度もテストを繰り返す場合、テスト時間は圧倒的に短くなるというメリットがあります。ただ問題なのはテスト精度です。

    「1分足OHLC」のモデルでは、価格がO-L-H-C、あるいはO-H-L-Cと4段階でしか変化しないので、LとかHの値で約定することがあります。特に逆張りのEAの場合、実際の約定価格より有利な価格で約定することになり、当然ながらテストの結果も全ティックよりよくなります。

    ただし、その結果の違いは、EAの売買ロジックに大きく依存します。

    例えば、同じEAを「1分足OHLC」と「全ティック」のモデルでバックテストしたときに、取引回数が大きく違う場合、「1分足OHLC」はあまり参考になりません。1分間に何度もトレードをするEAなので、「全ティック」、あるいは「リアルティック」を使うべきでしょう。

    もし「1分足OHLC」と「全ティック」で取引回数に大きな違いがない場合、「1分足OHLC」の結果から「全ティック」の結果を推測できる可能性があります。

    ここに、とあるEAがあり、「1分足OHLC」と「全ティック」のテスト結果が次のようになったとします。

    • 「1分足OHLC」の結果
    • 「全ティック」の結果

    これを見ると、総損益は「1分足OHLC」が13734ドルに対して、「全ティック」は6437ドルと半分以下になっています。やはり、「1分足OHLC」では、実際より有利な価格で取引されているようです。ただし、取引回数は475回と478回で大差ありません。損益の減った分が取引回数に比例していれば、「1分足OHLC」の結果から「全ティック」の結果が推測できるかもしれません。

    このEAは、EUR/USDを1取引あたり1ロットで売買させています。(13734-6437)/475=15.36より、平均すると、1取引につき15.36ドルほど損益が多く計算されていることになります。pipsで表すと、1.536pipsです。

    ただ、この値はEAの売買ロジックや業者にも依存します。ここでは詳細なデータは省略しますが、同じEAで試したところ、テスト期間によっては、1.5pipsから2.0pipsの範囲で変化するようでした。

    そこで、1取引あたり、2.0pipsほど損益を減らすようバックテストの総損益を補正してみます。そのために、テストしたいEAのプログラム中に、次のようなOnTester()という関数を作っておきます。

    これは、総損益から取引数×ロット数×20を引いて補正するものです。この結果は、バックテスト後の「OnTester結果」のところに表示されます。


    これを見ると、4233.64となっています。補正するにしても、1.5pipsから2.0pipsと幅があるので、当然ながらある程度の誤差はやむを得ません。ただ、そのEAのだいたいの良し悪しが短時間で評価できるのであれば、まあ使い道はあるのではないかと思います。

    皆さん、よいGWを。



  • MT5のタイムフレームをMT4で使う場合の注意点

    前回の記事でMT5のタイムフレームをMT4で使うためのライブラリを紹介しました。

    最近は、互換性のないMT4とMT5で、いかに互換性のあるソースファイルが作れるかが研究テーマ(?)となっていますが、今回のライブラリの仕組みは次のようになっています。

    モメンタムを算出するテクニカル指標関数 iMomentum()の引数を iMomentum(PERIOD_M10, MomPeriod, 1)のように変えたのは、MQL4/MQL5の組み込み関数を直接呼び出すのではなく、別に定義した関数を呼び出すためです。

    追加したライブラリLibTF5.mqhには、次のような関数の定義が書かれています。

    MQL4/MQL5では、関数のオーバーロードの機能があり、同じ関数名でも引数の数が違えば、別の関数として定義できるのです。なので、iMomentum()の引数の数が5個であれば、組み込み関数(MQL5の場合、LibMQL4.mqhで定義した関数)が呼ばれるのですが、今回のように3個にすれば、このライブラリの関数が呼ばれるのです。

    symbolの引数を省略したのは、通常チャート上のシンボル_Symbolを使うことが多いからです。またapplied_priceの引数を省略したのは、テクニカル指標を算出するデータを終値に限定したからです。

    それで、このライブラリで定義したiMomentum()関数では、同じくライブラリ中のCheckTF()という関数の戻り値により、組み込み関数のiMomentum()と、iMomentumOnArray()のどちらを呼ぶかを場合分けしています。

    ここで、CheckTF()は、引数のタイムフレームがMT4,MT5でそれぞれ対応しているかどうかをチェックする関数で、対応していればtrueを返すので、そのまま組み込みのテクニカル指標関数を呼び出します。

    今回のライブラリでは、タイムフレームが対応していない場合の処理が重要ですが、ちょっと強引な方法をとっています。あとあまりコードが複雑にもならないようにもしているので、実行効率はよくありません。

    簡単にいうと、タイムフレームが対応していない場合、1分足の終値を使って指定したタイムフレームの終値の配列を作成します。そして、その配列に対してモメンタムを算出するiMomentumOnArray()を使って、指定したタイムフレームでのテクニカル指標値を求めているのです。

    ということなので、テクニカル指標といっても、配列に対して算出できる関数があるものしか現状では対応できないということになります。つまり、MQL4で使えるのは、iBandsOnArray(), iCCIOnArray(), iEnvelopesOnArray(), iMomentumOnArray(), iMAOnArray(), iRSIOnArray(), iStdDevOnArray()の7つということになります。これ以外のテクニカル指標に対応させたい場合は、自作する必要があるでしょう。

    あと、終値配列を毎回作成するので、結構時間がかかります。売買ルールが単純であれば、EA実行に支障をきたすことはありませんが、ストラテジーテスターでのバックテストは時間がかかりすぎて実用的ではありません。1分足の終値の配列サイズをRATES_SIZEという定数で1000に指定してあり、それを小さくすることで多少速くできるかもしれませんが、逆に小さくすると、大きいタイムフレームの終値のサイズが少なくなり、テクニカル指標が算出できないという問題も生じます。

    以上、色々と使用上の注意点があるので、それらを解決できるまでは、このライブラリはβ版のままかもしれません。

    とりあえず、興味のある方は使える範囲でお使いください。



  • MT5のタイムフレームをMT4で使うためのMQL4/MQL5共通EAライブラリの拡張

    MT4とMT5の違いの一つに、タイムフレームの数があります。

    MT4で対応しているタイムフレームは、M1,M5,M15,M30,H1,H4,D1,W1,MN1の9個ですが、MT5ではさらに M2,M3,M4,M6,M10,M12,M20,H2,H3,H6,M8,M12 の12個が追加されています。

    そんなにたくさんのタイムフレームをどう使い分けるのか、という疑問もありますが、ネットで調べると、MT4で対応していないタイムフレームを使おうとする記事がいくつか見つかります。全く需要がないわけでもなさそうです。

    筆者は基本的にMT5でEAを開発して、それをMT4で動かしています。そのため、どちらでも同じソースプログラムが使えるようにと、MQL4/MQL5共通EAライブラリを作りました。

    ただ、MT5で色々とタイムフレームを変えてみて、例えば、10分足がいいかなと思っても、MT4では10分足に対応していないので、そのままでは動きません。

    MT4でも、1分足データから10分足データを作って、オフラインチャートから強引にEAを動かすということもできるようですが、あまり面倒なことはしたくありません。

    今回の記事では、拙作のMQL4/MQL5共通EAライブラリに追加してインクルードするだけで、MT5のタイムフレームをMT4で使えるようにする方法を紹介します。

    まずは、「新メタトレ実践本用のMQL4/MQL5共通ライブラリ(β版)」で取り上げたEAのプログラムです。

    このEAは、ファイルの拡張子を「mq4」にすればMT4で、「mq5」にすればMT5でコンパイルし、動かすことができます。ただし、チャートに挿入したタイムフレームのテクニカル指標を使うので、MT4では対応している9種類のタイムフレームしか使えません。

    チャートのタイムフレームと関係なく、決まったタイムフレームのテクニカル指標を使いたい場合、iMomentum()関数の2番目の引数にタイムフレームの定数を代入します。例えば、10分足にしたければ、次のようにします。

    MT5は10分足に対応しているので、この変更だけで10分足のテクニカル指標を使うことができます。ただし、MT4の場合、コンパイルは通るのですが、10分足に対応していないので、iMomentum()の値は常に0になってしまい、EAとして機能しません。

    そこで、新たに作った次のヘッダファイルをインクルードしてみます。

    あと、iMmentum()関数の最初の引数「_Symbol」と、4番目の引数「PRICE_CLOSE」を削除してみます。全体のコードは次のようになります。

    変更箇所は2行のみですが、このプログラムだと、MT4、MT5両方で、10分足のテクニカル指標を使ったEAとして機能します。

    ただし、このライブラリはまだβ版ですので、今後変更になる可能性が高いです。またどんなテクニカル指標でも対応できるわけではなく、色々と制約があります。そのあたりについては、ライブラリの仕組みと関係するものですので、別の機会に解説したいと思います。



  • MT4/5でチャート毎にマジックナンバーを変える

    皆さん、こんにちは。ずいぶん久しぶりの記事です。

    MT4/MT5では、EAでマジックナンバーを設定することが多いです。

    同じMT4に複数のチャートを開いてEAを動かす場合、通貨ペアが異なっていれば、特にマジックナンバーは同じでも構いません。ただし、同じ通貨ペアのチャートをいくつも開いて同じEAを動かす場合、それぞれマジックナンバーを変えておく必要があります。

    もちろん input をつけてマジックナンバー変数を宣言しておけば、EAを挿入後にマジックナンバーを個別に変えることはできます。今回はこれを自動的に行いたいという人向けの記事です。(個人的に必要だったので作ったものですが)

    使う関数は、ChartID(), ChartFirst(), ChartNext()です。

    これらの関数は、もともとMQL5の関数でしたが、新MQL4になってMQL4でも使えるようになったものです。

    ChartID()は、プログラムを挿入したチャートのIDを返す関数です。

    ChartFirst()は、MT4で開いている最初のチャートのチャートIDを返す関数です。

    ChartNext()は、前のチャートIDを引数として次のチャートのチャートIDを返す関数です。

    簡単にやるには、チャートIDをそのままマジックナンバーにすればいいですが、チャートIDはかなり大きな整数値なので、もう少し簡単なマジックナンバーに置き換えてみます。

    以下は、チャート毎に異なるマジックナンバーを返す簡単なスクリプトです。

    マジックナンバーの初期値は100としており、チャートを探す度に1ずつ増やすので、それぞれのチャートで、100、101、102・・・とマジックナンバーが変わっていきます。

    それだけなんですが、まま簡単にできたのでメモしておきます。特に調べてないので、既出かもしれませんが。



  • [MQL4/5]新しいバーができたときに1回だけ実行する

    皆さん、こんにちは。

    久しぶりにMQL4/MQL5の記事です。
    先日、拙著の読者の方から質問をいただきました。

    その質問は、新しいバーができたときに1回だけ何か実行したい場合、どうすればよいかという内容でした。

    最近の拙著で説明しているEAでは、新しいバーができたときに発注するというケースしか扱っていなかったので、売買シグナルの条件に加えて、ポジションがないという条件をつけて、1回しか発注しないようにしていました。

    今回は、例えば、新しいバーができたときにAlert()関数で何か表示させるというように、1回実行したという情報がないケースを考えてみます。

    Volume[0]を使う方法


    新しいバーができた瞬間は、Volume[0]が1になっていることを利用する方法です。これが最も簡単な方法です。

    しかし、これには問題があり、新しいバーができたときにtickが連続してしまうと、OnTick()実行時にVolume[0]が2以上になってしまい、何も実行しないまま、次のバーまで待たなくてはいけなくなることがあります。

    昔のようにtickがのんびりとしていた時代はよかったのでしょうが、最近では、tickが速いので、この方法では、新しいバーで必ず1回実行できることは保証されません。

    Barsを使う方法


    次は、定義済み変数Barsを利用する方法です。Barsはチャート上のバーの総数を表す変数なので、新しいバーができると、値が更新されます。なので、最初にBarsの値を記録しておき、その値が変わったときが新しいバーができたときと判断し、Alert()を実行するというものです。実行後は、その時点でのBarsの値を記録しておけば、次のバーが出てくるまで、Alert()が実行されることはありません。

    この方法は、MT4だと問題ないようですが、一つ心配なのは、オプションでチャートの最大バー数を少なく設定したときに、新しいバーができてもバーの総数が変わらなくなることがないかということです。

    MT4の仕様はときどき変わるので、この方法も必ず機能するという保証はないかもしれません。

    Time[0]を使う方法


    もう一つ、バーの開始時刻Time[0]を使う方法があります。考え方は、新しいバーができるまで値が変わらないというBarsと同じです。単にBarsをTime[0]におきかえます。

    この方法だと、チャートの最大バー数とは関係なく、Time[0]はバーができる毎に更新されるので、バーの最初に1回実行するということは、保証されると思います。

    MQL5の場合


    最後におまけで、MQL5の場合です。MQL5では、Volume[0]、Bars、Time[0]すべて使えません。ここでは、Time[0]に対応する方法を使ったコードを示します。

    MQL5では定義済み変数がほとんど使えないので、CopyTime()という関数を使わなくてはいけなかったり、関数の引数に配列を用意しなくてはいけなかったり、外部変数宣言して、初期値の代入をOnInit()関数で行わなくてはいけなかったり、と面倒な限りです。

    こういう状態でMT5への移行は本当に進むのでしょうかね。
    最近Python始めたので、特にそう思いますね。