MetaEditorを使ったデバッグ方法について紹介します。
MetaEditorにはデバッグ機能が付いており、それを使ってデバッグをしていくことになります。MT4の MetaEditorのデバッグでは、現在の実データで動作を確認していくことになります。必ずデモ口座で行なうようにしてください。
※週末など相場が動いていない時は価格変動がないため MetaEditorを使ったデバッグ処理はできません。
デバッグツールの基本操作
デバッグツールボタン
❶ 開いているファイルをコンパイル
現在開いているプログラムをコンパイルして mq4ファイルから ex4ファイルに変換されます。(プログラムが EAの場合、変換前後のファイルはこちらに保存されます)この時、構文エラー(警告含む)があれば表示されます。警告(warnings)が出てもコンパイルは出来ますが、必ず警告も無くすようにしてください。
➋ 実データでデバッグをスタート
現在の相場を用いてデバッグを行ないます。ブレイクポイントを設置していればプログラムはそこで止まります。ですのでデバッグをスタートする前にブレイクポイントを設置してください。
ブレイクポイントはブレイクポイントを置きたい行で右クリックして「ブレイクポイントのオンオフ」にするか、左側にある数字の上でダブルクリックをするとブレイクポイントのオンオフの切替ができます。
➌ デバッグの一時停止
処理時間が長い時、ループに入って抜け出せない時に一時停止して現在のプログラムの実行位置を確認できます。プログラムが止まっている位置には➡が付きます。
➍ デバッグの停止
デバッグを終了します。
➎ ステップイン
プログラムを一行ずつ進めていきます。(➡が付きます) 途中に関数が有る場合は、その関数の中へ移動します。
➏ ステップオーバー
プログラムを一行ずつ進めていきます。(➡が付きます) 途中に関数が有る場合でも、その関数中へは移動せず、関数の処理が終わったとして次の行のプログラムへ進みます。
➐ ステップアウト
次のブレイクポイントまでプログラムを進めます。
変数の状態の確認
デバッグ中のプログラムの変数の状態(現在の変数の値)を確認することが出来ます。
ブレイクポイントを設置後、デバッグをスタートさせてください。ブレイクポイントでストップした所で、確認したい変数を選択して右クリック→「ウォッチの追加」で変数を確認することができるようになります。
MetaEditor のデバッグ処理
「買いのみトラリピEA」エラー無し
比較用に「買いのみトラリピEA」使います。まずエラーがないもので試してみましょう。「買いのみトラリピEA」のコードをコピペしてデバッグするようにします。
コンパイルしてブレイクポイントを「int coe = 1;」と「ticket = OrderSend(…」の行の2ヵ所に置いてください。
「➋ 実データでデバッグをスタート」押してデバッグをスタートさせてください。
「パラメーターの入力」が表示されるので「取引最大値(各通貨単位)」をデバッグする通貨ペアの現在値より少しだけ高い値に設定して OKボタンを押すとデバッグが開始されます。
今回の場合、USDJPYを対象にしてデバッグを行なっており、現在値が 142円台なので「取引最大値(各通貨単位)」を 143円とします。
最初のブレイクポイントで止まります。ここで、変数の状態を確認するため、確認する変数を選択して「ウォッチの追加」をしていきます。
今回は、「i」「openPrice」「magicNumber」「ticket」「tradeType」を見ていきます。それぞれの変数は以下の意味を持ちます。
変数名 | データ型 | 説明 |
---|---|---|
i | int | パラメーターで設定した「トラップ数(個)」の変数です。この変数は「openPrice」や「magicNumber」に比例します。 |
openPrice | double | 新規取引するときの指値(or 逆指値)価格を表す変数です。 |
magicNumber | int | 各ポジションに付与されるこちらで設定した番号(マジックナンバー)の変数です。各ポジションに番号を付与することで現在ポジションとして既に確立しているか識別します。重複した注文をしないためにマジックナンバーで識別させます。 |
ticket | int | 予約注文した時に自動付与される整数で 1以上のチケット番号を表す変数です。任意のポジションで注文がまだ確立されていない時、既にそのポジションが決済されてポジションが無い時は -1になるようにプログラムで設定されています。 |
tradeType | int | 注文する時の方法を表す変数です。「指値買い注文」「逆指値買い注文」かを見ています。値と注文IDの対応はこちらの表を参考にしてください。 |
「➐ ステップアウト」ボタンを押して次のブレイクポイント「ticket = OrderSend(…」まで移動します。すると、その時の各変数の値が表示されます。
確認したら「➐ ステップアウト」ボタンを押して次に行きます。すると➡が一周して再び元の位置に戻ってきて変数が入れ替わっているのが確認できます。
ここまで命令が届いているものは、変数の内容に沿って指値注文(又は逆指値注文)がされていくことになります。
更に、「➐ ステップアウト」ボタンを順次押していくと変数の数字も順次変わっていきます。十数回程度押すと各変数は最初の数字に戻ります。
今回は、デバッグで自動売買を許可していないため注文(ポジション or オーダー)が存在しないので再び指値注文命令を出してしまうことになります。
デバッグでも自動売買が許可されている場合は、実際にデモで指値注文が発生するので最初の 1週目で注文(ポジション or オーダー)が存在して、2週目以降は注文(ポジション or オーダー)が存在している間は指値注文の命令は出されないようになっています。
変数iが一周したら一通りの命令が終わったと判断して良いです。
自動売買の許可についてはこちらを参考にしてください。
以上、正常時の動作確認です。
「買いのみトラリピEA」エラー有り
次の「買いのみトラリピEAバグ有」のコードはエラーを仕込んでいますので、MetaEditorへコピペしてコンパイルしてください。
// BuyOnlyTraripEA-bug.mq4(買いのみトラリピEAバグ有 フランのなるほどMT4)
//★1.初期設定値の決定★★★★★★★★★★★★
#property strict
extern double lots = 0.01; // ロット数
extern double maxPrice = 100.0; // 取引最大値(各通貨単位)
extern int trapsu = 100; // トラップ数(個)
extern int profitPips = 100; // 利益幅(Pips)
extern int trapIntervalPips = 50; // トラップ幅(Pips)
extern int slippage = 3; // スリッページ(Pips)
extern int magic = 1001; // マジックナンバー
extern int orderRangePips = 100; // 指値注文範囲(Pips)
int slippagePips; // スリッページの単位をPipsからPointへ変換した変数
double PipsPerCunit; // 1Pipsあたり各国通貨単位に変換する係数
int i, j, ticket; // i:トラップ数計数用の変数, j:ポジション数計数用の変数, ticket:チケットNoの変数
//★2.初期処理★★★★★★★★★★★★★★★★
void OnInit() { // 初期処理
int coe = 1; // 2,4桁表示業者の場合の係数は「1」
if(_Digits == 3 || _Digits == 5) { // 3,5桁表示業者の場合の係数は「10」
coe = 10;
}
PipsPerCunit = _Point * coe; // 1Pipsあたりを各国通貨単位に変換する係数
slippagePips = slippage * coe; // スリッページの単位をPipsからPointへ変換
}
//★3.終了処理★★★★★★★★★★★★★★★★
void OnDeinit(const int reason) { //終了処理
ObjectsDeleteAll(); // オブジェクトテキストをEA削除時消すための処理
}
//★4.レート変動毎の処理★★★★★★★★★★★
void OnTick() { //レート変動毎の処理
for(i=0; i < trapsu; i++){
//●4.①注文範囲内かのチェック●●●●●●●●
double openPrice = maxPrice - trapIntervalPips * i * PipsPerCunit;
RefreshRates();
double currentPrice = Ask;
if( orderRangePips != 0 && (openPrice < currentPrice - orderRangePips * PipsPerCunit || openPrice > currentPrice + orderRangePips * PipsPerCunit) ){
continue; // 現在値が指値注文範囲より乖離した注文は出さない
}
//●4.②決済価格とマジックナンバーの設定●●●
//注文範囲内に入ったので処理を続行
double closePrice = openPrice + profitPips * PipsPerCunit; //イフダン注文の決済価格を設定
int magicNumber = magic + i;
//●4.③注文有無のチェック●●●●●●●●●●
ticket = -1; // 既に注文orポジション化されているかチェック。無しの時、ticket=-1。
for(i=0; i < OrdersTotal(); i++) {
if(OrderSelect(i, SELECT_BY_POS) == false) {
break;
}
if(magicNumber == OrderMagicNumber() && OrderSymbol() == _Symbol) {
ticket = OrderTicket();
break;
}
}
//●4.④注文無しの時は注文する●●●●●●●●
if (ticket <= 0) { // 注文がなければ(ticket=-1の時)リピートする
int tradeType; // 注文形式を決定する
if(openPrice <= Ask) {
tradeType = OP_BUYLIMIT; // 指値 <= 現在価格(Ask) の時、買い指値注文
} else {
tradeType = OP_BUYSTOP; // 指値 > 現在価格(Ask) の時、買い逆指値注文
}
openPrice = NormalizeDouble(openPrice, Digits); //指値価格の有効桁丸め
closePrice = NormalizeDouble(closePrice, Digits); //決済価格の有効桁丸め
ticket = OrderSend(Symbol(), tradeType, lots, openPrice, slippagePips, 0, closePrice, "B_T_EA:" + (string)magicNumber, magicNumber, 0, clrNONE); //イフダン注文
}
}
}
コンパイルしてもエラーは発生しません。
この「買いのみトラリピEAバグ有」を先ほどと同様にブレイクポイントを設定、「ウォッチの追加」をしてデバッグを実行(自動売買の許可はしない)してください。
ticketまで来て、順次「➐ ステップアウト」ボタン押すと次のようになります。(※例です。デバッグする時の相場によって変数の値は変わってきます)
変数は変わらないです。通常であれば、変数iをはじめ、一周するまで順次値が変わっていきますが、そのようにはなりません。どこかに問題があることが分かります。
次に、変数の変化の状況を知りたい箇所にブレイクポイントを追加で設置します。
今回であれば、❶「ticket = -1;」と ➋「if (ticket <= 0) {…」のところにブレイクポイントを設置すると良いです。気になる箇所があれば、ブレイクポイントはどこに打っても良いです。
これで各変数の変化を見ていくと変数iが 0と 1を繰り返していることが分かります。
変数iは一定の範囲で番号を繰り返すことになるはずなので 0と 1を繰り返す原因を調べます。
「➐ ステップアウト」ボタンを押していくと❶➋の間で 1から 0に戻されていることが分かります。
すると❶➋の間に原因があることになるので、コードを確認すると、今回の場合、「原因のfor文」の所で変数i以外を使用しなければならないところ同じ変数iを使用していました。
これが原因で変数iが初期化され次のマジックナンバーに行けなかったことが分かります。
これを修正して、変数iを変数jに変えて再度デバッグを実行すると、順次変数が変わり正常に動いていることが分かりました。
デバッグ処理完了です。
以上、MetaEditorのデバッグ作業でしたが、MT4の場合、実データでしかデバッグ作業ができないので実用的ではない面があります。
作成した EAをストラテジーテスターのデバッグとデモ口座で一定期間動かしてみて最終確認として MetaEditorでのデバッグ処理をすると良いです。
また、EAプログラムにスプレッドやスワップの変化を含む場合はストラテジーテスターのデバッグでは出来ないのでそのような時は MetaEditorでのデバッグの出番です。
今回は、比較用としてエラーがない EAと比べることが出来ましたが、実際はこのようなことは出来ません。
しかし、皆さんがプログラムを組む時は必ず変数の変化の状況を考えてプログラムを組んでいるので変数などの変化を追いかけていけばエラーの箇所にたどり着きます。(変数の変化を考えないとプログラムを組むことはできません!)
プログラムは数千、数万行のように長くなることもありますので、エラー処理、修正などを考えて、コメントを入れた分かり易い(読み易い)整理されたプログラムを書くことを心掛けてください。