2009/06/20

自作指標のバグ取り作業


新たに指標を自作した際に付きまとう厄介なバグの修正作業!に注目してみました。
コンパイルは、出来たものの表示されない!MT4が、動かなくなったなど数多く経験されていると思います。
今回は、コンパイル完了後のバグについて記載しておきます。
まず、MT4がフリーズしてしまった時の作業です。
『MT4フリーズ時の脱出方法』
①Windowsタスクマネージャーの呼び出し【XPの場合(CTRL)+(ALT)+(DELETE)】
②(プロセス)→terminal.exeの選択→(プロセスの終了)
③原因の指標の変更
④MT4の起動(再度フリーズの場合は、①に戻る)
A)MT4がフリーズしてしまう場合
①無限ループに陥っている。
※ループ条件の脱出条件が未定の場合に発生します。
よくある?(私がよくする間違い)
例1:
while(i >= 0)
{
************************************
i--;※この条件を忘れてしまう!もしくは、符号を間違える。
}
例2:
For(i=0,k=0;i<100;k++){********************}
※iを終了条件にしているにも関わらず、k++となっており、i++がない場合
※こんなことするわけがないとお思いでしょうが、ループが2重、3重になると意外に多いものです。(私の場合・・・)
除算の分母に0(ゼロ)を代入した場合
※多くは、一端フリーズ状態を経て指標を表示せずMT4が起動して、バーの更新があると最新の指標を表示するなどの症状になります。
※除算の分母に変数を用いる場合は、初期条件に、ゼロを否定する条件を入れたほうが問題の発生を低減させることができます。
例)
Double A =0;
Double B =0;
A = Volume[0];
If(A!=0) B = 10/A;※このようにしておけばゼロエラーが回避できます。
B)指標が表示されない場合(すべては掲示出ませんが・・・)
①基本事項の確認をしてみる
 ・大域での宣言に間違いがないか?(#property indicator_buffers 1 #property indicator_color1 Red など・・・・)
 ※indicator_buffers Xは、表示する指標の個数になっていますか?など
 ・初期関数部(int init())の設定に間違いはないか?(SetIndexStyle(0,DRAW_LINE); SetIndexShift(0,MA_Shift); など・・・・・)
 ※非表示の時系列配列(計算用の時系列配列)も初期関数部でのセットが必要です。
②存在しないものを元に計算処理させた場合
・移動平均を再度平均化処理する場合などに、発生する可能性があります。
C)実際に例を元に、バグ取りを行ってみます。
例)終値を単純移動平均(SMA10)し、再度、単純平均する(SMA10)するコードを以下に示します。
このコードは、コンパイルエラーは起こらず、エラーを含んだコードです。(何個エラーがあるでしょうか?)
//+------------------------------------------------------------------+
1:#property indicator_chart_window
2:#property indicator_buffers 1
3:#property indicator_color1 Gold
4:extern int SMAPeriod = 10;
//---- buffers
5:double SMA[];
6:double SMASMA[];
//| Custom indicator initialization function |
7:int init()
8: {
9: IndicatorBuffers(2);
10: SetIndexStyle(1,DRAW_LINE);
11: SetIndexBuffer(1,SMASMA);
12: SetIndexStyle(2,DRAW_NONE);
13: SetIndexBuffer(2,SMA);
14: return(0);
15: }
//| Custom indicator deinitialization function |
16:int deinit()
17: {
18: return(0);
19 }
//| Custom indicator iteration function |
20:int start()
21: {
22: int CountedBars = IndicatorCounted();
23: int i = Bars-SMAPeriod-1;
24: if(CountedBars>0)i=Bars-CountedBars;
25: while(i >= 0)
26: {
27: SMA[i] = iMA(NULL,0,SMAPeriod,0,MODE_SMA,MODE_CLOSE,i);
28: SMASMA[i] = iMAOnArray(SMA,0,SMAPeriod,0,MODE_SMA,i);
29: i++;
30: }
31: return(0);
32: }
//+------------------------------------------------------------------+
※上記コードを用いて、バグ取り手順(素人の自己流なので、ベストな方法か疑問が残りますが・・・・)の説明
①何はともあれ、一度稼働させてみる。
 ※上記コード自体を稼働させないでください。(PCがフリーズします。)
②上記コードを稼働させたところ、PCがフリーズしたため、上記『MT4がフリーズした場合の脱出方法』を元に、脱出し、ループ関数を確認してみる。
A:29:行目【 i++;】が無限ループの原因と発覚!【i--;】 に変更、再度稼働。
B:再稼働後、MT4はフリーズから脱出したが、指標が表示されず。
③1:行目のコードをコメント化【//#property indicator_chart_window】2:行目の上に【#property indicator_separate_window】を記入。
 ※指標をサブウインドウで表示させることで、今後の確認作業を簡素化するためです。(この例ではほとんど関係ありませんが・・・)
④指標表示用配列(上記コードの場合SMASMA[ ]:) にiを代入【28:行目SMASMA[i] = i: //iMAOnArray(SMA,0,SMAPeriod,0,MODE_SMA,i);】し再稼働してみる。
 A:この状態で再稼働させても、指標が表示されないため、初期設定を疑う。
 B:初期設定確認時に、10:行目から13:行目にエラーコード発見、下記のように変更。
9: IndicatorBuffers(2);
10: SetIndexStyle(0,DRAW_LINE);
11: SetIndexBuffer(0,SMASMA);
12: SetIndexStyle(1,DRAW_NONE);
13: SetIndexBuffer(1,SMA);
 ※ちなみに、【SetIndexBuffer(A,B)】とは、配列(名前B[ ])をバーが更新するたびに、更新してくれる機能(バッファ)を持たせるというものです。
  例)【B[0] =5 B[1]=4 B[2]=3】の場合、新規バーが発生すると、【B[0] =新規 B[1] =5 B[2] =4 B[3] =3】になります。
  また、SetIndexBuffer(バッファ)の設定は、8つまで持つことができます。Aは、その番号です。(ただし、A=0~7です。)
  番号の割り当ては、0から始めなければならないお約束があります。
  つまり、元のコード(エラーコード)を訳すと!
   9行目 2つのバッファを設定します。
  10行目 バッファ1は、線表記を設定 (本来は、バッファ0にセットしなければなりません。)
11行目 バッファ1に配列名SMASMAをセット(本来は、バッファ0にセットしなければなりません。)
  12行目 バッファ2は、表記しません。(本来は、バッファ1にセットしなければなりません。)
13行目 バッファ2に配列名SMAをセット(本来は、バッファ1にセットしなければなりません。)
  こんな感じです。
  つまり、ここでエラーが発生していたことになります。
 C:再稼働後、右肩下がりの指標が現れる。④で変更したコードを元に戻す。【28:行目SMASMA[i] =iMAOnArray(SMA,0,SMAPeriod,0,MODE_SMA,i);】コンパイル後再稼働
 D:再度指標が表示されなくなる。
⑤前処理用の配列(バッファ)【SMA[ ]】が機能しているか確認してみる。コード変更【28:行目SMASMA[i] = SMA[i] ; //iMAOnArray(SMA,0,SMAPeriod,0,MODE_SMA,i);】
  A:コンパイル後、再稼働!指標が表示されていることを確認
  B:上記記載『B)② 存在しない配列を元に計算処理させた場合』が考えられるので、ループを別にしてみる。
int start()
{
int k;(新規ループ用に追加)
int CountedBars = IndicatorCounted();
int i = Bars-SMAPeriod-1;
k = i-SMAPeriod; (新規ループ用に追加)
if(CountedBars>0){i=Bars-CountedBars-SMAPeriod;k=i;} (新規ループ用に追加)
while(i >= 0)
{
SMA[i]=iMA(NULL,0,SMAPeriod,0,MODE_SMA,MODE_CLOSE,i);
i--;
}
while(k >= 0)
{
SMASMA[k] =iMAOnArray(SMA,0,SMAPeriod,0,MODE_SMA,k);
k--;
}
return(0);
}
⑥コンパイル後再稼働で指標が表示された。③で変更した部分を元に戻し終了です。(バグ取り完了)お疲れさまでした!
D)作成した指標が予定通り稼働しているか確認する。
 ※これが一番厄介なことです。なぜなら、実際のデータで指標を動かしても、自分の考え通りなのか不明確であることが多いためです。
 そのため、サンプルデータを用いて確認する方法があります。
 添付ファイルは、適当に作ったサンプルデータ(日足用)です。不要なシンボルに組み込んでみてください。
 以下のようなチャートが現れるはずです。(わかっているとは思いますが、指標は別です。)

ご参考までに!
追記
『今年中にMT5が発表予定!』とか、『金融庁によるレバ規制!』とか、今後目まぐるしく変化することと思います。
やなぎのごとく柔軟に対応できるチカラ!を持ちたいものです!では・・・