最近知ったことであるが、MT4 EAプログラミングで多用されているGetTickCount()関数の利用には躊躇すべき点があるようだ。豊嶋久道著「FXメタトレーダー実践プログラミング」のライブラリーで多用されていた同関数がその後の同氏著書では見当たらないこともその辺りの事情を物語っているようである。
この関数は豊嶋氏のライブラリーのMyOrderSend()に代表されるトレード関数に使われていて、例えば何かのトラブルで発注に失敗した場合に、致命的なものでなければそのままエラーとしてしまうのではなく、10秒間は何回も発注を繰り返すという際の時間差を測るツールであった。
GetTickCount()のデータ型は新MT4では、uint型で定義されており従来のint型より利用可能整数域が制限されていることに加えて、関数の返す戻り値がミリ秒単位であるため、50日足らずでオーバーフローをきたしてしまうことにある。そうとなれば、同関数を使ったEAをVPSで数ヶ月も運用することには、躊躇せざるを得ないという結論になる。
筆者は、豊嶋氏開発のMyLib.mqh 及びMyLib.mq4を参考に、私製のヘッダーファイルを作成しているが、その中でもGetTickCount()をそのまま使用しているので、これを次のように修正した。修正は、豊嶋氏著「メタトレーダー4&5」で新たに作成されたMyPosition.mqhを参考にした。本稿での修正は、MyOrderSend()の例であるが、MyOrderModify()やMyOrderClose()も同様の修正を加えることになる。
「実践プログラミング」でのMyOrderSend()
// 注文を送信する
bool MyOrderSend(int type, double lots, double price, int slippage, double sl, double tp, string comment, int magic)
{
price = NormalizeDouble(price, Digits);
sl = NormalizeDouble(sl, Digits);
tp = NormalizeDouble(tp, Digits);
int starttime = GetTickCount();
while(true)
{
if(GetTickCount() - starttime > MyOrderWaitingTime*1000)
{
Alert("OrderSend timeout. Check the experts log.");
return(false);
}
if(IsTradeAllowed() == true)
{
RefreshRates();
if(OrderSend(Symbol(), type, lots, price, slippage, sl, tp, comment, magic, 0, ArrowColor[type]) != -1) return(true);
int err = GetLastError();
Print("[OrderSendError] : ", err, " ", ErrorDescription(err));
if(err == ERR_INVALID_PRICE) break;
if(err == ERR_INVALID_STOPS) break;
}
Sleep(100);
}
return(false);
}
変更後のMyOrderSend()
// 注文を送信する
bool MyOrderSend(int type, double lots, double price, int slippage, double sl, double tp, string comment, int magic)
{
price = NormalizeDouble(price, Digits);
sl = NormalizeDouble(sl, Digits);
tp = NormalizeDouble(tp, Digits);
if(IsTradeAllowed() == true)
{
RefreshRates();
if(OrderSend(Symbol(), type, lots, price, slippage, sl, tp, comment, magic, 0, ArrowColor[type]) != -1) return(true);
int err = GetLastError();
Print("[OrderSendError] : ", err, " ", ErrorDescription(err));
}
return(false);
}