2011/06/10

MT4用EA開発時代 - 「ERR_COMMON_ERROR」ってなんやねん



さて前回は、再発してしまった「ERR_INVALID_TRADE_PARAMETERS」への対応について書きました。今回は、デモ口座上EAで発生した「ERR_COMMON_ERROR」にどう対処するのか検討している様子を書いてみたいと思います。

そもそもの発端は、とある日、クリティカルエラー検出した旨のメールが。
内容は、OrderClose()にてエラーコード「ERR_COMMON_ERROR」が発生とのこと。
そして今回の設計通り、エラーを検出した通貨ペアの新規発注が停止状態に。

さて、エラーコードから愛用している有志日本語ヘルプを見てみたら。

●ヘルプの説明
 Common error. All attempts to trade must be stopped until reasons are clarified. 
  Restart of operation system and client terminal will possibly be needed.
  一般的なエラー。理由が明確になるまで、トレードするすべての試みは停止する必要
  があります。オペレーション システム(OS)とターミナル クライアントの再起動が必要
  とされます。











一般的なエラー??



エラーに一般的とかあるのか???
原因がわかるまで停止やと?

 
しかも、原因の如何に関わらずPC再起動せよと?
なぜ原因によって対処が変わらないのだ??
#そもそも、「ERR_COMMON_ERROR」というエラーコード以上の詳細なエラー情報無いぞ。。。







だいたい

どうやって調査しろ
ゆーねん??




メモリもがらがらに空いてる。 (2GB積んでて、利用メモリ700MB程度) 
1プロセスあたりの最大メモリも30MB程度。
同居している合計4つのMT4は元気に動いてる。
毎週土日はPCの電源切ってる。

しかも、エラーが発生したMT4のプロセスの他のトレードはその後も順調に処理されてるし、通信エラーも発生してない。

実際に出力された「操作履歴」でのログは以下。(口座番号は伏せてます)
#ちなみに、FX業者はECN系。MT4のバージョンは、「Version: 4.00 Build228」(03 Nov2010)

【出力された操作履歴】
-------------------------
00:45:35 'XXXXXXX': order buy market 1.00 USDZAR sl: 0.00000 tp: 0.00000
00:45:35 'XXXXXXX': request was accepted by server
00:45:35 'XXXXXXX': request in process
00:45:35 'XXXXXXX': order was opened : #5011193 buy 1.00 USDZAR at 6.73600 sl: 0.00000 tp: 0.00000
00:45:35 'XXXXXXX': modify order #5011193 buy 1.00 USDZAR at 6.73600 sl: 0.00000 tp: 0.00000 -> sl: 6.72360 tp: 6.78120
00:45:36 'XXXXXXX': request was accepted by server
00:45:36 'XXXXXXX': request in process
00:45:36 'XXXXXXX': order #5011193 buy 1.00 USDZAR at 6.73600 was modified -> sl: 6.72360 tp: 6.78120
00:50:37 'XXXXXXX': modify order #5011193 buy 1.00 USDZAR at 6.73600 sl: 6.72360 tp: 6.78120 -> sl: 6.72640 tp: 6.78120
00:50:37 'XXXXXXX': request was accepted by server
00:50:37 'XXXXXXX': request in process
00:50:37 'XXXXXXX': order #5011193 buy 1.00 USDZAR at 6.73600 was modified -> sl: 6.72640 tp: 6.78120
00:55:35 'XXXXXXX': close order #5011193 buy 1.00 USDZAR at 6.73600 sl: 6.72640 tp: 6.78120 at price 0.00000
00:55:35 'XXXXXXX': order #5011193 buy 1.00 USDZAR closing at 0.00000 failed [Common error]
-------------------------

チケット番号も正しいし、その後の上記以外の独自トレードログも正しく出力されている。
ログ上、何も怪しい事がない。


さて、どう対処するか。


今の設計上、このエラーコードは「新規トレード停止」状態になって、MT4を再起動するまでは、この通貨ペアでの新規発注はされない様になる。

実は最近思う事があって、今回設計した「新規発注停止」というのは、裏を返すと「機会損失」という「損失」でもあるので、あまり安易に「新規発注停止」状態にしたくないという事を思い始めた。

そこで、MQL4 Communityで、「ERR_COMMON_ERROR」を検索してみた。

【検索結果の記事一覧】
-------------------
-------------------

上記記事を要約すると、やっぱり原因は曖昧で、「サーバ側」の問題と考えているっぽいのと、保有ポジションを全てクローズした上で、今回の設計と同様「新規発注停止」にする方法が紹介されている。
でも、OS再起動しても解決されないという事も書かれている。

次は、妄想で何が発生しているのか考えて見た。

まずは、そもそものオーダ関連関数(OrderSend/OrderModify/OrderClose等)はどうやって実現されているのか、という事を考えて見ると。

【妄想の根拠】
-------------------------
1.HTTPSセッションは2本という事実と、2本の内1本はオーダ送信用、残り1本は
  ティックデータ受信用という仮説。
2.オーダ関連関数は1MT4で同時に一つしかできない。
  通信用スレッドが1つだけある
3.チャート毎にスレッドがある
  これは本当に怪しい仮説。
  コレを正しいとした場合、実際に使っているスレッド数がチャートの数より少ないし、
  パフォーマンスモニタを見てると、スレッド数が増減している。
  なのでむしろ、ティックデータ受信毎に、スレッドをチャート単位で生成して、
  一定時間何も無ければスレッドを削除していると考えた方がよさそう。
  すくなくとも、start()関数実行毎にスレッドがあって、そこから通信用スレッドに、
  オーダを出している様に見える。
-------------------------  

まず、「トレードサーバ」以外から返却されるOrderCloseのエラーコードと説明を列挙すると。

【トレードサーバ以外から返却されるエラーコード】
-------------------------------
1.ERR_CUSTOM_INDICATOR_ERROR:「Custom indicator error.」
2.ERR_INTEGER_PARAMETER_EXPECTED:「Integer parameter expected.」
3.ERR_INVALID_FUNCTION_PARAMVALUE:「Invalid function parameter value.」
4.ERR_INVALID_PRICE_PARAM:「Invalid price.」
5.ERR_INVALID_TICKET:「Invalid ticket.」
6.ERR_UNKNOWN_SYMBOL:「Unknown symbol.」
7.ERR_TRADE_NOT_ALLOWED:
  「Trade is not allowed. Enable checkbox "Allow live trading" in the expert properties.」
-------------------------------

上記エラーコードから見る限り、トレードサーバにリクエスト送信する前の事前チェックぐらい。
意味がわからないのは、「ERR_CUSTOM_INDICATOR_ERROR」。
#なんで、OrderCloseでインジケータが関係するんや???

つまり裏を返すと、以下が妄想される。
・MT4クライアント側で発生した、メモリ不足とかスタックオーバフローとかのリソース不足や、
 不正メモリアクセス系も無いし、想定外のエラーが他に無い。
・トレードサーバから返却されるエラーコードを見てると、少なくとも通信エラーではなさそう
 だし、サーバ側での想定外エラー(バグ起因/リソース不足/障害)が他にない。

さらにそこから妄想を膨らませると、1つのMT4上1つしかないと思われる通信用スレッド内とトレードサーバ側で発生した、リソース不足系のエラーや想定外エラーは全て「ERR_COMMON_ERROR」に含まれている。

これを絵にしたのが以下の図。

【妄想中のMT4内の構造】
---------------------------
---------------------------


するとヘルプで書かれている「OSの再起動が必要」という記述に疑問が。

実際、MT4唯一の通信用スレッドで一回「ERR_COMMON_ERROR」が発生しているのに、同じMT4上で動作している他の通貨ペアはそのまま通常動作を続けているし。
#通信用スレッドがおかしくなっているのであれば、後続処理もエラーになるはず。

つまり、「ERR_COMMON_ERROR」の原因を大別すると、以下になるのではないかと。

【「ERR_COMMON_ERROR」原因分類の妄想】
---------------------------
1.リソース不足(MT4側/トレードサーバ側)
2.HW障害か、OSがそもそも不安定(MT4側/トレードサーバ側
3.「MT4クライアント」か「トレードサーバ」のバグ
---------------------------

なので、確かにOS毎再起動しなければならないケースもあるけど、そうじゃないケースもあって、今回発生したのは、OS再起動不要で、リトライすれば成功する可能性もありそう。
#実際、OSは再起動せずにMT4を再起動。その後今回のエラーは発生してない。

次に今回のケースを考えて見た。

【今回のケースで原因を妄想】
------------------------
1.リソース不足
  メモリは余っているし、1プロセスあたりの最大利用メモリもゴミ程度。#仮想メモリででも。
  セッションは張りっぱなしなので、ソケットハンドル/ポート不足というのは考えられない。
  なので、あまり考えられない。 
2.HW障害か、OSがそもそも不安定(MT4側)
  他のMT4は普通に動いているし、エラー発生したMT4で他の通貨ペアでは
  問題なく処理を継続していたので、考えにくい。
3.「MT4クライアント」か「トレードサーバ」のバグ
  残るはこれしかないが、対処しようがない。
  MT4やOSを再起動したところで、解決される可能性は低い。
------------------------

やっぱり、リトライで成功する可能性がありそう。

じゃあ、共通部品としてどうするかを考えてみた。

【共通部品としてどうするか】
----------------------------
結局、「リトライによる被害増大」と「発注しないことによる機会損失」の天秤。

結局一番怖いのは、ERR_TRADE_TIMEOUT」でのブログ記事と同じで、リトライで不用ポジションを持ってしまうこと。OrderModifyとかOrderCloseは多重実行しても問題なさそう。

次に「リソース不足」や「HW障害/OS不安定起因」の場合について考えて見た。
この場合、ERR_TRADE_TIMEOUT」と全く同じではダメそうだけど、ERR_COMMON_ERROR」が短期間で何度か発生する気もする。

なので、「ERR_COMMON_ERROR」が発生した場合は以下の様にする事に。

●「ERR_COMMON_ERROR」発生時処理
   OrderSendの場合は1分間後のティック受信時にリトライ。
   OrderModify/OrderDelete/OrderCloseは通常リトライ。
   ただし、発生時は警告メール送信とログ出力。 
 2.MT4上でリトライ回数が一定数以上になれば、クリティカル・エラー扱いにする。
   「ERR_COMMON_ERROR」が発生する毎に、大域変数上のカウンタをインクリメントする。
   大域変数としたのは、同じMT4で複数チャートを開いている場合に、
   異なるチャートで発生したのも合算してカウントしたかったから。
   リトライアウトは3回ぐらいかな?
 3.カウンタをクリアするタイミング
   これは難しいので後述。

●カウンタクリアタイミングについて
 案1.1週間に一回再起動するから起動時にクリアする。
     → 一番楽で、発生頻度的にも適切かも。
 案2.1回オーダ関連関数で成功すればクリアする。
     → 間欠障害の様な場合に問題になりそう。
 案3.1日1回クリアする。
     → 毎日起きてたらちょっとおかしいかも。
 
 なので、「案1.」にする。

 ただ注意しないといけないのは、今回start()関数全体を排他制御しているから大丈夫だけど、
 排他制御しない場合は、大域変数上のカウンタをインクリメントする際、以下の処理順になる点。
  1.大域変数から現在値を取得
  2.取得した現在値をインクリメント
  3.インクリメントしたカウンタを大域変数に格納
 この時、連続で複数のスレッドが「ERR_COMMON_ERROR」を検出した場合に、正しい発生回数
 にならないタイミングがあること。
 排他制御してない場合、1つのスレッドが上記「1.」~「2.」の間に、他のスレッドで「1.」
 を実行すると、本来の発生回数より少ない数になってしまう点。
 
 今回の共通部品は、ECN対応の件もあって、start()全体を排他制御する事を前提としたいから、
 特に考えないことにした。
 #やろうと思えばできるけど、これ以上プログラムを複雑にしたくない。
----------------------------


 


ほんま、ようわからんエラーや。

詳細なエラー情報出してほしい。

発生原因わからんやん。 

しかも、原因わからないで、ヘルプ通りにすると、
一回発生したら二度とMT4使えなくなるやん。。
#原因がわかるまでトレードするなという事なので。。。






しかし、また共通部品のプログラム修正かぁ。。






そして、なかなかEAソース修正が収束せず、「FXシステムトレード初心者奮闘記」の「MT4用EA開発時代」は、新たなバグが出ない限り、「OrderSelect問題」仮説の検証に進むかもしれないのでした。
#1つのデモ口座が破産しちゃった。。

0 件のコメント:

コメントを投稿