トレード備忘録 & MT4/MT5インディケータ及びEAの開発

日々のトレード備忘録及びMT4/MT5に関する事項

新MT4ライブラリー <LibEA4.mqh>

2017-07-05 14:19:02 | 投資

 豊嶋久道著Kindle版「EA実践プログラミング」ライブラリーの優れた点については既述の通りであるが、先日来、少し厄介な状況に直面してきた。トラブルの元はFX業者側にあるが、ライブラリーではそのような想定外の事態には対応していなかったのである。 

 LibEA4.mqhを利用したEA例で説明してみよう。仕掛けシグナルをsig_entry、手仕舞いシグナルをsig_exit、ストップロスをSLpipsとすると、そのEAは次のように簡便なものとなる。(本体部分のみ)

//ティック時実行関数

void OnTick()

{

   //損切りオーダーの付加

   if(MyOrderStopLoss() == 0) MyOrderModify(0, MyOrderShiftPrice(-SLpips), 0);

   //成行売買

   MyOrderSendMarket(sig_entry, sig_exit, Lots);

}

 このEAを4時間足以上の時間足で稼働させると、損切り決済に遭遇することが多くなる。その場合、仕掛けシグナルが有効であると、再エントリーとなり、ボラティリティが高い場合、二度三度と損切りを繰り返してしまうことがある。そこで同一時間足(バー)内では、注文を繰り返さないよう、MyMarketSendMarket()に次の条件を付加してみた。

   //成行売買

     static datetime time = Time[0];

     if(Time[0] != time){

     MyOrderSendMarket(sig_filter, sig_exit, Lots);

     time = Time[0];}

 これで一安心と就寝したものの、翌朝チャートを開いてみると、6時に仕掛けシグナルが出ているのにエントリーがないのである。不審に思って、ターミナルのエキスパートタブを開いてみると、休日でもないのに132 Market is closedなるエラーメッセージが出ている。 

 エラーとなった原因は二つあった。

① 海外業者の中には、平日の日付変更時(夏時間では日本時間の午前6時)には、ロールオーバーのため1~2分間トレードできない仕様にしているところがある。当然この間は休日同様の扱いとなり、オーダーが出されても市場は休場(Market is closed)とのエラーとなってしまう。豪州系業者にはこのような仕様のところが多く,Pepperstone社では、その警告を正式に発している。https://pepperstone.com/en/support/about-trading/market-opening-hours 

② MyOrderSendMarket()に条件を付加したこと

 新ライブラリーでは、エラーが発生した場合にはエラーの原因が消滅して正常に復帰した際には、自動的に再注文が出される仕組みになっている。ところが、この関数はvoidで定義されているため、たとえエラーであっても、「同じ時間足では再注文を出さない」との付加条件が働いて、サーバーが正常に復帰しても同一時間足内(同一バー内)では再注文が出せなくなっていた。 

解決策

① voidで定義されていたMyOrderSendMarket()をbool関数に変更し、正常に発注が終了した時に限り、「同じ時間足内では再注文を出さない」ことにした。

//シグナルによる成行注文

bool MyOrderSendMarket(int sig_entry, int sig_exit, double lots, int pos_id=0)

{

   //ポジション決済

   MyOrderCloseMarket(sig_entry, sig_exit, pos_id);

   //買い注文

   if(sig_entry > 0) MyOrderSend(OP_BUY, lots, 0, pos_id);

   //売り注文

   if(sig_entry < 0) MyOrderSend(OP_SELL, lots, 0, pos_id);

  

   //エラーの場合

   int err = GetLastError();

   if(err > 0)

   {

     return false;

   }

   return true; //正常終了

}

② MyOrderSend()を変更

 MyOrderSendMarket()では、エラーの有無は毎チックで行われる。そのため、一旦エラーが発生すると、この関数の裏側で働くMyOrderSend()もエラーが解消するまで毎チックで再注文が繰り返されることになる。事例のように、毎朝1~2分間EAが稼働できない状況では、その間夥しい数の再注文が出し続けられる。4時間足以上の長い時間足でトレードする場合では、10秒間に一度再注文が出されれば十分なので、MyOrderSend()関数を次のように変更した。

//注文の送信

bool MyOrderSend(int type, double lots, double price=0, int pos_id=0)

{

   color ArrowColor[6] = {clrBlue, clrRed, clrBlue, clrRed, clrBlue, clrRed}; //矢印の色データ

 

   CheckPosID(pos_id);  //ポジション番号のチェック

   if(MyOrderType(pos_id) != OP_NONE) return true; //注文済み

 

   price = NormalizeDouble(price, _Digits); //価格の正規化

 

   //RefreshRates();

   if(type == OP_BUY) price = Ask;  //成行注文の買値

   if(type == OP_SELL) price = Bid; //成行注文の売値

 

   //注文送信

   while(true)

   {

      if(IsTradeAllowed() == true)

      {

         RefreshRates();

         int ret = OrderSend(_Symbol, type, lots, price, Slippage, 0, 0,

                       IntegerToString(MagicNumber[pos_id]),

                       MagicNumber[pos_id], 0, ArrowColor[type]);

         if(ret != -1) return true;

  

         int err = GetLastError();

         Print("MyOrderSend : ", err, " " , ErrorDescription(err));

         //return false;

       }

       //return true; //正常終了

       Sleep (10000);

   }

}

③ 結果検証

 本日の朝6時にもたまたま買いシグナルが出ており、EAは正常に作動したようで、シグナル通りのポジションが形成されていた。ターミナルのエキスパートには、企図した通り132 Market is closedが10秒間隔で6回出ていて、6:01には正常発注がなされている。このことからサーバーは、ロールオーバーのため毎朝1分間注文を受け付けないことも確認された。利用している業者は、Pepperstone同様豪州系である。 

 結果として、著者開発のライブラリーに変更を加えてしまったので、著者に迷惑が掛からぬよう変更後のライブラリーは別名にして使用している。