販売用EA開発 よくあるミス

fx-on.comエンジニアの岩淵です。
今日は販売用EA開発時の注意点についてご紹介させていただきます。
1.マジックナンバーはパラメータにしましょう
たまに見かけるのがマジックナンバーを定義してしまってるEA あるいはグローバル変数として宣言しているEA 悪い例1 プログラム内で定義してる例#define MagicNumber 1234悪い例2 グローバル変数として定義してる例
int MagicNumber = 1234;マジックナンバーの設定ってかなり重要な要素なので、必ずユーザーが設定できるようにしましょう。 複数のEAを運用していてマジックナンバーが被ってしまうと、口座にとって良くないことが起きます。 良い例
extern int MagicNumber = 1234;こんな事例もあります。 EAの内部処理では複数のマジックナンバーを使用しているけど、ユーザーが設定できるのは1つだけのEA 例えばEAの処理で2つのマジックナンバーを使用する際に、
extern int MagicNumber = 1;としてマジックナンバーを1つだけ指定させて、もう1つはMagicNumber+1の数値を使用している場合がそうです。 マジックナンバーのパラメータに1を指定して安心していると、1だけではなく2も使われていて他のEAとマジックナンバーが被ってしまったなんてことも起こり得ます。 この場合は処理を変えたりパラメータを増やす必要は無いのですが、商品概要などにパラメータで指定した値以外も使用することを記載していただけると、ユーザーが把握できていいかと思います。 例
MagicNumberに1を指定すると1~10までを使用します繰り返しになりますが、複数のEAを運用していてマジックナンバーが被ってしまうと、口座にとって良くないことが起きます。
2.ポジション管理はチケット番号に頼り過ぎない
MQL4でエントリーするための関数は、皆さんご存知のOrderSend関数です。 OrderSend関数はエントリーに成功すると、戻り値として約定したポジションのチケット番号を返します。 このチケット番号は、ポジションを決済したり、TP/SLを変更したりと、色々な場面で必要になる重要な番号です。 出品物のコードを拝見していると、OrderSend関数から受け取ったチケット番号を変数に代入して、そのまま再利用するようなコードを見かけることがありますが、この方法は問題があります。 チケット番号を変数に代入すると、MT4を再起動したタイミングなどで変数が初期化され、チケット番号が失われてしまいます。 結果としていつまでも決済されない迷子のポジションが生まれます。 迷子ポジションが原因のお問い合わせを、数ヶ月に一度のペースでいただいております。 この現象ってバックテストでは発生しないから気づきにくいんですよね・・・ この問題の解決方法はいくつかありますが、一番オススメの方法をお教えします。 チケット番号が必要な場面(決済時など)の直前でチケット番号を再取得しましょう。 チケット番号の再取得は次のように書けます。 保有中のポジションのチケット番号を取得する場合int ticket = -1;
for(int i = 0; i < OrdersTotal(); i++){
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false) break;
if(OrderMagicNumber() != MagicNumber) continue;
ticket = OrderTicket();
}
決済済みのポジションのチケット番号を取得する場合
int ticket = -1;
for(int i = 0; i < OrdersHistoryTotal(); i++){
if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY) == false) break;
if(OrderMagicNumber() != MagicNumber) continue;
ticket = OrderTicket();
}
保有中の(あるいは決済済みの)全ポジションを順番にチェックしていき、マジックナンバーが一致するポジションのチケット番号を取得するという処理です。
私にとっては親の顔よりよく見た処理です。
チケット番号を取得するためにこのような長いコードを書かなくてはいけないのがMQL4の嫌なところですね・・・
3.通貨ペア名に注意
ソースコード内で特定の通貨ペアをチェックするときには、業者ごとの通貨ペア名の違いに気をつけましょう。 例えばドル円以外の通貨ペアでは稼働させたくない時などです。 悪い例if(Symbol() != "USDJPY") return;チャートの通貨ペアを取得して、ドル円じゃなければ終了する処理ですが、このコードは不十分です。 ドル円の通貨ペア名が「USDJPY」のOANDA Japanデモ口座などでは正しく稼働しますが、同じOANDA Japanでもドル円が「USDJPY-a01」のベーシック口座では正しく稼働しません。 良い例
if(StringSubstr(Symbol(), 0, 6) != "USDJPY") return;チャートの通貨ペアの先頭6文字のみを抽出して、USDJPYと一致しているかを判定させます。 この方法なら、「USDJPY」も、「USDJPY-a01」も、あるいは「USDJPYpro」も全て「USDJPY」として扱われます。 なんで同じドル円なのにブローカーによって名称が違うのでしょうね? たぶん嫌がらせでしょうね・・・
4.資金管理のロジックはドル建ての場合も考慮
ロット数の複利計算を使用しているEAでたまに見かけるミスです。 ユーザーはザックリ分けると、国内で円建てで運用する方と海外でドル建てで運用する方がいます。(もしかするとユーロ建てやフラン建ての人もいるかもしれません) ロット数の計算を円建て前提で計算してしまうと、ドル建てのユーザーのロット数が滅茶苦茶になってしまいます。 ロット数の計算では口座の通貨に左右されない計算方法にしましょう。 だんだん説明が大変になってきたので簡単に書きます。 以下の値を取得してロット数を算出に活かすと、いい感じになる場合が多いです。 1Lot保有している時に最小変動価格分だけ価格が動いた場合に変化する損益を口座の通貨単位で取得できるMarketInfo(Symbol(), MODE_TICKVALUE)1Lot当たりの取引数量を取得する
MarketInfo(Symbol(), MODE_LOTSIZE)最小変動価格を取得する
MarketInfo(Symbol(), MODE_TICKSIZE)余談ですが複利計算処理って人によって計算方法も書き方も全然違うんですよ~ 誰かが「コレだ!」っていう複利計算関数を作ってくれればややこしい計算処理を書かなくて済むのですが・・・



