EAでエラーが発生していて調べたらリトライ可能なものだったので修正した。発生したエラーは複数の発注が同時にさらたときに発生するもの。前の発注処理が完全に終わる前に次の発注をしているのでエラーになっていると思われる。なのでタイミングを少しだけずらせば発注は成功する。
本記事はFXの自動売買について紹介していますが内容を保証するものではありません。金銭にかかわる内容であるためご注意ください。参考にする場合は自己責任でお願いします。
一般的なエラー処理
思い付くエラー処理の種類を上げてみた。
継続不可能な致命的エラー
これは予測できない致命的なエラーで基本的にはシステムを停止もしくは一時停止することがある。例えばデータベースやストレージに全くアクセスできず回復不可能なエラーコードが返ってくるとか。業務システムより低いレイヤー(ハードより)で起きた場合など。いきなり処理を中断すると再開示に問題が起きる可能性があるので、可能な限り終了処理を実行してから停止状態に入る。メモリリークによりメモリ枯渇などもここに含まれる。ようするに「お手上げ」なエラーなのである。
リトライで可能性のあるエラー
何らなの理由で処理でが継続できない場合処理を中断する場合がある。例えば連携するシステムがたまたま運悪くビジー状態でエラーになった場合など。昨今のシステムは並列処理で作られているのでこのようなリトライエラーは少ないハズ。ただし、データベースへのコミット(更新処理の確定)タイミングでの排他処理(同時処理できない作業)がある場合はビジー状態になることも考えられる。
FXの場合は約定に時間がかかることがあるためこのビジー状態になりやすい気がしている。通常の業務処理に比べ約定処理は高コストのようだ。やはりお金が絡むシステムなのでこのあたりの作りは慎重になっているのが原因だろう。
タイムアウトエラー
依頼した処理に想定以上の時間がかかってしまった場合に発生するエラー。連携システムで無限ループやデッドロック(同期制御系エラー)が原因となることが多い。ウェブサービスの場合はアクセスが集中して処理落ちする場合もこれにあたる。大人数がアクセスするサービス以外でタイムアウトが発生したらシステム的な問題がある可能性が高く致命的エラーに近くなる。
業務エラー
例えば業務設計的にありえない組み合わせになってしまった場合など。入力時に法律で決められた値の範囲内に限定しているにも関わらず、すでに範囲外の数値が入力されているとか。EAで言うなら買いシグナルがでているのに売りで発注をだしてしまったりとか。コードの記述ミスが原因になることが多い。各処理セクションごとに適切な業務エラーチェックを入れておけばエラーによる矛盾をいち早く検知することができる。EAの場合も同様で矛盾する引数や処理結果が入ってこないかチェックしておくとバグを防ぐことができる。
EAで発生するエラー
31種類のエラーがあるが今のところは146しか確認できていない。
受発注時のエラー
OrderSend(発注)時のエラーはGetLastError()でエラーコードを取得できる。こちらがエラーコード一覧。詳しくはこちら。
Code | ID | Description |
---|---|---|
0 | ERR_NO_ERROR | No error returned |
1 | ERR_NO_RESULT | No error returned, but the result is unknown |
2 | ERR_COMMON_ERROR | Common error |
3 | ERR_INVALID_TRADE_PARAMETERS | Invalid trade parameters |
4 | ERR_SERVER_BUSY | Trade server is busy |
5 | ERR_OLD_VERSION | Old version of the client terminal |
6 | ERR_NO_CONNECTION | No connection with trade server |
7 | ERR_NOT_ENOUGH_RIGHTS | Not enough rights |
8 | ERR_TOO_FREQUENT_REQUESTS | Too frequent requests |
9 | ERR_MALFUNCTIONAL_TRADE | Malfunctional trade operation |
64 | ERR_ACCOUNT_DISABLED | Account disabled |
65 | ERR_INVALID_ACCOUNT | Invalid account |
128 | ERR_TRADE_TIMEOUT | Trade timeout |
129 | ERR_INVALID_PRICE | Invalid price |
130 | ERR_INVALID_STOPS | Invalid stops |
131 | ERR_INVALID_TRADE_VOLUME | Invalid trade volume |
132 | ERR_MARKET_CLOSED | Market is closed |
133 | ERR_TRADE_DISABLED | Trade is disabled |
134 | ERR_NOT_ENOUGH_MONEY | Not enough money |
135 | ERR_PRICE_CHANGED | Price changed |
136 | ERR_OFF_QUOTES | Off quotes |
137 | ERR_BROKER_BUSY | Broker is busy |
138 | ERR_REQUOTE | Requote |
139 | ERR_ORDER_LOCKED | Order is locked |
140 | ERR_LONG_POSITIONS_ONLY_ALLOWED | Buy orders only allowed |
141 | ERR_TOO_MANY_REQUESTS | Too many requests |
145 | ERR_TRADE_MODIFY_DENIED | Modification denied because order is too close to market |
146 | ERR_TRADE_CONTEXT_BUSY | Trade context is busy |
147 | ERR_TRADE_EXPIRATION_DENIED | Expirations are denied by broker |
148 | ERR_TRADE_TOO_MANY_ORDERS | The amount of open and pending orders has reached the limit set by the broker |
149 | ERR_TRADE_HEDGE_PROHIBITED | An attempt to open an order opposite to the existing one when hedging is disabled |
150 | ERR_TRADE_PROHIBITED_BY_FIFO | An attempt to close an order contravening the FIFO rule |
エラー処理の実装
上記のエラー表を見ると正常処理を除いて31種類のエラーがある。いきなりエラーごとのエラー処理をする必要はない。なぜなら、発生頻度が異常に少ないものが多い可能性があるからだ。何なら一生お目にかかることがないエラーも存在するだろう。はじめは正常終了かエラーかのどちらか程度のレベルで良い。
エラー処理について
基本は発生したエラーだけに対応すればいい。未確認のエラーはポップアップメッセージで表示し直ぐに確認できるようにしておく。筆者が現在確認しているエラーは146の「Trade context is busy」だけ。
【EA開発ガイド】Part 7 フォワードテスト基礎 – Chapter 4 フォワードテスト中にエラー発生する
エラー処理例
エラー146は処理が集中しているだけなのでリトライすれば何とかなる可能性が高い。なので146エラーだけはリトライさせるように実装する。
以下はエラー実装の抜粋。OrderSendの復帰値が-1ならエラーなのでコードに合わせて処理。146エラーが発生したらエラーメッセージだけ出力しリトライする。それ以外のエラーはレポートを出力して処理を中断。未対応のエラーが発生したら逐次実装していく。
if(g_ticketNumber == -1) { // エラーコードを取得 int errorCode = GetLastError(); if(errorCode == 146) { // ビジー状態なのでリトライする errorPrint("エントリーでエラーが発生しました。", magicNumber); } else { errorReport("エントリーでエラーが発生しました。", magicNumber); } return false; }
まとめ
146エラーをポップアップしない仕様にしたので今後146エラーがどの程度発生したかはログ等で確認する必要がある。毎回ログファイルを確認するのも大変なので専用ファイルにエラーをレポートする処理を実装でもしようかな。
- EAのエラー処理は必要になってから実装
- 致命的エラーでは無ければリトライが無難
- GetLastError()で詳細エラーコードを取得できる
バックテストでは146エラーが発生しないので成績が悪くないそうな気がします。