[EA・プログラム] 稼働中のEAがチャートから外れる最恐のエラー
こんにちは。2payです。
今回もEAにまつわる小話です。
皆さんは稼働中のEAが急に外れた経験はないでしょうか?
EAによるポジションが立った後で、EAがチャートから勝手に外れ、ポジションが制御できなくなるケースが稀に起こっているようです。
EAが異常に陥った時、操作履歴かエキスパートログにエラーが表示されます。
今回テーマに掲げている最恐のエラーは「array out of range」です。
配列外アクセスした際に生じるエラーの事で、これが発生するとプログラムが強制停止します。
インジケータの場合はチャートに残っているものの、計算処理が行われず何も表示されません。
そしてEAの場合はプログラムごとチャートから外されます。
エラー時に何か通知を飛ばしてくれるわけでも無いため、寝ている時や出先等、気づかないタイミングでしれっと外れ、だれも制御していないポジションはとんでもない損益を叩き出します。
異常に気づいたEAの利用者は状況が理解できず、ポジションを切るべきかどうか悩みます。
再度EAをセットしようとしても同様のエラーで繰り返し弾かれたりするわけです。
どういう時に発生するのでしょうか?
それを理解するには配列について知る必要があります。(以下は少しかみ砕いた表現を使用します。)
配列とは連続した変数のようなものです。
プログラムにおける変数とは、好きな名前を付けられて、データ(数字や文字)を格納できる箱です。
"a"という名前の箱に数字の"1"を代入(格納)する場合、
a=1 と表記することで、aの箱の中に1という数字を格納することができます。
反対に箱"a"の中身を知りたい時は
Print(a) 等と表記します。( "Print()" はログに結果を出力する命令(関数)です。 )
するとログには "1" と表示が出ます。
"a" のような箱を大量に用意する場合、 "b" "c" ... と作っても良いのですが、100個とか必要になると変数名を考えるのが大変です。
そこで "a" をシリーズとして扱えるように配列化させます。
a[100] と表記することで、
aの0番から99番までの100個の変数aを用意出来ました。 (mql言語では配列は0番からスタートします。)
100個の変数にはそれぞれ異なる数字を代入することができます。
a[0]=1
a[1]=25
a[99]=-10
と言った具合です。
ここで、
a[250]=45
と表記するとどうでしょう。
aの配列は先ほど100個(99番まで)しか作成しませんでした。
存在しない250番に数字を代入することは可能でしょうか?
答えは 出来ません。
なぜなら配列範囲(0~99)外の番号を指定しているからです。
これがarray out of rangeです。
ソース内で配列が使われるものの中で代表的なものは4本値です。
終値は "close[]" と定義されていて、配列範囲はチャートに表示されているバー数と一致します。
4本値のような時系列順で並んでいる配列を "時系列配列" と呼びます。
通常、[0](=0番) が現在足で、一番古い足が最も大きい値 [バー数-1] となります。
例えばチャートバー数が3000本の時、3000本より過去にあたる close[4500]にアクセスすれば、範囲外の為エラーが発生します。
EAやインジケータで、何かしらの指標を算出するために最低でも3000本遡って計算させる必要がある場合、開発者は計算を開始する足を[2999]と定め、[0]までカウントダウンします。
ここで大事なのはユーザー側で、それに応じられるようにチャート本数を3000本以上表示しておく必要があるということです。
開発側からの指定がある場合は指示に従いましょう。
もちろん開発側もこれは対策を取るべきです。
何かの拍子にユーザーがバー数を変更することもあるため、配列エラーを起こす前に配列範囲が不足していないか、または誤った指定をしていないか確認し、バー数を増やすことを促せるようなアラートを入れてユーザーに気づいてもらうための工夫をした方が良いでしょう。
実際の記述においては、エレメント(配列の要素番号)に直接数字を入れることは少なく、一般的に変数で指定します。
close[a]
こうすることで記述上の利便性が上がりますが、aの中身が何であるか外部に出力してみないとどこで詰まったのか分からなくなります。
以下の条件はcloseの配列範囲内である場合のみ出力を可能にする条件文です。 配列サイズよりaが小さい値でなければ close[a] の出力は実行されません。
if( ArraySize(close)-1 > a ){
Print( close[a] ); }
大規模なループの中で実行する場合は ArraySize(close)はループ外部で変数に代入し、ループ内で何度も関数を呼び出さないようにしましょう。
私も勉強を始めたての頃は何でこのエラーが起きているかさっぱり分からず、仕組みを理解するのにも結構苦労した覚えがあります。
それでも開発に携わる以上は必須で、基本的にarray out of rangeが出ないようにエラー回避処理を施さないといけません。
今回のお話はここまでです。
読んで頂きありがとうございました。
Is it OK?