ゼロから始めるEA開発Part9 デバッグ方法
「ゼロから始めるEAの開発」シリーズ、今回で最終回…の予定です。(何かネタがあったら続きを書くかもしれません)
※「番外編」の記事を書く予定はあります。そこで別のEA開発やインジケーター作成、メール送信など解説予定です。
さて、デバッグについてですがMetaTrader4にはデバッグ機能があります。(昔はありませんでした!)
まずはMetaTrader4のデバッグ機能からみていきましょう。
MetaTrader4のデバッグ機能
デバッグ機能が実装されたときに少し触ってみたのですが、使い方がわからず放置した記憶があります。(まだ兼業だった頃の話です)
それもそもはずで「土日は動かない」というサラリーマン(兼業)トレーダーには致命的ともいえる欠陥が…!(MetaQuotes社からすれば仕様どおりでしょうけど、主に土日に作業したい日曜プログラマーにはあまりにも辛い仕様です…)
また、このデバッグ機能は「バックテストでは使用できない」という制限があり、「バックテスト中に何か問題が発生している」という状況の調査には役に立ちません。
バックテストで使えれば「土日は動かない」という問題も解決できるのですけど。非常に残念です…
しかし、非常に便利な機能ですから市場が動いている時間帯であれば利用しない手はありません。
デバッグの設定
上部メニューのツール(Tools)>オプション(Options)のデバッグ(Debug)タブで設定します。
ここで通貨ペアや時間軸、初期証拠金(Deposit)やレバレッジが設定できます。
期間等もありますがヒストリカルデータでバックテストできないので設定しても意味はありません。
(ヒストリカルデータでのバックテストはMT5でサポートされている機能で、MT4では動作しません…)
デバッグの手順
問題のあるプログラムをみて「どこがおかしい(可能性がある)」のかアタリをつけます。
そして処理の一番最初の行にカーソルを当てて「ブレークポイント」を置きましょう。
上部メニューのデバッグ(Debug)>Toggle Breakpoint もしくは F9キーです。(ショートカットが便利ですので、ショートカットの方を覚えましょう!)
ブレークポイントを解除する場合もF9キーです。
「どこでおかしくなるのか分からない!」場合にはOnInit関数の最初にブレークポイントを置いてもOKです。
ブレークポイントが設置されると青丸が表示されます。これでOKです。
複数も可能ですので必要な箇所に設置しましょう。
デバッグ実行
実行はF5キーです。ポチッと押してみてください。
EAのパラメーター設定画面が出てきますので適当に設定してOKを押下します。
画面がソースコード(MetaEditor)に切り替わって、先ほどの青丸のところに緑の矢印が表示されています。
それではデバッグしてみましょう。
停止した箇所の上にあるMACDやMAを取得している変数値を確認してみます。
変数を選択(変数の上でダブルクリック)して右クリックメニューを表示し、Add Watchを選択します。(Shift+F9でOKです)
するとツールボックスウィンドウ(通常、下部に表示)に「変数名」「変数の中身(値)」「変数の型」が表示されます。
MaPreviousの値が確認できました。(後で使うので「total」も追加しています。totalは「現在のポジション数」が入っています。)
「稼働中の変数の中身」をチェックしたい場合にはこの「ウォッチ」を使います。
なお、OnInitはEAが開始する直前、OnDeInitはEAが終了する直前、そしてOnTickは「リアルでティックが動いた時」に実行されます。(ティックの動きが鈍い時にはすぐに実行されません…。ティックが動くまで待ちましょう…。)
取得できるデータはリアル(現在)値のみです。
1行ずつ実行する(ステップイン)
次に1行ずつ実行してみます。F11キーを押しましょう。
1行実行されて緑の矢印が動きました。
先ほどウォッチで確認したとおりtotalは0でしたからifの条件どおりですね。
後はおかしくなるところはどこか、1行ずつ動かしながら見ていくだけです!!
ちなみにF5キーをもう一度押せば、最後まで処理をした後、もう一度先ほどのブレークポイントで止まります。(その時のティックデータに更新されています)
上記の例で「totalが1以上の場合の動作確認がしたい」場合にはMT4で発注すればOKです。(EA側でMagicナンバーのチェックをしていると思いますので、手動で発注した場合と同じ0をMagicナンバーに指定しておきましょう。こうすれば手動発注をEAの発注と認識させることができます。)
基本的なデバッグ機能の使い方は以上です。
一応、その他の機能について簡単に書いておきますと「F10」をクリックすると「ステップオーバー」です。ステップ実行(F11)すると「自作関数の中も1行ずつ実行」しますが、「この関数の中はチェックしなくても良い(飛ばしていい)」という場合に「F10」キーで関数実行を飛ばせます。
「Shift+F11」はステップアウトで「現在実行中の関数のみ」飛ばします。
デバッグの中止は「Shift+F5」です。一旦、中止しないとコンパイルできません。なにか修正した場合には停止・コンパイルしてから再実行してください。
伝統的なPrintデバッグ
伝統的なデバッグ手法「Printデバッグ(C言語でいうところのprintfデバッグ)」について解説します。
MT4にはデバッグ機能があり「変数の中身」や「動作状況」が確認できますが、最初に記載したように「バックテストで使用できない」という制限があるため、「バックテストでなければ再現できない問題」や「土日に問題解決したい場合」には使えません。
そこで、(やむおえず)この古き伝統的な手法に頼ることになります…。
先ほど同様、MAPreviousとtotalの変数値をチェックしてみましょう。
Print("MaPrevious = " + MaPrevious); Print("total = " + total);
このように変数値をPrint関数でログに出力します。
「ここ、本当に通っているのかな…?」という場合にもPrint文で適当な文章を出力することで確認できます。
if(hensu==hogehoge) { Print("通ってるのかな?"); ・ ・ ・ }
必要に応じて「デバッグ用のコードを書く」手段もあります。
//変数(hensu)が10より大きくなっているかどうか調べるよ if(hensu > 10) { Print("10より大きくなることがあるよ = " + hensu); }
面倒ですが、たいていの問題はデバッグ用コードを書けば調べられます。(MetaTrader4のデバッグ機能を使う場合もデバッグ用コードを書き足して実行する手段は有効です。)
まとめ
MetaTrader4のデバッグ機能と、伝統のPrintデバッグについて解説しました。
状況に応じて使い分けてください。ちなみにPrintデバッグではログが長くなりすぎて問題解決できない場合にはファイルに出力する方法もあります。(私はMT4で「デバッグ用のログファイル」を作成したことはありませんから、使うことは稀だと思います。)
これで「ゼロから始めるEA開発」は終了となります。ご愛読ありがとうございました!(Part10までやりたかったのですが、ネタが思い浮かばなかったのです…)
もし「ゼロから始めるEA開発」として「こういうのをやってほしい!」というご要望がありましたらコメント等にお願いします。
次回について
次回は「自動売買システムを作ろう! 番外編その1」として「(今まで作ってきた物とは別の)自動売買システム」を作ってみます。
コメント
バックテストでデバッグ機能が使えないなんて本当に不便ですよね
これだけは直して欲しい
お世話になっております。
ヒストリカルデータを用いてテスターを実施した際のデバックは出来ないという認識でよろしいでしょうか。
例えばコードの中にPrint(“テキスト”);が必ず通るように記載した場合どこかに出力されるのか、もしくは出力する方法があるのかなと思いコメントしました。
何卒宜しくお願いいたします。
MT4ではデバッグ機能が使えませんが、Printで出力したものはログに出ます。
デバッグしたい場合にはこれくらいしか方法が無いと思います。
お世話になっております。
ご連絡が遅れて申し訳ありません。
承知いたしました。
ありがとうございます。
度々申し訳ございません。
本記事とは異なる質問にはなってしまうのですが教えて頂けたら幸いです。
現在EAを作成しており。
前回約定価格から比較して金額が下がっていれば注文するというコードを作成しています。
イメージとしてはif(Bid < 前回注文約定価格){ 注文処理 }としています。
仮にBidが108.400、前回が108,410でtrueとなりif分を通った直後に注文処理を入れていても注文処理の約定価格がif内の条件と矛盾した価格(108.420)とBidからかなり離れてしまいます。
どのような対策が有効でしょうか。
大変申し訳ございませんがよろしくお願いします。
一番考えられるのはプログラムのミスです。
本当に想定した動きになっているのかどうか‥。
あとはスプレッドの問題とかは無いですかね‥?
BidでBuyを入れてもうまくいかないかも知れません。
疑問が晴れなければここではなく、どこかの質問サイトや掲示板サイト等に投稿された方が良いかと思います。
emija様
ご返答ありがとうございます。
無事解決できました、約定価格はスプレッドを含んでいない価格と勘違いしていました。
ありがとうございました。