FXメタトレーダー実践プログラミングへの補足(2)/MyOrderClose()の改善

昨日紹介した応急処置は、

//if(lots != 0) break;
これだけで、売り1/買い2 になった状態で買いシグナルは止まります。

ですが、基本的に1ポジションしか取らないことを前提にしたEAでこれはあまり良くないので、正攻法な直し方を紹介します。
今回の問題の本質は、MyOrderClose でポジションのクローズに成功したのか?確認せずに、新規ポジションを建ててしまう点にあります。
なので、以下のように直すのが自然です。これが正統派..というか、理解しやすいですよね。


…とはいうものの、MyOrderClose 内でも OrderSelectのループが回って、MyCurrentOrders 内でもOrderSelectのループが回るのは処理が重複しており、バックテストや最適化に時間が掛かる一因にもなります。私が手直しするとしたら、MyOrderClose のポジションが無かった場合の返り値を true に変更して、以下のようにします。

↑修正案2と3 は同じ処理を意味しています。私の好みの書き方は 3 です。


↓本来は、OrderCloseする為のポジションが無かったので、OrderCloseに失敗した = false という行為の正否を返す意味だと思いますが、
ポジションが残っている状態 = false /ポジションが(クローズされていて)無い状態 = true という状態の正否を返すように変更します。

少し強引ですが、この辺りは自分が納得できるカタチで修正してみてください。




さて、MyOrderClose に限らず、MyOrderSend,MyOrderModify,MyOrderDelete 全て、エラー時のリトライ処理が組み込まれています。実運用ではリトライ処理は必須ですしそれ自体は問題無いのですが..バックテスト中にリトライ処理に引っかかると悲惨です。
(某商用EAでバックテストに異常に時間が掛かっていたのはこれが原因..汗
例えば、昨日の MyOrderClose の例では、エラー時にループを抜ける処理が ERR_INVALID_PRICE しか書かれていません。

if(err == ERR_INVALID_PRICE) break;

FREEZELEVELが問題でクローズできない場合、ERR_TRADE_MODIFY_DENIED が発生するのですが、これではループを抜けられないので、1Tick更新のたびに10秒間待たされることになります。(テスト環境下では何度リトライしても結果は変わりません..)
実運用では、RefreshRates();を繰り返している間に価格が動いてクローズできるかもしれないので

if(err == ERR_INVALID_PRICE) break;
if(err == ERR_TRADE_MODIFY_DENIED) break;

のようにエラーの検出を追記するのは好ましくありません。
そこで、

if(err == ERR_INVALID_PRICE) break;
if( IsTesting() ) break;

↑このように、バックテスト中に発注エラーが起きた時は、ループを抜ける..ようにします。
(本当は、テスト時にエラーが出ないように適切な注文をすべきですよ...^^;;)





最後に..MyOrderClose() は、スキャルピングには不適な側面がある点を紹介します。
MyOrderClose のコア部分を抜き出したのが以下です。

ループの中で、RefreshRates して、成行き価格となる OrderClosePrice でクローズしています。


…という事は、以下のようなフローが起こりえます。

(1) 90.00円で買ったポジションが 90.05円になって 5pips 含み益が出ている。
(2) MyOrderClose(0,MN) でスリッページゼロで利確実行。
(3) 90.05でのクローズに失敗..そこでリトライ。
(4) 90.03でのクローズに失敗..そこでリトライ。
(5) 90.02でのクローズに失敗..そこでリトライ。
(6) 89.98でクローズに成功。

+5pipsを得るはずが、-2pipsの損失で終わるのは不本意ですよね。
(10秒のリトライ中に 7pips も動くかっ!!というツッコミは無しでお願いします..


こういう場合は、 OrderClosePrice を使わずに、指定の価格(price = 90.05)でのクローズをリトライする関数を別途用意すればOKです。

OrderClose(ticket, OrderLots(), price, slippage, ArrowColor[type])

ちなみに、注文関係の処理のライブラリとして有名なLibOrderReliable.mq4も、成行きでのクローズ(OrderCloseReliableMKT)と指定価格でのクローズ(OrderCloseReliable)で分けているので、自分のニーズに合わせて必要な関数を用意するのが吉ですね。






コメント返し

ところでこの様な意図しない結果を生む可能性のある事を
未然に防ぐ為に、バックテストの結果を確認する
(テスターで十分な期間のデータを使用し)。
これで基本的に十分なのでしょうか?

全く不十分です...orz
上述のスキャルピングには不適な側面は、バックテストでは必ず利確してしまうので気付かないと思います。
バックテスト、デモ口座でのフォワードテスト、リアル口座で小額でのフォワードテストを経て、実運用に取り掛かっても、やはり意図しない結果に出会うのが現実です..。