
マジックナンバー:オーダー"マジック"識別子
1. はじめに
MT3では、オープンポジションの管理は時間の取得をおこなうことでおこなっていました。トレーダーは任意にオープン・クローズポジションのリストを使って動作するよう非常に限られたツールセットしか持っていませんでした。”固有の”ポジションと”別の”ポジションとを区別するには、かなり複雑な方法でおこなっていました。MT4では、この状況は大幅に改善しました。今ではトレーダーは多種多様な関数を使用することができ、全てのオープンポジションと注文を完璧に管理し、クローズポジションに関する情報にアクセスすることができます。
マジックナンバーと名付けられた特別なパラメーターが識別子に加えられました。これが本稿で取り扱うパラメーターです。
2. マジックナンバーとは?
MQL4 リファレンス:
int OrderSend( string symbol, int cmd, double volume, double price, int slippage, double stoploss, double takeprofit, string comment=NULL, int magic=0, datetime expiration=0, color arrow_color=CLR_NONE)
…
magic - オーダーマジックナンバーユーザー定義の識別子として使用できます。
つまりどういうことかと言うと、オーダーを注文した時(ポジションがオープンした時)、そのオーダーに固有の番号を割り当てることができるのです。この番号は他のオーダーと区別するために使うことができます。この機能を裁量トレードで使用することは(可能性も)ありませんが、エキスパートアドバイザーを使用したトレード(自動トレード)をおこなう時にとてもに役立ちます。
例その1: 裁量トレードとエキスパートアドバイザーによるトレードをクライアントターミナルで同時におこなう場合。
タスク: エキスパートアドバイザーはそのアルゴリズムに従ってトレードをおこない、手動でポジションをオープンできないようにしなければいけません。
解決策: エキスパートアドバイザーがオープンされたポジションに、固有のゼロでないマジックナンバーを割り当てるようにします。時間が経過しても、現在のマジックナンバーと同一のポジションのみを管理します。
例その2: 2つの異なるアルゴリズムを持ったエキスパートアドバイザーがクライアントターミナルで同時にトレードする場合。
タスク: エキスパートアドバイザーは”自分の”オーダーのみ管理しなければいけません。
解決策: 各エキスパートアドバイザーは、ポジションをオープンする際に固有のゼロでないマジックナンバーを使用します。時間が経過しても、現在のマジックナンバーと同一のポジションのみを管理します。
例その3: 複数のエキスパートアドバイザーや裁量トレード、非標準トレーリングストップができる補助エキスパートアドバイザーがクライアントターミナルで同時におこなわれている場合。
タスク: トレードをおこなうエキスパートアドバイザーはそのアルゴリズムに従ってトレードをおこない、手動でポジションをオープンできないようにしなければいけません。トレーリングストップをおこなう補助エキスパートアドバイザーは手動でオープンしたポジションのみを修正し、他のエキスパートアドバイザーがオープンしたものを修正してはいけません。
解決策: エキスパートアドバイザーは固有のマジックナンバーを使用し”自分の”ポジションだけを管理します。補助エキスパートアドバイザーはゼロであるマジックナンバーを持つポジションのみを修正します。
これら3つの例はすべて典型的な課題で、ユーザーはこのような課題に自ら取り組んできたことでしょう。3つの例はすべて、マジックナンバーを使用することで解決できます。込み入った方法ではありません。非常に簡単な方法で解決できます。
3. 実際のコードについて
それではここで、あるタスクを解決していきましょう。手動でポジションをオープンしたり、他のエキスパートアドバイザーがポジションをオープンしたりしないよう、”自分の”ポジションのみを扱うエキスパートアドバイザーを作成しましょう。
まず最初に簡単なエキスパートアドバイザーを作成します。ポジションオープンのシグナルが、MACDインディケーターのゼロラインを満たした場合に発生するというものです。このエキスパートアドバイザーのコードは次のようになるでしょう。
int start() { //---- 後の分析に必要なインディケーターの値を記憶します。 //----1番目と2番目のバーを使用しています。これはバー1本分遅れるということです。 //---- (つまり、シグナルは後になって現れます。)1本のバーでポジションのオープンとクローズを繰り返していしまう //---- ことを防ぎます。 double MACD_1 = iMACD( Symbol(), 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, 1 ); double MACD_2 = iMACD( Symbol(), 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, 2 ); int _GetLastError = 0, _OrdersTotal = OrdersTotal(); //---- 全オープンポジションを検索 for ( int z = _OrdersTotal - 1; z >= 0; z -- ) { //---- ポジション選別時にエラーが発生した場合、次へ移動 if ( !OrderSelect( z, SELECT_BY_POS ) ) { _GetLastError = GetLastError(); Print( "OrderSelect( ", z, ", SELECT_BY_POS ) - エラー #", _GetLastError ); continue; } //---- 現在使用している通貨ペアでポジションがオープンされていない場合、スキップ。 if ( OrderSymbol() != Symbol() ) continue; //---- 買いポジションがオープンしている場合 if ( OrderType() == OP_BUY ) { //---- MACDがゼロラインへ上から到達した場合 if ( NormalizeDouble( MACD_1, Digits + 1 ) < 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) >= 0.0 ) { //---- ポジションをクローズ if ( !OrderClose( OrderTicket(), OrderLots(), Bid, 5, Green ) ) { _GetLastError = GetLastError(); Alert( "エラー OrderClose # ", _GetLastError ); return(-1); } } //---- アラートが変更しない場合、イグジット。新たにポジションをオープンするには早急ということです。 else return(0); } //---- 売りポジションがオープンしている場合 if ( OrderType() == OP_SELL ) { //---- MACDがゼロラインへ下から到達した場合 if ( NormalizeDouble( MACD_1, Digits + 1 ) > 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) <= 0.0 ) { //---- ポジションをクローズ if ( !OrderClose( OrderTicket(), OrderLots(), Ask, 5, Red ) ) { _GetLastError = GetLastError(); Alert( "エラー OrderClose # ", _GetLastError ); return(-1); } } //---- アラートが変更しない場合、イグジット。新たにポジションをオープンするには早急ということです。 else return(0); } } //+------------------------------------------------------------------+ //| この時点まで到達したなら、オープンポジションはな存在しないということです。 | //| まだポジションをオープンする可能性があるかチェック | //+------------------------------------------------------------------+ //---- MACDがゼロラインへ下から到達した場合 if ( NormalizeDouble( MACD_1, Digits + 1 ) > 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) <= 0.0 ) { //---- 買いポジションをオープン if ( OrderSend( Symbol(), OP_BUY, 0.1, Ask, 5, 0.0, 0.0, "MACD_test", 0, 0, Green ) < 0 ) { _GetLastError = GetLastError(); Alert( "エラー OrderSend # ", _GetLastError ); return(-1); } return(0); } //---- MACDがゼロラインへ上から到達した場合 if ( NormalizeDouble( MACD_1, Digits + 1 ) < 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) >= 0.0 ) { //---- 売りポジションオープン if ( OrderSend( Symbol(), OP_SELL, 0.1, Bid, 5, 0.0, 0.0, "MACD_test", 0, 0, Red ) < 0 ) { _GetLastError = GetLastError(); Alert( "エラー OrderSend # ", _GetLastError ); return(-1); } return(0); } return(0); }
チャート上で稼働させてみましょう。
全て大丈夫なようにみえます。しかしここで問題があります。エキスパートアドバイザーが稼働中にポジションを手動でオープンした場合、そのポジションは”自分の”ポジションとして扱われてしまうのです。これは望むことではありません。
”自分の”ポジションだけを管理するようエキスパートアドバイザーを修正しましょう。
- エキスパートアドバイザーがオープンしたポジションのマジックナンバーの値を変更するのに使用する、Expert_IDと名付けた外部変数を付け加えます。
- OrderSelect()関数によってオーダーを選択した後、そのオーダーのマジックナンバーが、Expert_ID変数のナンバーをコンパイルしたかチェックします。
- ポジションをオープンしている最中は、0の代わりにExpert_IDの値をマジックナンバーのフィールドに書き込みます。
これまでの変更を反映したコードは次のとおりです。
extern int Expert_ID = 1234; int start() { //---- 後の分析に必要なインディケーターの値を記憶します。 //----1番目と2番目のバーを使用しています。これはバー1本分遅れるということです。 //---- (つまり、シグナルは後になって現れます。)1本のバーでポジションのオープンとクローズを繰り返していしまう //---- ことを防ぎます。 double MACD_1 = iMACD( Symbol(), 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, 1 ); double MACD_2 = iMACD( Symbol(), 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, 2 ); int _GetLastError = 0, _OrdersTotal = OrdersTotal(); //---- 全オープンポジションを検索 for ( int z = _OrdersTotal - 1; z >= 0; z -- ) { //---- ポジション選別時にエラーが発生した場合、次へ移動 if ( !OrderSelect( z, SELECT_BY_POS ) ) { _GetLastError = GetLastError(); Print( "OrderSelect( ", z, ", SELECT_BY_POS ) - エラー #", _GetLastError ); continue; } //---- 現在使用している通貨ペアでポジションがオープンされていない場合、スキップ。 if ( OrderSymbol() != Symbol() ) continue; //---- マジックナンバーがExpert_IDと一致しない場合、ポジションをスキップ。 if ( OrderMagicNumber() != Expert_ID ) continue; //---- 買いポジションをオープンしている場合 if ( OrderType() == OP_BUY ) { //---- MACDがゼロラインへ上から到達した場合 if ( NormalizeDouble( MACD_1, Digits + 1 ) < 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) >= 0.0 ) { //---- ポジションをクローズ if ( !OrderClose( OrderTicket(), OrderLots(), Bid, 5, Green ) ) { _GetLastError = GetLastError(); Alert( "エラー OrderClose # ", _GetLastError ); return(-1); } } //---- アラートが変更しない場合、イグジット。新たにポジションをオープンするには早急ということです。 else { return(0); } } //---- 売りポジションがオープンしている場合 if ( OrderType() == OP_SELL ) { //---- MACDがゼロラインへ下から到達した場合 if ( NormalizeDouble( MACD_1, Digits + 1 ) > 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) <= 0.0 ) { //---- ポジションをクローズ if ( !OrderClose( OrderTicket(), OrderLots(), Ask, 5, Red ) ) { _GetLastError = GetLastError(); Alert( "エラー OrderClose № ", _GetLastError ); return(-1); } } //---- アラートが変更しない場合、イグジット。新たにポジションをオープンするには早急ということです。 else return(0); } } //+------------------------------------------------------------------+ //| この時点まで到達したなら、オープンポジションは存在しないということです。 | //| まだポジションをオープンする可能性があるかチェック | //+------------------------------------------------------------------+ //---- MACDがゼロラインへ下から到達した場合 if ( NormalizeDouble( MACD_1, Digits + 1 ) > 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) <= 0.0 ) { //---- 買いポジションをオープン if ( OrderSend( Symbol(), OP_BUY, 0.1, Ask, 5, 0.0, 0.0, "MACD_test", Expert_ID, 0, Green ) < 0 ) { _GetLastError = GetLastError(); Alert( "エラー OrderSend # ", _GetLastError ); return(-1); } return(0); } //---- MACDがゼロラインへ上から到達した場合 if ( NormalizeDouble( MACD_1, Digits + 1 ) < 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) >= 0.0 ) { //---- 売りポジションオープン if ( OrderSend( Symbol(), OP_SELL, 0.1, Bid, 5, 0.0, 0.0, "MACD_test", Expert_ID, 0, Red ) < 0 ) { _GetLastError = GetLastError(); Alert( "エラー OrderSend # ", _GetLastError ); return(-1); } return(0); } return(0); }
これでエキスパートアドバイザーが稼働中でも、ユーザーは手動でポジションをオープンできます。エキスパートアドバイザーが手動でオープンしたポジションに関わることはありません。
4. 1つの通貨ペアシンボルの異なるチャートで複数同時に稼働できるエキスパートアドバイザーについて
同じEAは同じシンボルのチャートでトレードしていますが、例えば異なるタイムフレームでトレードをおこなうことがあります。エキスパートアドバイザーをユーロドル1時間足のチャートと30分足のチャートに同時に作動させようとする場合、互いに干渉しあってしまいます。どちらもオープンポジションを”自分の”ポジションと”みなして”しまい、ポジションを勝手に修正してしまうのです。
この問題は他のエキスパートアドバイザーに別のExpert_IDを割り当てれば解決できます。しかしこれはそれほど便利なものではありません。たくさんの使用中のエキスパートアドバイザーがあると、IDもたくさんあり混乱してしまいます。
この問題はチャート期間をマジックナンバーとして利用することで解決できます。どのようにコードを書けばいいでしょうか?チャート期間にExpert_IDを加えると、2つの異なるチャートに2つの異なるエキスパートアドバイザーが同じマジックナンバーを生成することを可能にします。
そのためExpert_IDを10倍してチャート期間の最後に(正確には1から9までの数字を)付与するのが良いでしょう。
コードは次のようになります。
int Period_ID = 0; switch ( Period() ) { case PERIOD_MN1: Period_ID = 9; break; case PERIOD_W1: Period_ID = 8; break; case PERIOD_D1: Period_ID = 7; break; case PERIOD_H4: Period_ID = 6; break; case PERIOD_H1: Period_ID = 5; break; case PERIOD_M30: Period_ID = 4; break; case PERIOD_M15: Period_ID = 3; break; case PERIOD_M5: Period_ID = 2; break; case PERIOD_M1: Period_ID = 1; break; } _MagicNumber = Expert_ID * 10 + Period_ID;
このコードをエキスパートアドバイザーのinit()関数に加え、Expert_IDをマジックナンバーにすべて置き換えます。
EAの最終形は次の通りです。
extern int Expert_ID = 1234; int _MagicNumber = 0; int init() { int Period_ID = 0; switch ( Period() ) { case PERIOD_MN1: Period_ID = 9; break; case PERIOD_W1: Period_ID = 8; break; case PERIOD_D1: Period_ID = 7; break; case PERIOD_H4: Period_ID = 6; break; case PERIOD_H1: Period_ID = 5; break; case PERIOD_M30: Period_ID = 4; break; case PERIOD_M15: Period_ID = 3; break; case PERIOD_M5: Period_ID = 2; break; case PERIOD_M1: Period_ID = 1; break; } _MagicNumber = Expert_ID * 10 + Period_ID; return(0); } int start() { //---- 後の分析に必要なインディケーターの値を記憶します。 //----1番目と2番目のバーを使用しています。これはバー1本分遅れるということです。 //---- (つまり、シグナルは後になって現れます。)1本のバーでポジションのオープンとクローズを繰り返していしまう //---- ことを防ぎます。 double MACD_1 = iMACD( Symbol(), 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, 1 ); double MACD_2 = iMACD( Symbol(), 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, 2 ); int _GetLastError = 0, _OrdersTotal = OrdersTotal(); //---- 全オープンポジションを検索 for ( int z = _OrdersTotal - 1; z >= 0; z -- ) { //---- ポジション選別時にエラーが発生した場合、次へ移動 if ( !OrderSelect( z, SELECT_BY_POS ) ) { _GetLastError = GetLastError(); Print( "OrderSelect( ", z, ", SELECT_BY_POS ) - エラー #", _GetLastError ); continue; } //---- 現在使用している通貨ペアシンボルでポジションがオープンされていない場合、スキップ。 if ( OrderSymbol() != Symbol() ) continue; //---- マジックナンバーが_MagicNumberと一致しない場合、ポジションをスキップ。 if ( OrderMagicNumber() != _MagicNumber ) continue; //---- 買いポジションをオープンしている場合 if ( OrderType() == OP_BUY ) { //---- MACDがゼロラインへ上から到達した場合 if ( NormalizeDouble( MACD_1, Digits + 1 ) < 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) >= 0.0 ) { //---- ポジションをクローズ if ( !OrderClose( OrderTicket(), OrderLots(), Bid, 5, Green ) ) { _GetLastError = GetLastError(); Alert( "エラー OrderClose # ", _GetLastError ); return(-1); } } //---- アラートが変更しない場合、中止。新たにポジションをオープンするには早急ということです。 else return(0); } //---- 売りポジションがオープンしている場合 if ( OrderType() == OP_SELL ) { //---- MACDがゼロラインへ下から到達した場合 if ( NormalizeDouble( MACD_1, Digits + 1 ) > 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) <= 0.0 ) { //---- ポジションをクローズ if ( !OrderClose( OrderTicket(), OrderLots(), Ask, 5, Red ) ) { _GetLastError = GetLastError(); Alert( "エラー OrderClose № ", _GetLastError ); return(-1); } } //---- アラートが変更しない場合、中止。新たにポジションをオープンするには早急ということです。 else return(0); } } //+------------------------------------------------------------------+ //| この時点まで到達したなら、オープンポジションは存在しないということです。 | //| まだポジションをオープンする可能性があるかチェック | //+------------------------------------------------------------------+ //---- MACDがゼロラインへ下から到達した場合 if ( NormalizeDouble( MACD_1, Digits + 1 ) > 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) <= 0.0 ) { //---- 買いポジションをオープン if ( OrderSend( Symbol(), OP_BUY, 0.1, Ask, 5, 0.0, 0.0, "MACD_test", _MagicNumber, 0, Green ) < 0 ) { _GetLastError = GetLastError(); Alert( "エラー OrderSend # ", _GetLastError ); return(-1); } return(0); } //---- MACDがゼロラインへ上から到達した場合 if ( NormalizeDouble( MACD_1, Digits + 1 ) < 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) >= 0.0 ) { //---- 売りポジションオープン if ( OrderSend( Symbol(), OP_SELL, 0.1, Bid, 5, 0.0, 0.0, "MACD_test", _MagicNumber, 0, Red ) < 0 ) { _GetLastError = GetLastError(); Alert( "エラー OrderSend # ", _GetLastError ); return(-1); } return(0); } return(0); }
このようなコードであれば、エキスパートアドバイザーは複数のチャートで異なる期間で使用することができます。
Expert_ID変数の値は2つのエキスパートアドバイザーを同じシンボルと期間(例えばユーロドル1時間足とユーロドル4時間足)のチャート上で試用する必要がある場合のみ変更しますが、このようなことは非常に稀なケースです。
また、上記のコードを使用して、ユーザーは自分のEAを改良し”外部の”ポジションから”自分の”ポジションを区別するよう”教える”ようにすることができます。
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/1359




- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索