FX自動売買研究記!

    - 為替相場をメタトレーダーの自作自動売買プログラムで勝ち抜く -

    OrdersTotal()の落とし穴 

    最近、僕の主要EAの一つが、エントリーフラグを満たしているにもかかわらず全く取引を行わなくなりました。

    色々調べてみた結果、どうやら『OrdersTotal()の落とし穴』にハマっていた事が分かりました。

    そのEAはポジションを過剰に保有してしまうことが無いように、最大ポジション数を限定しています。
    例えばMaxPositionsという変数名を用意して、これが現在保有しているポジション数以下の時のみエントリーを許可しているわけです。

    if( 今のポジション保有数 < MaxPositions)
    {
      エントリーオーダー;
    }
    という感じ。

    御存知の通り、ポジション保有数を調べるにはOrdersTotal()を使います。
    しかし、このOrdersTotal()は
    買い建玉、売り建玉、指値買い、指値売り、逆指値買い、逆指値売り
    そして、同時に運用しているその他のEAによって注文したオーダーについても見境なく、
    MT4のターミナルに行事されている全てのオーダーをカウントし、値を返してしまいます。

    そのため、対象EAが
    if( OrdersTotal() < MaxPositions )
    {
    }
    という条件文でポジション数の判断をしていた場合、別EAで大量のポジションを保有してしまっていると、
    その時点でこのif文はスルーされ、対象EAのエントリー判断ロジックに無関係に全てのエントリーを見送ることになってしまいます。


    今回僕のEAエントリーフラグをスルーし続けていたのはこのためでした。


    さて解決策ですが、この様な関数を使えば良いと思います。

    int Check_Positions_Type(int orderstype)
    {
    int r = 0;
    for(int i=0; i<=OrdersTotal()-1; i++)
    {
    if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) == false) break;
    if(OrderMagicNumber() != MAGIC || OrderSymbol() !=Symbol()) continue;
    if(OrderType() == orderstype)
    {
    r++;
    }
    }
    return(r);
    }


    if(OrderMagicNumber() != MAGIC || OrderSymbol() !=Symbol()) continue;
    の一文は、マジックナンバーと取引通貨ペアからこのEAで注文を出したオーダーのみをカウントさせるための条件文で、
    if(OrderType() == orderstype)
    は、特定注文についてのみカウントさせる条件文です。
    引数に以下の数値を設定でき、返り値として任意のオーダー種の数を取得できます。

    0 = 成行買い
    1 = 成行売り
    2 = 指値買い
    3 = 指値売り
    4 = 逆指値買い
    5 = 逆指値売り


    これらはほとんどが“FXメタトレーダー実践プログラミング”からの引用です。
    FXメタトレーダー実践プログラミング (現代の錬金術師シリーズ)
    FXメタトレーダー入門―最先端システムトレードソフト使いこなし術
    ↑(amazonへのリンクです。僕はこの2冊のみでMQLを習得することができました。超良書ですよ。)
     



    さて、この関数を使えば、問題の箇所である
    if( OrdersTotal() < MaxPositions ){
    }
    で条件処理を行なっている部分を、

    if( Check_Positions_Type(int orderstype) < MaxPositions ){
    }

    と書き換えることで、このEAによって約定したポジション数のみを調べることができ、冒頭の問題はクリアできます。




    バックテストではバッチリ動作するのに、
    なんでライブトレードではトレードしてくれないんだ!!!!
    とか、
    あれ、バックテストとフォワードテストの取引回数が違うぞ??

    って場合はこの辺の可能性を疑ってみてもよいかもしれません。


    ( 2011/02/28 20:41 ) Category コード的なこと | TB(0) | CM(3)

    Trade context is busy対策 

    真剣に約定拒否対策に乗り出すにあたり、
    ERR_TRADE_CONTEXT_BUSY 146 Trade context is busy.
    について調べました。

    ■発生理由
    複数EAを同時に運用する場合、EAのオーダー処理の競合が大きな問題になってきます。
    MT4では、複数のオーダーを同時に発注することができないからです。
    そして、その時にエラーメッセージとして表示されるのが
    ERR_TRADE_CONTEXT_BUSY 146 Trade context is busy.
    です。

    MT4上で運用される複数のEAはまるで同時処理されている様に見えますが、
    実際のところ、それぞれのプログラムがきっちり順番に処理されています。
    もし前の順番のEAの処理が残っていれば、次のEAに障害が出るわけです。
    それが最も顕著なのが、注文処理です。
    一つのEAによって発生した注文処理は、メタトレーダーを通してブローカーとのやりとりを行いますが、
    その間に別のEAからオーダーが入ると、後から発注されたオーダーは処理されず、エラーとなってしまうのです。

    それを踏まえて対応を考える必要があります。


    ■対処
    ERR_TRADE_CONTEXT_BUSY 146 Trade context is busy.
    こいつが出ている以上、オーダーは通っていません。
    なぜなら、別のEAの注文によってメタトレーダーとブローカーがやりとりを行っている最中だからですね。
    ゆえに、これを避けるには注文処理が終わるのを待つ以外ありません。

    まずは競合の有無を調べましょう。

    今現在 ERR_TRADE_CONTEXT_BUSY 146 Trade context is busy. が発生するような状態なのか、
    注文の競合が起こる状態なのか。という事を事前にチェックした上で、競合するようならば
    しばらく待機してから発注をかける必要があります。

    このチェックを行う関数が、

    IsTradeAllowed()


    です。
    こいつは、返り値がbool型の関数で、
    今はどんな注文も入ってないからチャンスだよ!って時は、
    IsTradeAllowed()=true
    今は前のオーダーの注文処理中だからエラーんなるよ!って時は、
    IsTradeAllowed()=false
    を返します。

    ここで競合が発生していた場合、待ちをかける必要があります。
    方法は2つ。
    ①EAの処理の中でwaitを入れる方法
    ②オーダが通らなかった場合は再度EAを呼び出す方法
    です。

    対処① EAの処理の中でwaitを入れる方法
    注文が約定するまで、ひたすらwhileループでオーダーをかけ続ける方法です。
    延々と146 Trade context is busy.が出続けるでしょうが、そんなもの何回出ようが知ったことではありません。
    とにかく約定するまで繰り返し続けます。
    注意点は2つ。再注文を出すまで何秒間待機させるかきちんと設定しておくことと、
    無限ループに陥らないよう、ループの脱出に気を使うことです。
    これは
    ERR_OFF_QUOTES 136 Off quotes.
    ERR_BROKER_BUSY 137 Broker is busy.
    ERR_REQUOTE 138 Requote.
    らの約定拒否対策にも使えますので、詳しくは近いうちに書きたいと思います。


    対処② 次のtickまで待たせる方法
    ①に比べると効果は限定的ですが、コード自体はこっちの方が簡単です。

    int start()
    {
    if(IsTradeAllowed() == false) return(0);

    .....
    }

    という感じでメイン関数を呼び出した直後に注文可能であるか判断し、
    このEAの注文を受ける準備ができていなければ、 return(0)によってメイン関数(start())を終了します。
    これだけです。
    MT4の仕様上、次回start()が呼び出されるのは次のtickが更新されたときになるので、
    その時には恐らく注文処理は終了していることでしょう。




    詳しくはこちら。
    http://articles.mql4.com/141
    英語なので大変ですが、
    このエラーの発生理由から様々なケースの対処法とそのコードまでとても詳しく書かれています。

    あ、例によって愛読書にもキッチリ書かれていますよ。
    FXメタトレーダー実践プログラミング (現代の錬金術師シリーズ)
    FXメタトレーダー入門―最先端システムトレードソフト使いこなし術

    ( 2011/08/06 19:01 ) Category コード的なこと | TB(0) | CM(0)

    約定拒否対策 

    最近約定拒否が多発しています。
    オープンのタイミングを逃すのはまぁ良いとして、イグジットタイミングを逸するのは致命的です。

    約定拒否原因として考えられるのは、
    ①前回処理(ブローカーとの通信)が終了していないためエラーになるケース
    ②相場が激しく動き、設定した価格で取引ができないケース

    の二つだと思います。
    先日、Trade context is busy対策を書きましたが、
    これは①の問題に対する対処法です。

    ここでのメインは、②。
    週明け、指標など、相場の激動によって発生する約定エラー対策です。

    対象となるエラーメッセージはこいつら。

    ERR_OFF_QUOTES 136 Off quotes.
    (ブローカー側で現在の価格を公示が出来ない相場状態なっている。相場が落ち着くまで待つしか無い??)
    ERR_BROKER_BUSY 137 Broker is busy.
    (ブローカービジー。これもエラー136同様、待つしか方法は無い様な感じ。)
    ERR_REQUOTE 138 Requote.
    (激しい価格変化のため、発注しようとした価格が間に合わず公示価格が既に変ってしまった状態)

    これらのエラーは全て、一定の時間を空けて再注文することで対処可能です。


    即ち・・・下記のようにOrderClose()関数を改良して、
    エラー発生時には時間をおいて再オーダーをかけることで対処可能です。

    改良OrderClose()は、SecureOrderClose()としました。

    int SecureOrderClose()
    {
    for(int i=OrdersTotal()-1; i>=0; i--)
    {
    if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) == false) break;
    if(OrderMagicNumber() != MAGIC || OrderSymbol() !=Symbol()) continue;

    while(true)
    {
    if(IsTradeAllowed() == true) //----①
    {
    RefreshRates();//----②
    if(OrderClose(OrderTicket(),OrderLots(),closeprice,Slippage*10,Gray)==true)
    {
    break;//----③
    }
    }
    Sleep(100); //----④
    }
    }
    }


    ① ここでブローカーとの通信が可能か判定
    ② 実は重要。waitを掛けると価格が過去のものとなるため、ここで再度通貨の価格を取得。
    ③ 正しくクローズが通れば(trueが返れば)、whileを抜ける
    ④ 正しくクローズ出来なければ(falseが返れば)、100ミリ秒待ってやり直し。


    これは例によって市販の解説書を参考としたものですので、詳細に書くのは控えたいと思います。ご了承下さい。

    ( 2011/08/06 19:17 ) Category コード的なこと | TB(0) | CM(0)
    プロフィール

    asahi_fx

    Author:asahi_fx
    日々のEA開発記録を綴っています。

    忙しい時は全然更新できませんが、
    進展がある度に少しづつ書いていこうと思います。



    運用中のEA


    Batou_EURUSD_1h_L
    Batou_AUDUSD_1h_L
    Batou_Counter_EURUSD_1h_L
    Batou_Counter_EURUSD_30min_L
    Ishikawa_EURUSD_1h_L
    Ishikawa_AUDUSD_1h_L
    Ishikawa_EURGBP_30min_L
    Ishikawa_USDJPY_1h_S
    Ishikawa_USDJPY_30min_S
    Togusa_USDJPY_1h_L
    Togusa_USDJPY_1h_S
    Togusa_USDJPY_5min_S
    Togusa_EURCHF_1h_S
    Togusa_EURCHF_5min_S
    Borma_USDJPY_15min
    Borma_EURUSD_15min
    Borma_GBPUSD_15min
    Paz_WPR_gradient_USDJPY_15min
    Pza_heikin_EURUSD_1h