【MQL5】 MT5のEA作成の勉強 その9 複数ポジションをオープンする (1 / 2)

【MQL5】 MT5のEA作成の勉強 その9 複数ポジションをオープンする (1 / 2)

まえがき

 前回の投稿でやっとこさ任意の条件(Parabolic SAR)で取引を行うEAを作ることができました。しかし、そこでブラックボックスとして残ってしまったのが、「ポジション数の制限をどこで行っているのか?」という点です。
  前回の投稿で問題となっていたのは、「新規バーの初めでのみ取引を行う」という条件でした。これを取り外した結果、無事にEA完成にこぎつけたわけですが、どこかで取引を制限しなければ、条件を満たすバーでティックごとにポジションをオープンするという処理になるはずです。しかし、実際には満たしたティックに一回だけ取引を行うようになっていました。
 結果オーライではあるのですが、そこをブラックボックスのままにしておくのは怖いです。それに、このままではナンピンやマーチンゲールのような、条件を満たすたびにポジションを追加するような処理が実現できません。なので、ここで、しっかり理解しておきたいと思います。

デバッグで動作を確認

  まずは、前回の投稿で作製したEAのロングポジションオープン処理の判定を満たした後の処理をデバッグモードで追ってみたいと思います。まず、ロングポジションオープン処理の直後にブレークポイントを貼り、そこで止まった状態で、ポジションオープン判定処理の部分にブレークポイントを貼って、F5で処理を進めます。

 へっ!?ってなりました。次にロングポジションオープンの判定が行われたのは、先ほどオープンしたロングポジションがクローズされた後だったのです。即ち、

ポジションがオープンされている間は判定処理そのものが行われていない

ようです。判定結果によらず取引しないなら、そもそも判定する必要はないということでしょう。合理的ですね。

OnTick()での判定

 さて、 ポジションがオープンされている間、判定処理が行われない原因を探るために、再びデバッグモードで調査を行いました。まず、初めに怪しいと睨んだのは、 OnTick() で行われている判定です。処理の詳細は 公式サイトのMACD Sampleのをご確認ください。
 怪しいと思っのは、この処理の中で使われている変数「limit_time」最初にロングポジションをオープンして以降、ロングポジションをクローズするまで、オープンした時刻に固定されていたからです。
 しかし、結論から言うと、ここは無関係でした。 「limit_time」 が固定されていたのは、取引プロセスで何も取引が行われなかった場合、「ExtExpert.Processing()」がFalseを返していたためです。
 では、なぜこんな誤解をしたのかというと、ロングポジションオープン直後の数回のループでは、上記の判定処理を囲んでいる「TimeCurrent()>=limit_time」が常時Falseを返していたからです。しかし、これは、MQL5のループが、FX会社の提供するティックの更新間隔(10秒とか)よりも短い場合に、そこで余分な処理が行われないようにするためのものです。根気強く一行づつ処理を進めていると、大体10秒程度経過した後は、取引処理に入ってはFalseを返して戻るという処理を繰り返すようになります。
 つまるところ、

ここでの判定はポジションの複数保持の判定には無関係。無駄な処理を行わないための処理

ということです。

Processing()での判定

 OnTick() を確認した次はProccessing()を確認しました。すると、中央部に完全にドンピシャな判定を見つけました。以下の部分です。(コメントは理解しやすいように書き換えています。)ポジションをオープンしている場合はクローズもしくは変更の処理を行い、オープンしていなければ、オープン判定を行う、という処理になっているようです。

 すなわち、

ロングポジションが一度オープンされた時点で、それがクローズされるまでは、ポジションオープンの判定は行われない構造になっています。

Processing() のオープンポジションの有無判定を削除 (失敗)

 そこで、この部分の判定を削除して、オープンポジションの有無に関わらず、全ての判定が行われるようにしてみました。
 結論から言いますと、これでは、一度もポジションオープンの判定が行われないという結果になりました。上記の処理では、上から順番にクローズや変更などの取引を試み、どれか一つでも実行されれば(各判定処理に記述した条件に一致しる場合)それ以下の処理は行わずに処理を抜けるようになっています。そして、

全ての取引を無条件に試みる場合、「LongModified()」が常時trueを返してしまう

のです。 LongModified() のコードは 公式サイトのMACD Sampleのをそのまま使っているのですが、この処理に、オープンポジションが無いまま入った場合、当然ながら、注文の変更は行われず、エラーメッセージが出力されます。しかし、エラーメッセージを出力する判定の外に「res = true;」が存在するため、処理の結果によらず、trueが返ります。

Processing() のオープンポジションの有無判定とReturnの書き換え

 さて、上記の実験で、ポジションオープン判定は残した方が良いことが分かりました。ただし、ポジションが存在する場合にもポジションオープン判定を行うように変更する必要があります。加えて、 公式サイトのMACD Sample そのままでは、左記の変更を行っても、 LongModified() が trueを返した時点で処理が終了してしまうので、この部分も、 LongModified() が trueを返し てもポジションオープン判定を行うように変更します。
 実行すると、以下の様に、条件を満たすバーでティックごとにロングポジションをオープンしています。勿論このままでは使い物になりませんが、第一歩はクリアです。

 ・・・と、思ったのですが、このソースでは、一度ロングポジションがクローズされた瞬間、EAが強制終了するという現象が確認されました。しかし、これはコード上の問題ではなく、大量のポジションを持ったために証拠金が足りなくなっただけでした。テスターの証拠金を追加すると無事に流れました。

まとめ

  オープンポジションの有無判定とReturn条件の書き換えで、ポジションオープンの条件を満たす場合に、ポジションを追加する処理を作ることができました。しかし、このままでは、上の図のように、一つのバーで何回もポジションがオープンされ、悲惨なことになるのは明らかです。そこで次回は、一つのバーで複数回のポジションオープンを制限する方法を勉強してゆきたいと思います。