さて前回は、ECN系FX業者への対応方式を検討した所まで書きました。今回は、以前の記事で処置したはずが再発してしまった、「ERR_INVALID_TRADE_PARAMETERS」に関するバグに関する対応について書いてみたいと思います。
発生事象は以前の記事と同じ。
【発生事象詳細】
-------------------------
1.OrderModify時に、ERR_INVALID_TRADE_PARAMETERSが発生
ログを見ると、チケット番号も、指定価格も間違えてない。
ロジックは、ERR_INVALID_TRADE_PARAMETERSが発生した場合、RefreshRates()後、
OrderSelectをループさせて、ポジションが無くなっていれば成功扱いとしていた。
しかし、そこでポジションありと判定されたため、今回のERR_INVALID_TRADE_PARAMETERS
がクリティカル・エラー扱いとなった。
2.その直後のログで、StopLossにひっかかって、決済された旨のログが出力されていた。
3.ERR_INVALID_TRADE_PARAMETERS発生の前のバーでは、OrderModifyは成功している。
-------------------------
上記バグの対応時に立てた仮説が、OrderSelect()の結果が最新化されるのが、ティックデータ受信後のRefreshRates()後というMT4の動作。
じゃあ、仮説が間違えていたのか?という話ですが、
考慮漏れです。
だからと言って、仮設が正しいという事が証明された訳じゃけど。。
#ティックデータ受信後にRefreshRates()すると、OrderSelect()結果が最新化されるという仮説
考慮モレを簡単に言うと、RefreshRates()でTRUEが返ってきたからと言って、その時受信したティックデータが、SL/TPで決済された後のティックデータである保障は無いということ。
つまり、OrderModify()実行中に受信したティックデータに、SL/TPで決済された旨の情報がはいっているはずがない。以降は詳細。
まずは、前回の対処。
【前回の修正後のロジック】
-----------------------
ポジション保有中と思っていた場合、以下の様に修正
・「ERR_INVALID_TRADE_PARAMETERS」が発生した場合、RefreshRates()がTRUEを返却
するか、IsStopped()がTRUEになるまで、スリープ&リトライする。
→RefreshRates()はデータ更新が不要(つまり最新化されていない)であれば、FALSEを返すので。
・RefreshRates()がTRUEを返却した場合、ポジション保有中かどうかをOrderSelectのループで確認。
・上記でポジション保有していれば、クリティカルエラー扱いに。逆に保有ポジションなしで
あれば、成功扱いで、ログ出力のみ。
-----------------------
後の説明の為に、前回記事で発生していた事を絵にしてみると。
【ERR_INVALID_TRADE_PARAMETERS発生条件-1】
--------------------------
下図の「エラー検出」箇所が「ERR_INVALID_TRADE_PARAMETERS」検出したところ。
そして、ティックデータ受信していない状態で、RefreshRates()しても、反映する
データが無いので、OrderSelect()しても、オーダ保有中と判断されてしまった。
そして、以前の記事で対処したのが以下。
【ERR_INVALID_TRADE_PARAMETERS発生条件-2】
--------------------------
MT4クライアント側で、RefreshRates()がTRUEを返却するまでループする事で、
ティックデータ受信を確認してから、オーダ保有有無を確認していた。
ここまでが、以前のブログ記事での対処。
一見問題なさそうだけど、
また同じ現象が発生。
そこで改めて、HTTPSのセッションが2本張ってある事実と、それらが「オーダ操作用」と「ティックデータ」受信用という仮説を元に、いろんなタイミングを考えて見ると、以下のタイミングのズレがある事に気付いた。
【ERR_INVALID_TRADE_PARAMETERS発生条件-3】
--------------------------
これに対処する為に、一旦OrderModify()処理中に受信したティックデータをRefreshRates()で反映させてから、さらに次のティックデータ受信するまでRefreshRates()をループする様に修正。すると以下の様なデータの流れになる。
ここで問題なのが、上記図での2回目のティックデータ送信が、本当に「トレードサーバ」でSL/TP決済を認識した後のデータかどうかが解らない点。
つまり、以下の様なケース。
【ERR_INVALID_TRADE_PARAMETERS発生条件-4】
--------------------------
下図の「トレードサーバ」側からの2回目のティックデータ送信をMT4クライアント側で受信するタイミングがずれて、「MT4クライアント側」の1回目のRefreshRates()実施後になってしまった場合。
こんなケースが
ほんまに起こりうるんかい!
という話もあるんですが。。。。
ここを少しでも緩和する為に、TimeCurrent()を使う事にした。
この関数は、サーバ側時間を秒単位で取得する事ができ、ヘルプを見ると、ティックデータ受信毎に「MT4クライアント側」に反映される。
なので前述の追加修正に加え、「MT4クライアント側」start()関数内のOrderModify()で、「ERR_INVALID_TRADE_PARAMETERS」を検出したタイミングで一旦TimeCurrent()を取得しておき、このTimeCurrent()が変わるまで、RefreshRates()をループさせる様にさらに修正。
すると少なくとも、OrderModify()処理中に「MT4クライアント」に溜まっていたデータを吐き出したあと、少しは時間が経った後の2回目のティックデータ受信という事はわかる。
#同じ時分秒で発生したティックデータではないというレベルだけど。。
もう一つ、ヘルプにも書いてないし、なんの検証もしてないけど少しだけ期待している事が。
それは、OrderModify()のレスポンスをMT4クライアント側が受信した時に、TimeCurrent()が更新されること。これが「もし」本当であれば、今回のロジックで穴は無くなるはず。
これでダメなら、後はTimeCurrent()が何秒ずれるまで待つ、という設定を追加するか、クリティカルエラーをあきらめて、警告レベルのエラー扱いにするかぐらいしか思いつかない。
--------------------------
どっちにしても、
根本解決策
思いつかず。
OrderSelectの情報を最新化するAPIが欲しい。。
#実は他にも、ブログ記事にする程のものじゃない、純粋なロジックミスのバグ改修があったりしてた。。。
0 件のコメント:
コメントを投稿