様々な状況でのEAの挙動に注意する
ストラテジーテスターだけでは、EAを適用した後にどんな挙動をするか把握しきることはできない。
フォワードテストで成績が悪いとかそういう話ではなく、EAの仕様の関係で意図しない挙動をしないように制御してあげる必要がある。
グローバル変数の中身
EAのイベントハンドラのひとつにOnInitがある。
”Init”は初期化を意味しているので、OnInitはEAの初期化処理という認識になるが、何がどう初期化なのかを確認する。
OnInitがコールされるのは、EAを適用した時、EA適用中に入力パラメータを変更した時、EA適用中に時間足を変更した時などが挙げられる。
下記のEAを用意する。
#property copyright "" #property link "" #property version "1.00" #property strict input int mode=0; int state=0; int OnInit(){ Print(state); state++; return(INIT_SUCCEEDED); }
OnInitが実行されると、グローバル変数stateを表示してからインクリメントする。
このEAを適用してみる。
EA適用時にOnInitがコールされ、”0”、”initialized”の順に表示される。
続いて、時間足を変更してみる。
OnInitがコールされ、”1”、”initialized”の順に表示される。
グローバル変数stateの中身は保持されていることが分かる。
続いて、適用中のEAの入力パラメータを変更してみる。
OnInitがコールされ、”2”、”initialized”の順に表示される。
ここでもグローバル変数stateは保持されている。
続いて、同じEAをドラッグ&ドロップで再適用してみる。
適用中のEAがremoveされた後、OnInitがコールされ、”0”、”initialized”の順に表示される。
一度removeされているのでグローバル変数stateの中身も初期化されていることが分かる。
時間足変更時にグローバル変数の中身を初期化したいならOnInit(またはOnDeinit)に記述する事になる。
初期化するかどうかはそのグローバル変数の使い方による。
例えば、そのEAが適用されているチャートの時間足設定に準じたトレードを行う仕様なら(MQL4でのClose配列などを使うなら)、初期化すべき変数がいくつか宣言されているかもしれない。
自動売買/アルゴリズム取引をOFFにするとEAはどうなるか
MT4/5にある自動売買(MT4)/アルゴリズム取引(MT5)をOFFにすると、EAはどのような状態になるかを確認する。
下記のEAを用意する(MQL4)。
#property copyright "" #property link "" #property version "1.00" #property strict int state=0; datetime time=0; int OnInit(){ return(INIT_SUCCEEDED); } void OnTick(){ if(time!=Time[0]){ time=Time[0]; if(state==0){ double ma1=iMA(Symbol(),Period(),5,0,MODE_SMA,PRICE_CLOSE,1); double ma1Prev=iMA(Symbol(),Period(),5,0,MODE_SMA,PRICE_CLOSE,2); double ma2=iMA(Symbol(),Period(),20,0,MODE_SMA,PRICE_CLOSE,1); double ma2Prev=iMA(Symbol(),Period(),20,0,MODE_SMA,PRICE_CLOSE,2); if(ma1>ma2 && ma1Prev<ma2Prev){ state=1; Print("state: 0 -> 1"); return; } } } if(state==1){ double ma1=iMA(Symbol(),Period(),5,0,MODE_SMA,PRICE_CLOSE,0); double ma2=iMA(Symbol(),Period(),20,0,MODE_SMA,PRICE_CLOSE,0); if(Bid<=ma1 && Bid>ma2){ Print("エントリー条件達成"); if(OrderSend(Symbol(),OP_BUY,0.1,Ask,3,0,0,NULL,12345)<0){ Print("約定失敗"); return; }else{ Print("約定成功"); state=2; Print("state: 1 -> 2"); return; } }else if(Bid<ma2){ state=0; Print("state: 1 -> 0"); return; } } if(state==2){ double ma=iMA(Symbol(),Period(),20,0,MODE_SMA,PRICE_CLOSE,0); int total=OrdersTotal(); for(int i=total-1;i>=0;i--){ if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false)break; if(OrderMagicNumber()!=12345)continue; if(OrderSymbol()!=Symbol())continue; if(Bid<=ma){ if(OrderClose(OrderTicket(),OrderLots(),Bid,3)){ state=0; Print("state: 2 -> 0"); return; }else{ Print("決済失敗"); return; } } } } }
- グローバル変数stateを初期値0で用意する。
- stateが0の時、各バーの始値のティック時点で5SMAと20SMAを用意し、ゴールデンクロスを確認したらstateを1に変更する。
- stateが1の時、各ティックの度に5SMAと20SMAを用意し、Bidが5SMA以下かつ20SMAより大きければロングエントリーし、約定したらstateを2に変更する。
もしBidが既に20SMAを下回っていたらstateを0に変更する。 - stateが2の時、各ティックの度に20SMAを用意し、Bidが20SMA以下だったらポジションを決済してstateを0に変更する。
state変更のタイミングで、ログを出している。
このEAをチャートに適用し、自動売買をOFFにしておく。
EAは稼働を続けている。
エントリー条件を満たし、OrderSendが初めて実行されたタイミングで”trade operations not allowed by settings”が表示され、エントリー処理が制限されていることが分かる。
(エントリーが失敗した時と同様に、OrderSendの戻り値がマイナスになっていることも確認できる)
MQL5ならTerminalInfoInteger(TERMINAL_TRADE_ALLOWED)、MQL4ならIsTradeAllowed()を用いて、自動売買が許可されているかどうか検査し、処理を分岐させると良い。
PCがスリープするとEAはどうなるか
PCがスリープすると、EAはどのような状態になるか確認する。
前述のEAを適用(自動売買はON)して、PCをスリープさせる。
暫く時間を置いてからPCのスリープを解除する。
これに関しては特に画像を貼らないが、スリープしている間EAは全く動いていないため、当然stateの変更ログを含め一切のログは出力されない。
またスリープ&解除はPCの状態であり、MQLにこのためのイベントハンドラというのは存在しない。
スリープする直前のstateがスリープ解除後に引き継がれることになる。
なお、会社など人のいる場所でWindowsを使っている人は良くやると思うが、PCのロック(ショートカットキーならWindowsキー+L)状態は、通常時と同じでEAは問題なく稼働する。
上記のことから、EAを稼働する場合は、PCのスリープ設定をなしに変更し、原則EAを適用したチャートをいじらない方が無難だ。
EAを作成して他人に使用させる場合は、使用者に上記のような注意喚起をすると共に、万が一スリープしてしまっていた場合であっても意図しないエントリーが行われないような制御が必要になる。
前述のようなEAであれば、例えばstate変更時点のdatetimeを保持し、次のアクションを起こす際には、保持しているdatetime以降のバーを走破して、現在のstateの正当性を確認するなど。
とは言え、SL/TPを置かず、値動きに応じて決済注文を行うようなEAの場合、エントリー後にスリープされるケースなどはどうしようもない部分がある。
基本的にスリープはNGという事を強く意識しなければならない。