信頼できる仕掛け注文関数

アイキャッチ

MQL4標準の仕掛け注文関数は穴だらけ

各種仕掛け注文(成行、指値、逆指値)を出す、MQL4の標準関数にOrderSend()があります。

注文が必ず通るのであれば、OrderSend()を使えば良いわけですが、実際はそうでもありません。

市場の動きが早くて許容スリッページ内で執行できなかったり、ネットワークの調子が悪くて通信エラーが発生したり、FX業者によっては約定拒否されたりして、うまく注文できない場合があります。

その場合、OrderSend()だけでは不十分で、注文失敗時のフォローが必要になります。

というわけで、OrderSend()の注文が失敗した時を考慮した仕掛け注文関数を紹介します。

orderSendReliable()の引数をOrderSend()と同じにすることで、導入しやすくしています。OrderSend()の代わりにorderSendReliable()を使うことで、より信頼できる仕掛け注文を行えるようになります。

orderSendReliable()とは別に、orderType2String()という関数を定義しています。これは、指定した注文種別の数値(成行注文の場合、0)を文字列(成行注文の場合、BUY)に変換する関数です。ログを見る際、数値では意味が分かりにくいですからね。

orderSendReliable()は単独では起動しません。定数(MAX_RETRY_TIME、MILLISEC_2_SEC)の利用を前提にしているためです。プログラム全体で使い回す値は定数化なりグローバル変数化しておくと便利です。MAX_RETRY_TIMEは注文失敗時の最大リトライ時間を表す定数です。MILLISEC_2_SECはミリ秒を秒の単位に変換するための定数です。

orderSendReliable()のポイントは、利食い/損切り価格が現在価格に近すぎないか、MarketInfo(aSymbol, MODE_STOPLEVEL)とMarketInfo(aSymbol, MODE_FREEZELEVEL)で注文前に確認している点と、一時的エラーによる注文失敗時はif(GetTickCount() – startTime > MAX_RETRY_TIME * MILLISEC_2_SEC){で制限時間までリトライする点です。繰り返しリトライできるように、while(true)で注文処理を無限ループさせています。そして、制限時間に到達したら、ループから抜け出すようにしています。

あと、最適化かバックテストの場合は、注文失敗時によるリトライには意味がないので(最適化かバックテストの場合、何度やっても状況は改善されないので)、一回注文失敗した時点で、if(IsOptimization() || IsTesting()){で強制終了させています。

余談ですが、ECN/STPタイプのFX業者の場合、仕掛け注文時に損切りと利食い価格を同時に指定できないため、損切りと利食いを指定せずに注文後、すぐにOrderModify()で注文変更するテクニックが書籍や記事で紹介されていることがありますが、2014/12/17現在のMT4では解消されていることがMQL4フォーラムで確認されています。そのため、orderSendReliable()では、ECN/STP業者かどうかを考慮していません(する必要がありません)。

なお、orderSendReliable()を作成するにあたって、豊嶋久道氏の「FXメタトレーダー実践プログラミング」、7bit氏の「common_function.mqh」及びMatthew Kennel氏らの「LibOrderReliable.mq4」を参考にしました。

サンプルEA

関数だけではイメージが沸きづらいと思いますので、サンプルEAを載せておきます。

スポンサードリンク

ブログランキングに参加中!

ポチっとクリック頂けると励みになります♪
(クリックしてもランキング一覧が表示されるだけですが、それでOKです)

にほんブログ村 為替ブログ FX システムトレード派へ

10件のコメント

  • たけパパ

    初めて投稿させていただきます。
    「本サイトは凄い!!」と数年前からの陰ながらのファンの私。
    しかしMT4での開発は育児などありしばらく封印していました。
    ですが友人から開発を依頼され、
    久しぶりに本腰を入れて本サイトもまじめに読んだりw
    古い投稿の確認ですみません。
    この関数の引数である「aPrice」ですが
    この値を渡しても途中でBidかAskを突っ込んでいるので指値でなく成行になっちゃいますよね?

    別件なのですがりゅーきさんがどこかでMT4を学ぶ講座か何かを受けたのでしょうか?
    自分もMT4で精進したいのですが何か学べるところとかあり、ご存知でしたら教えてほしいですw

    • りゅーき

      ファンでいてくれてありがとうございます^-^
      さて、ご質問の件。

      orderSendReliableの引数のことだと思いますが、答えは「No」です。

      その理由はif文にあります。
      AskやBidで上書きしているのはOP_BUYかOP_SELLの場合のみです。
      この2つは成行き注文を表します。だから上書きしています。
      指値や逆指値の場合はOP_BUYLIMIT等になるので、上書きされません。

      MT4というより多分MQL4のことだと理解しましたが、書籍とかネット(海外含む)が情報源です。
      ネットで言えばfaiさんのブログ「とあるMetaTraderの備忘秘録」が飛び抜けていますね。
      勉強させてもらっています。更新が停止してしまったのが非常に残念です。

      あとは実践あるのみです。
      とにかく数をこなして壁にぶつかってはネットで解決策を探す&自分でアレンジを加えるを繰り返しています。

      ちなみに開発したい方向けにいつか開発講座みたいなのを開きたいなぁと思っています。

  • たけパパ

    回答ありがとうございます。
    了解しました!そうですね、よく見たら成行の時だけでしたね。
    orderSendReliablを元に改良させていただきました。
    ※引数を減らしなるべく疎結合にしたかったので
    この辺を必須で渡す引数でなく、OPTION化させていただきましたw
    本やら「とあるMetaTraderの備忘秘録」も利用させていただいておりますw
    確かにあそこの情報量も半端ないですねw
    http://d.hatena.ne.jp/fai_fx/20100724/1279912220
    これとか採用させてもらいましたw
    りゅーきさんはこのマジック番号とかどうやってますか?
    本サイトには投稿がなかったのでりゅーきさんの実装方法があったら教えてほしいです。
    利用用途がなかったらいらない機能ですがw

    言葉が雑ですみませんw MQL4のことです。
    やはり書籍・ネットですね。
    本サイトが以前から一番きれいで整理されていて大ファンですw
    りゅーきさん講座がありましたら是非!参加させて下さい!
    懇親会でもなんでも参加しちゃいますw
    これからもよろしくお願いします。

    • りゅーき

      改造はどんどんしていただければと思います。
      そのためにプログラムを公開しておりますので。
      マジックナンバーは原則としてパラメータ化して個別入力する形を取っています。
      そこにはこだわっていません。

      サイトについてお褒めいただき光栄です。
      これからも見やすい分かりやすいサイトを目指していきますので、ご愛読いただければ幸いです。

  • 匿名

    私の勘違いかもしれませんが、ストップレベル、フリーズレベルと比較して近すぎないかを絶対値で判定している箇所が気になりました。

    例えば下記の判定文の場合です。
      if(MathAbs(bid – aStoploss) < stopLevel){
    もしスプレッドが異常に開いて、bidがaStoplossよりも異常に低い価格となった場合、絶対値で判定しているためにこの判定をスルーしてしまうのではないでしょうか。

    そこまでスプレッドが開くのは極端なケースかもしれませんが、、、。

    絶対値を取らずに下記のようにそのまま判定すれば良いのではとおもいました。
    if((bid – aStoploss) < stopLevel){

    決してケチを付けたいのではありません。このブログで公開されているコードに本当に助けられています。

    • りゅーき

      ご指摘ありがとうございます。

      指摘されて改めて考えてみたのですが、なぜ絶対値を取るようにしたのか思い出せず(^-^;
      確か最初は入れてなくて、何らかの不都合があってこうした記憶がおぼろげながらあります。

      明確な答えを出せずに恐縮です。
      絶対値を取る目的を思い出したら、追加コメントいたします。

      こんなこと言うのもアレですが…このエラーチェックは別に無くても良いかなぁと思ってたりもします。
      ダラダラとコードは長いし、分かりにくいし。
      近づき過ぎてたら、自分でエラーチェックしなくてもMT4が勝手にエラー出してくれますしね。
      エラー時に何らかの処理を入れてるわけでもないので、とっぱらちゃうのも1つの手かと思います。
      そのうち気が向いたらそうするかもしれません。

      要らない、おかしいと思ったらどんどんカスタマイズしちゃってください。
      それで問題が起きたら直せばいいだけです。
      それぐらいの気持ちの方が続けられます。

  • lux

    はじめまして、luxと申します。
    貴サイトでは有用なTIPSをたくさん得られ感謝しております。
    特にOrderSend関数のwrapperとして使える当関数にはとても助けられています。

    さて、当関数を使うにあたり、私が引っ掛かり、かつ今後MQL4初心者が引っかかり得る問題があるのでご連絡します。
    (もっとも、この関数に渡す前にNormalizeDoubleをかけなかった場合に起こり得るだけの問題ですが)

    “aPrice”もNormalizeDoubleをかけないと、下記のようなエラーが出ます。
    “invalid price 110.75555556 for OrderSend function”

    • りゅーき

      ご指摘感謝です。
      double型はこの手の計算誤差が常に付きまとうんですよね。
      意識はしているのですが、どうしても漏れが発生することがあります。
      double型の誤差についてはそのうち記事で書こうと思います。
      ライブラリも近いうちに修正しますね。

  • まさ

    はじめまして。そしてありがとうございます。
    本サイトのおかげで、数年前にあきらめていたMT4での自動売買ができました。
    どてんのロジックを組んでいたんですが、何度やっても too_many_request エラーが出て困っていたところ、仕切り関数のほうにはこのエラー処理が一時エラーとして記載されており、試しに仕掛けにも入れてみたらばっちり動きました。
    本当にありがとうございます。

    • りゅーき

      お礼のお言葉、ありがとうございます。
      うまく動作したようで良かったです!
      意図した通りに動くと嬉しいですよね。

コメントを残す



one × one =