注文の管理ーこれは簡単です
1. はじめに
各取引エキスパートアドバイザには、オープンポジションの管理ブロックがあります。これは、サイクルの全ての注文の取捨であり、通貨ペアやMagicNumberの値やその後の値の変化またはクローズによる『自分の』ポジションの選択です。このようなブロックはとても似ていて、多くの場合、同様の機能を有しています。よって、この重複するコードの一部をエキスパートアドバイザから関数に運び出すと、エキスパートアドバイザの作成を大きく簡素化することができ、エキスパートアドバイザのコードがコンパクトになります。
まず初めに、課題を難易度や機能性が異なる3つの段階に分けましょう。これらは、エキスパートアドバイザの3つの種類と一致します。
- 一度に一つのポジションのみ開くことができるエキスパートアドバイザ。
- 各タイプにつき一つずつのポジションを開くことができるエキスパートアドバイザ。(例えば、一つは買いポジション、もう一つは売りポジション)
- 好きなだけポジションを開くことができるエキスパートアドバイザ。
2. 一つのポジション
一つのポジションのみを使用する戦略は沢山存在します。それらのポジションコントロールブロックは、十分簡単なものですが、少なくとも作成には時間と注意を要します。
では、MACD線の交点で動作するポジションオープンのシグナルの簡単なエキスパートアドバイザを用いて、そのポジションコントロールブロックを簡素化します。処理前はこのようになります。
extern int _MagicNumber=1122; int start() { //---- 今後の分析の為のインディケータ値を記憶します 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 ) - Error #",_GetLastError); continue; } // もしポジションが現在のツールで開いていない場合、スキップします if(OrderSymbol()!=Symbol()) continue; // もしMagicNumberが_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); }
ここで、ポジションコントロールのブロックに代わる関数を書く必要があります。この関数は全ての注文を取捨し、必要なものを見つけ、その全ての特性をグローバル変数に記憶します。これは以下のようになります。
int _Ticket = 0, _Type = 0; double _Lots = 0.0, _OpenPrice = 0.0, _StopLoss = 0.0; double _TakeProfit = 0.0; datetime _OpenTime = -1; double _Profit = 0.0, _Swap = 0.0; double _Commission = 0.0; string _Comment = ""; datetime _Expiration = -1; void OneOrderInit( int magic ) { int _GetLastError, _OrdersTotal = OrdersTotal(); _Ticket = 0; _Type = 0; _Lots = 0.0; _OpenPrice = 0.0; _StopLoss = 0.0; _TakeProfit = 0.0; _OpenTime = -1; _Profit = 0.0; _Swap = 0.0; _Commission = 0.0; _Comment = ""; _Expiration = -1; for ( int z = _OrdersTotal - 1; z >= 0; z -- ) { if ( !OrderSelect( z, SELECT_BY_POS ) ) { _GetLastError = GetLastError(); Print("OrderSelect( ", z, ", SELECT_BY_POS ) - Error #", _GetLastError ); continue; } if ( OrderMagicNumber() == magic && OrderSymbol() == Symbol() ) { _Ticket = OrderTicket(); _Type = OrderType(); _Lots = NormalizeDouble( OrderLots(), 1 ); _OpenPrice = NormalizeDouble( OrderOpenPrice(), Digits ); _StopLoss = NormalizeDouble( OrderStopLoss(), Digits ); _TakeProfit = NormalizeDouble( OrderTakeProfit(), Digits ); _OpenTime = OrderOpenTime(); _Profit = NormalizeDouble( OrderProfit(), 2 ); _Swap = NormalizeDouble( OrderSwap(), 2 ); _Commission = NormalizeDouble( OrderCommission(), 2 ); _Comment = OrderComment(); _Expiration = OrderExpiration(); return; } } }
ご覧のように、全ては簡単です。11の変数があり、それぞれがポジションの特性の一つを保存しています。(チケット番号、タイプ、ロットサイズなど)関数の始めにこれらの変数のゼロ化が行われます。これらはグローバル変数で宣言され、関数の呼び出し時にゼロ化されず、私たちには前のティックからの情報は必要ではなく、全てのデータは最新のものでなければならないので、これは必要不可欠です。それから、全てのオープンポジションの標準的な取捨が行われ、シンボルとMagicNumber値の一致があった場合、対応する変数に特性が記憶されます。
それでは、私たちのエキスパートアドバイザにこの関数を入れましょう。
extern int _MagicNumber = 1122; #include <OneOrderControl.mq4> int start() { int _GetLastError = 0; //---- オープンポジションのパラメータを記憶します(もしこれがある場合) OneOrderInit( _MagicNumber ); //---- 今後の分析の為のインディケータ値を記憶します 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 ); // ここで、ポジションの品分けの代わりに、ただ // オープンポジションがあるかどうかを見てみましょう: if ( _Ticket > 0 ) { //---- もし買いポジションが開いている場合 if ( _Type == OP_BUY ) { //---- もしMACDがゼロラインと下向きに交差した場合、 if ( NormalizeDouble( MACD_1, Digits + 1 ) < 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) >= 0.0 ) { //---- ポジションを閉じます if ( !OrderClose( _Ticket, _Lots, Bid, 5, Green ) ) { _GetLastError = GetLastError(); Alert( "エラー OrderClose № ", _GetLastError ); return(-1); } } // もしシグナルが変わらない場合、終了します。まだ // 新しいポジションを開くには早いです else return(0); } //---- もし売りポジションが開いている場合、 if ( _Type == OP_SELL ) { //---- もしMACDが上向きにゼロラインと交差した場合、 if ( NormalizeDouble( MACD_1, Digits + 1 ) > 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) <= 0.0 ) { //---- ポジションを閉じます if ( !OrderClose( _Ticket, _Lots, Ask, 5, Red ) ) { _GetLastError = GetLastError(); Alert( "エラー OrderClose № ", _GetLastError ); return(-1); } } // もしシグナルが変わらない場合、終了します。まだ // 新しいポジションを開くには早いです else return(0); } } //---- もしエキスパートアドバイザによって開かれたポジションがない場合( _Ticket == 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, "CrossMACD", _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, "CrossMACD", _MagicNumber, 0, Red ) < 0 ) { _GetLastError = GetLastError(); Alert( "エラー OrderSend № ", _GetLastError ); return(-1); } return(0); } return(0); }
3. 一つのタイプの一つのポジション
次の関数の実装の為には、より複雑なエキスパートアドバイザが必要です。エキスパートアドバイザには、異なるタイプの複数のポジションを開き、その後でそれらと何か行う必要があります。それでは、エキスパートアドバイザのアルゴリズムを形作ってみましょう。
- 起動時にエキスパートアドバイザは、+20ポイントのASKレベルでのバイストップと−20ポイントのBIDレベルでのセルストップの2つの指値注文を設定する必要があります。
- 注文のうちの1つが作動した場合には、もう1つは削除される必要があります。
- オープンポジションは、トレーリングストップを伴う必要があります。
- ストップロスまたはテイクプロフィットによってポジションが閉じられた後、最初のポイントに移ります。つまり、もう一度2つの指値注文を設定します。
エキスパートアドバイザのコードは次のようになります。
extern int _MagicNumber = 1122; #include <OneOrderControl.mq4> int start() { int _GetLastError = 0; //---- オープンポジションのパラメータを記憶します(もしこれがある場合) OneOrderInit( _MagicNumber ); //---- 今後の分析の為のインディケータ値を記憶します 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 ); // ここで、ポジションの品分けの代わりに、ただ // オープンポジションがあるかどうかを見てみましょう: if ( _Ticket > 0 ) { //---- もし買いポジションが開いている場合 if ( _Type == OP_BUY ) { //---- もしMACDがゼロラインと下向きに交差した場合、 if ( NormalizeDouble( MACD_1, Digits + 1 ) < 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) >= 0.0 ) { //---- ポジションを閉じます if ( !OrderClose( _Ticket, _Lots, Bid, 5, Green ) ) { _GetLastError = GetLastError(); Alert( "エラー OrderClose № ", _GetLastError ); return(-1); } } // もしシグナルが変わらない場合、終了します。まだ // 新しいポジションを開くには早いです else return(0); } //---- もし売りポジションが開いている場合、 if ( _Type == OP_SELL ) { //---- もしMACDが上向きにゼロラインと交差した場合、 if ( NormalizeDouble( MACD_1, Digits + 1 ) > 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) <= 0.0 ) { //---- ポジションを閉じます if ( !OrderClose( _Ticket, _Lots, Ask, 5, Red ) ) { _GetLastError = GetLastError(); Alert( "エラー OrderClose № ", _GetLastError ); return(-1); } } // もしシグナルが変わらない場合、終了します。まだ // 新しいポジションを開くには早いです else return(0); } } //---- もしエキスパートアドバイザによって開かれたポジションがない場合( _Ticket == 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, "CrossMACD", _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, "CrossMACD", _MagicNumber, 0, Red ) < 0 ) { _GetLastError = GetLastError(); Alert( "エラー OrderSend № ", _GetLastError ); return(-1); } return(0); } return(0); }
それでは、オープンポジションのコントロールブロックを簡素化する関数を書きます。この関数は、各タイプの1つの注文ごとに見つけ、その特性をグローバル変数に保存します。それは次のようになります:
// 注文の特性が保存される // グローバル変数: int _BuyTicket = 0, _SellTicket = 0, _BuyStopTicket = 0; int _SellStopTicket = 0, _BuyLimitTicket = 0, _SellLimitTicket = 0; double _BuyLots = 0.0, _SellLots = 0.0, _BuyStopLots = 0.0; double _SellStopLots = 0.0, _BuyLimitLots = 0.0, _SellLimitLots = 0.0; double _BuyOpenPrice = 0.0, _SellOpenPrice = 0.0, _BuyStopOpenPrice = 0.0; double _SellStopOpenPrice = 0.0, _BuyLimitOpenPrice = 0.0, _SellLimitOpenPrice = 0.0; double _BuyStopLoss = 0.0, _SellStopLoss = 0.0, _BuyStopStopLoss = 0.0; double _SellStopStopLoss = 0.0, _BuyLimitStopLoss = 0.0, _SellLimitStopLoss = 0.0; double _BuyTakeProfit = 0.0, _SellTakeProfit = 0.0, _BuyStopTakeProfit = 0.0; double _SellStopTakeProfit = 0.0, _BuyLimitTakeProfit = 0.0, _SellLimitTakeProfit = 0.0; datetime _BuyOpenTime = -1, _SellOpenTime = -1, _BuyStopOpenTime = -1; datetime _SellStopOpenTime = -1, _BuyLimitOpenTime = -1, _SellLimitOpenTime = -1; double _BuyProfit = 0.0, _SellProfit = 0.0, _BuySwap = 0.0, _SellSwap = 0.0; double _BuyCommission = 0.0, _SellCommission = 0.0; string _BuyComment = "", _SellComment = "", _BuyStopComment = ""; string _SellStopComment = "", _BuyLimitComment = "", _SellLimitComment = ""; datetime _BuyStopExpiration = -1, _SellStopExpiration = -1; datetime _BuyLimitExpiration = -1, _SellLimitExpiration = -1; void OneTypeOrdersInit( int magic ) { // 変数のゼロ化: _BuyTicket = 0; _SellTicket = 0; _BuyStopTicket = 0; _SellStopTicket = 0; _BuyLimitTicket = 0; _SellLimitTicket = 0; _BuyLots = 0.0; _SellLots = 0.0; _BuyStopLots = 0.0; _SellStopLots = 0.0; _BuyLimitLots = 0.0; _SellLimitLots = 0.0; _BuyOpenPrice = 0.0; _SellOpenPrice = 0.0; _BuyStopOpenPrice = 0.0; _SellStopOpenPrice = 0.0; _BuyLimitOpenPrice = 0.0; _SellLimitOpenPrice = 0.0; _BuyStopLoss = 0.0; _SellStopLoss = 0.0; _BuyStopStopLoss = 0.0; _SellStopStopLoss = 0.0; _BuyLimitStopLoss = 0.0; _SellLimitStopLoss = 0.0; _BuyTakeProfit = 0.0; _SellTakeProfit = 0.0; _BuyStopTakeProfit = 0.0; _SellStopTakeProfit = 0.0; _BuyLimitTakeProfit = 0.0; _SellLimitTakeProfit = 0.0; _BuyOpenTime = -1; _SellOpenTime = -1; _BuyStopOpenTime = -1; _SellStopOpenTime = -1; _BuyLimitOpenTime = -1; _SellLimitOpenTime = -1; _BuyProfit = 0.0; _SellProfit = 0.0; _BuySwap = 0.0; _SellSwap = 0.0; _BuyCommission = 0.0; _SellCommission = 0.0; _BuyComment = ""; _SellComment = ""; _BuyStopComment = ""; _SellStopComment = ""; _BuyLimitComment = ""; _SellLimitComment = ""; _BuyStopExpiration = -1; _SellStopExpiration = -1; _BuyLimitExpiration = -1; _SellLimitExpiration = -1; 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 ) - Error #", _GetLastError); continue; } if ( OrderMagicNumber() == magic && OrderSymbol() == Symbol() ) { switch ( OrderType() ) { case OP_BUY: _BuyTicket = OrderTicket(); _BuyLots = NormalizeDouble( OrderLots(), 1 ); _BuyOpenPrice = NormalizeDouble( OrderOpenPrice(), Digits ); _BuyStopLoss = NormalizeDouble( OrderStopLoss(), Digits ); _BuyTakeProfit = NormalizeDouble( OrderTakeProfit(), Digits ); _BuyOpenTime = OrderOpenTime(); _BuyProfit = NormalizeDouble( OrderProfit(), 2 ); _BuySwap = NormalizeDouble( OrderSwap(), 2 ); _BuyCommission = NormalizeDouble( OrderCommission(), 2 ); _BuyComment = OrderComment(); break; case OP_SELL: _SellTicket = OrderTicket(); _SellLots = NormalizeDouble( OrderLots(), 1 ); _SellOpenPrice = NormalizeDouble( OrderOpenPrice(), Digits ); _SellStopLoss = NormalizeDouble( OrderStopLoss(), Digits ); _SellTakeProfit = NormalizeDouble( OrderTakeProfit(), Digits ); _SellOpenTime = OrderOpenTime(); _SellProfit = NormalizeDouble( OrderProfit(), 2 ); _SellSwap = NormalizeDouble( OrderSwap(), 2 ); _SellCommission = NormalizeDouble(OrderCommission(), 2 ); _SellComment = OrderComment(); break; case OP_BUYSTOP: _BuyStopTicket = OrderTicket(); _BuyStopLots = NormalizeDouble( OrderLots(), 1 ); _BuyStopOpenPrice = NormalizeDouble( OrderOpenPrice(), Digits ); _BuyStopStopLoss = NormalizeDouble( OrderStopLoss(), Digits ); _BuyStopTakeProfit = NormalizeDouble( OrderTakeProfit(), Digits ); _BuyStopOpenTime = OrderOpenTime(); _BuyStopComment = OrderComment(); _BuyStopExpiration = OrderExpiration(); break; case OP_SELLSTOP: _SellStopTicket = OrderTicket(); _SellStopLots = NormalizeDouble( OrderLots(), 1 ); _SellStopOpenPrice = NormalizeDouble( OrderOpenPrice(), Digits ); _SellStopStopLoss = NormalizeDouble( OrderStopLoss(), Digits ); _SellStopTakeProfit = NormalizeDouble( OrderTakeProfit(), Digits ); _SellStopOpenTime = OrderOpenTime(); _SellStopComment = OrderComment(); _SellStopExpiration = OrderExpiration(); break; case OP_BUYLIMIT: _BuyLimitTicket = OrderTicket(); _BuyLimitLots = NormalizeDouble( OrderLots(), 1 ); _BuyLimitOpenPrice = NormalizeDouble( OrderOpenPrice(), Digits ); _BuyLimitStopLoss = NormalizeDouble( OrderStopLoss(), Digits ); _BuyLimitTakeProfit = NormalizeDouble( OrderTakeProfit(), Digits ); _BuyLimitOpenTime = OrderOpenTime(); _BuyLimitComment = OrderComment(); _BuyLimitExpiration = OrderExpiration(); break; case OP_SELLLIMIT: _SellLimitTicket = OrderTicket(); _SellLimitLots = NormalizeDouble( OrderLots(), 1 ); _SellLimitOpenPrice = NormalizeDouble( OrderOpenPrice(), Digits ); _SellLimitStopLoss = NormalizeDouble( OrderStopLoss(), Digits ); _SellLimitTakeProfit = NormalizeDouble( OrderTakeProfit(), Digits ); _SellLimitOpenTime = OrderOpenTime(); _SellLimitComment = OrderComment(); _SellLimitExpiration = OrderExpiration(); break; } } } }
それではエキスパートアドバイザに関数を入れます:
extern int _MagicNumber = 1123; extern double Lot = 0.1; extern int StopLoss = 60; // ポイントにおけるストップロスまでの距離(0ーストップロスを無効にする) extern int TakeProfit = 100; // ポイントにおけるテイクプロフィットまでの距離(0ー無効にする) extern int TrailingStop = 50; // ポイントにおけるトレーリングストップのサイズ(0−無効にする) extern int Luft = 20; // 指値注文の設定レベルまでの距離 #include <OneTypeOrdersControl.mq4> int start() { int _GetLastError = 0; //---- オープンポジションのパラメータを記憶します(もしこれがある場合) OneTypeOrdersInit( _MagicNumber ); //---- もし両方の指値注文がある場合、終了します //---- そのうちの1つが作動するまで待つ必要があります if ( _BuyStopTicket > 0 && _SellStopTicket > 0 ) return(0); //---- もし開いている買いポジションがある場合、 if ( _BuyTicket > 0 ) { //---- もしセルストップがまだ削除されていない場合、これを削除します: if ( _SellStopTicket > 0 ) { if ( !OrderDelete( _SellStopTicket ) ) { Alert( "OrderDelete Error #", GetLastError() ); return(-1); } } //---- ストップロスを移動する必要があるかをチェックしましょう: //---- もしトレーリングストップのサイズがあまり小さくない場合、 if ( TrailingStop > MarketInfo( Symbol(), MODE_STOPLEVEL ) ) { //---- もしポジションの利益はTrailingStopポイントよりも大きい場合、 if ( NormalizeDouble( Bid - _BuyOpenPrice, Digits ) > NormalizeDouble( TrailingStop*Point, Digits ) ) { // もし新しいストップロスレベルが、現在のポジションのものよりも高い場合 // (もしくは、ポジションにストップロスがない場合)、 if ( NormalizeDouble( Bid - TrailingStop*Point, Digits ) > _BuyStopLoss || _BuyStopLoss <= 0.0 ) { //---- 注文を修正します if ( !OrderModify( _BuyTicket, _BuyOpenPrice, NormalizeDouble( Bid - TrailingStop*Point, Digits ), _BuyTakeProfit, 0 ) ) { Alert( "OrderModify Error #", GetLastError() ); return(-1); } } } } // もしオープンポジションがある場合、終了します。これ以上することはありません return(0); } // 次のブロックは完全に買いポジションの処理ブロックと同じです // そのためこれに対するコメントは付けられていません if ( _SellTicket > 0 ) { if ( _BuyStopTicket > 0 ) { if ( !OrderDelete( _BuyStopTicket ) ) { Alert( "OrderDelete Error #", GetLastError() ); return(-1); } } if ( TrailingStop > MarketInfo( Symbol(), MODE_STOPLEVEL ) ) { if ( NormalizeDouble( _SellOpenPrice - Ask, Digits ) > NormalizeDouble( TrailingStop*Point, Digits ) ) { if ( NormalizeDouble( Ask + TrailingStop*Point, Digits ) < _SellStopLoss || _SellStopLoss <= 0.0 ) { if ( !OrderModify( _SellTicket, _SellOpenPrice, NormalizeDouble( Ask + TrailingStop*Point, Digits ), _SellTakeProfit, 0 ) ) { Alert( "OrderModify Error #", GetLastError() ); return(-1); } } } } return(0); } //+------------------------------------------------------------------+ //| もし実行がこの場所に到達した場合、それは指値注文や| //| 開いているポジションがないということ | //+------------------------------------------------------------------+ //---- バイストップやセルストップを設定します: double _OpenPriceLevel, _StopLossLevel, _TakeProfitLevel; _OpenPriceLevel = NormalizeDouble( Ask + Luft*Point, Digits ); if ( StopLoss > 0 ) _StopLossLevel = NormalizeDouble( _OpenPriceLevel - StopLoss*Point, Digits ); else _StopLossLevel = 0.0; if ( TakeProfit > 0 ) _TakeProfitLevel = NormalizeDouble( _OpenPriceLevel + TakeProfit*Point, Digits ); else _TakeProfitLevel = 0.0; if ( OrderSend ( Symbol(), OP_BUYSTOP, Lot, _OpenPriceLevel, 5, _StopLossLevel, _TakeProfitLevel, "", _MagicNumber ) < 0 ) { Alert( "OrderSend Error #", GetLastError() ); return(-1); } _OpenPriceLevel = NormalizeDouble( Bid - Luft*Point, Digits ); if ( StopLoss > 0 ) _StopLossLevel = NormalizeDouble( _OpenPriceLevel + StopLoss*Point, Digits ); else _StopLossLevel = 0.0; if ( TakeProfit > 0 ) _TakeProfitLevel = NormalizeDouble( _OpenPriceLevel - TakeProfit*Point, Digits ); else _TakeProfitLevel = 0.0; if ( OrderSend ( Symbol(), OP_SELLSTOP, Lot, _OpenPriceLevel, 5, _StopLossLevel, _TakeProfitLevel, "", _MagicNumber ) < 0 ) { Alert( "OrderSend Error #", GetLastError() ); return(-1); } return(0); }
ここでは、初期のエキスパートアドバイザと改作したエキスパートアドバイザの間の差は遥かに顕著であり、ポジションコントロールのブロックはとても簡単で分かりやすいです。
それでは、最も難しいエキスパートアドバイザーオープンポジションの数に制限がないエキスパートアドバイザの番です。
4. 全てのポジションのコントロール
もし1つの注文の特性の保存の為に変数を使用できる場合、各特性1つずつにいくつかの配列を設ける必要があります。関数の意味の残りの部分はとても似ています:
- スタートの際に全ての配列をゼロ化します;
- その後、全ての注文を取捨し、チャートのシンボルと一致し、MagicNumberがmagic関数のパラメータと等しいシンボルの特性のみ配列に書き込みます;
- 使いやすくする為に、エキスパートアドバイザに含まれている注文の総数を保存するグローバル変数を一つ追加します。配列にアクセスする時、これはとても役に立ちます。
すぐに関数の記述に取り掛かりましょう:
// エキスパートアドバイザに含まれている // 注文数を保存する変数: int _ExpertOrdersTotal=0; // 注文の特性が保存される配列: int _OrderTicket[],_OrderType[]; double _OrderLots[],_OrderOpenPrice[],_OrderStopLoss[], _OrderTakeProfit[]; double _OrderProfit[],_OrderSwap[],_OrderCommission[]; datetime _OrderOpenTime[],_OrderExpiration[]; string _OrderComment[]; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void AllOrdersInit(int magic) { int _GetLastError=0,_OrdersTotal=OrdersTotal(); // 現在のポジション数に応じて配列のサイズを変えます // (もし_OrdersTotal = 0の場合、配列のサイズを1に変更します) int temp_value=MathMax(_OrdersTotal,1); ArrayResize(_OrderTicket,temp_value); ArrayResize(_OrderType,temp_value); ArrayResize(_OrderLots,temp_value); ArrayResize(_OrderOpenPrice,temp_value); ArrayResize(_OrderStopLoss,temp_value); ArrayResize(_OrderTakeProfit,temp_value); ArrayResize(_OrderOpenTime,temp_value); ArrayResize(_OrderProfit,temp_value); ArrayResize(_OrderSwap,temp_value); ArrayResize(_OrderCommission,temp_value); ArrayResize(_OrderComment,temp_value); ArrayResize(_OrderExpiration,temp_value); // 配列をゼロ化します ArrayInitialize(_OrderTicket,0); ArrayInitialize(_OrderType,0); ArrayInitialize(_OrderLots,0); ArrayInitialize(_OrderOpenPrice,0); ArrayInitialize(_OrderStopLoss,0); ArrayInitialize(_OrderTakeProfit,0); ArrayInitialize(_OrderOpenTime,0); ArrayInitialize(_OrderProfit,0); ArrayInitialize(_OrderSwap,0); ArrayInitialize(_OrderCommission,0); ArrayInitialize(_OrderExpiration,0); _ExpertOrdersTotal=0; for(int z=_OrdersTotal-1; z>=0; z --) { if(!OrderSelect(z,SELECT_BY_POS)) { _GetLastError=GetLastError(); Print("OrderSelect( ",z,", SELECT_BY_POS ) - Error #",_GetLastError); continue; } if(OrderMagicNumber()==magic && OrderSymbol()== Symbol()) { // 配列を埋めます _OrderTicket[_ExpertOrdersTotal]=OrderTicket(); _OrderType[_ExpertOrdersTotal] = OrderType(); _OrderLots[_ExpertOrdersTotal] = NormalizeDouble(OrderLots(),1); _OrderOpenPrice[_ExpertOrdersTotal]=NormalizeDouble(OrderOpenPrice(),Digits); _OrderStopLoss[_ExpertOrdersTotal]=NormalizeDouble(OrderStopLoss(),Digits); _OrderTakeProfit[_ExpertOrdersTotal]=NormalizeDouble(OrderTakeProfit(),Digits); _OrderOpenTime[_ExpertOrdersTotal]=OrderOpenTime(); _OrderProfit[_ExpertOrdersTotal]=NormalizeDouble(OrderProfit(),2); _OrderSwap[_ExpertOrdersTotal]=NormalizeDouble(OrderSwap(),2); _OrderCommission[_ExpertOrdersTotal]=NormalizeDouble(OrderCommission(),2); _OrderComment[_ExpertOrdersTotal]=OrderComment(); _OrderExpiration[_ExpertOrdersTotal]=OrderExpiration(); _ExpertOrdersTotal++; } } // エキスパートアドバイザに入っているポジション数に応じて配列のサイズを変えます // (もし_ExpertOrdersTotal = 0の場合、配列のサイズを1に変えます) temp_value=MathMax(_ExpertOrdersTotal,1); ArrayResize(_OrderTicket,temp_value); ArrayResize(_OrderType,temp_value); ArrayResize(_OrderLots,temp_value); ArrayResize(_OrderOpenPrice,temp_value); ArrayResize(_OrderStopLoss,temp_value); ArrayResize(_OrderTakeProfit,temp_value); ArrayResize(_OrderOpenTime,temp_value); ArrayResize(_OrderProfit,temp_value); ArrayResize(_OrderSwap,temp_value); ArrayResize(_OrderCommission,temp_value); ArrayResize(_OrderComment,temp_value); ArrayResize(_OrderExpiration,temp_value); }
関数の動作原理を理解する為に、エキスパートアドバイザによって開かれた全てのポジションの情報を画面上に出力する、簡単なエキスパートアドバイザを書きましょう。
そのコードは十分に簡単なものです:
extern int _MagicNumber=0; #include <AllOrdersControl.mq4> //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int start() { AllOrdersInit(_MagicNumber); if(_ExpertOrdersTotal>0) { string OrdersList=StringConcatenate(Symbol(),",MagicNumber ",_MagicNumber,":\n"); for(int n=0; n<_ExpertOrdersTotal; n++) { OrdersList=StringConcatenate(OrdersList,"Ордер № ",_OrderTicket[n],", прибыль/убыток: ",DoubleToStr(_OrderProfit[n],2)," ",AccountCurrency(),"\n"); } Comment(OrdersList); } return(0); }
もし_MagicNumberを0と等しく設定する場合、エキスパートアドバイザは手動で開かれたポジションのリストを表示します:
5. まとめ
記事の最後に、自力で自分の注文を取捨するエキスパートアドバイザと関数を使うエキスパートアドバイザの応答時間を比較したいと思います。この為に2つのバージョンを『全ティック』モードで10回連続でテストしました。(_MagicNumberパラメータによる最適化)テスト時間の測定は、MetaTrader自体が行い、最適化の際に自動的にかかった時間を算出します。
結果は次の通りです:
エキスパートアドバイザー |
10回のテストにかかった時間(時分) |
---|---|
CrossMACD_beta(関数なし) |
07:42 |
CrossMACD |
11:37 |
DoublePending_beta(関数なし) |
08:18 |
DoublePending |
09:42 |
表からわかるように、関数を使用するエキスパートアドバイザの動作は若干遅いです。(少なくともテストモードでは)しかしこれは、エキスパートアドバイザのソースコードの簡易さと記述のしやすさに比べれば合理的なコストと言えます。
いずれにしても、これらを使用するかどうかは、一人一人が自分で決定してください。
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/1404
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索