English Русский 中文 Español Deutsch Português 한국어 Français Italiano Türkçe
MQL5 クックブック:Expert Advisorsにトレード条件を設定するためのインディケータ利用

MQL5 クックブック:Expert Advisorsにトレード条件を設定するためのインディケータ利用

MetaTrader 5 | 26 11月 2015, 09:38
794 0
Anatoli Kazharski
Anatoli Kazharski

はじめに

本稿では、Expert Advisor は値がポジションオープンの条件を確認するのに使用されるインディケータを使って強化されます。それに一点添えるために、外部パラメータにドロップダウンリストを作成し、3つのトレードインディケータの中から1つを選ぶことができるようにします。

念のために以下を思い出してください。 MQL5 クックブックシリーズの先行記事をとおして作業をおこなってきているExpert Advisorの修正を続行します。Expert Advisor の最終バージョンは記事 "MQL5 Cookbook: The History of Deals And Function Library for Getting Position Properties"からダウンロードすることができます。

また、本稿ではトレード処理を行うことができるか否かを確認するために作成する関数を取り上げます。ポジションをオープンする関数は修正し、Expert Advisor がトレードモード(即時実行マーケット実行)を判断できるようにします。

先行記事で行われたすべての強化策や改善に続いて Expert Advisorのコードはすでに 1,500 行を越えているため、新しい機能が追加されるごとにそれは利便性が低下しています。そのため理論的なソリューションは個別のライブラリファイルとして複数のカテゴリーに分けられています。これで目標は設定できました。では始めましょう。

 

Expert Advisor の作成

Expert Advisor (*.mq5) のソースコードは先行記事から別のフォルダ TestIndicatorConditionsに入れ、そこにサブフォルダ Include を作成する必要があります。これはインクルードファイル (*.mqh)を作成するフォルダです。それらはMQL5 ウィザード (Ctrl+N) を用いて作成するか、標準テキストファイル (*.txt) として必要なディレクトリにマニュアルで作成し、のちに *.mqhと名前を付けなおすことができます。

以下が作成されるインクルードファイルすべての名前とコメントです。

  • Enums.mqh はすべての列挙を持ちます。
  • InfoPanel.mqh は情報パネルを設定し、グラフィックオブジェクトを作成および削除します。
  • Errors.mqh はエラーコードと再初期化理由を返す関数すべてを扱います。
  • TradeSignals.mqh は価格とインディケータ値を配列に書き込む関数、およびシグナルブロックを取り上げます。
  • TradeFunctions.mqh はトレード関数を持ちます。
  • ToString.mqh は数値を文字列値に変換する関数を取り扱います。
  • Auxiliary.mqh はその他補助関数用に使用されます。

これらライブラリをメインのファイルにインクルードするには #include 命令を使用します。Expert Advisor のメインファイルとインクルードファイルフォルダ(Include)は同じフォルダにあるため、ファイルをインクルードするコードは以下のようなものとなります。

//--- Include custom libraries
#include "Include\Enums.mqh"
#include "Include\InfoPanel.mqh"
#include "Include\Errors.mqh"
#include "Include\TradeSignals.mqh"
#include "Include\TradeFunctions.mqh"
#include "Include\ToString.mqh"
#include "Include\Auxiliary.mqh"

そうするとそれらを開き変更し、Expert Advisorのメインファイルからソースコードの一部を移動することができるようになります。

コードで正確に検索するには、Expert Advisor のメインファイルと同様に隣接したヘッダファイルへの参照が各ヘッダファイルに追加されます。たとえばわれわれのトレード関数のライブラリ TradeFunctions.mqhに対して、これは次のように記載されます。

//--- Connection with the main file of the Expert Advisor
#include "..\TestIndicatorConditions.mq5"
//--- Include custom libraries
#include "Enums.mqh"
#include "InfoPanel.mqh"
#include "Errors.mqh"
#include "TradeSignals.mqh"
#include "ToString.mqh"
#include "Auxiliary.mqh"

同一ネストレベルのファイルに対しては、ただ名前を指定するだけで十分です。上位レベルに行くにはパスのバックスラッシュの前にドットを2個入れる必要があります。

Enums.mqh ファイルのインディケータに列挙を追加します。説明のためにこの Expert Advisor では標準インディケータを2個(移動平均 および コモディティチャネル指数)とカスタムインディケータを1個(MultiRange_PCH)使用します。以下がその列挙です。

//--- Indicators
enum ENUM_INDICATORS
  {
   MA       = 0, // Moving Average
   CCI      = 1, // CCI
   PCH      = 2  // Price Channel
  };

外部パラメータは次のように変更されます。

//--- External parameters of the Expert Advisor
sinput   long              MagicNumber=777;        // Magic number
sinput   int               Deviation=10;           // Slippage
input    ENUM_INDICATORS   Indicator=MA;           // Indicator
input    int               IndicatorPeriod=5;      // Indicator period
input    int               IndicatorSegments=2;    // Number of one direction indicator segments
input    double            Lot=0.1;                // Lot
input    double            VolumeIncrease=0.1;     // Position volume increase
input    double            VolumeIncreaseStep=10;  // Step for volume increase
input    double            StopLoss=50;            // Stop Loss
input    double            TakeProfit=100;         // Take Profit
input    double            TrailingStop=10;        // Trailing Stop
input    bool              Reverse=true;           // Position reversal
sinput   bool              ShowInfoPanel=true;     // Display of the info panel

前述のようにインディケータパラメータのドロップダウンリスト内で3つのインディケータから1つを選択することが可能となります。

インディケータ期間が設定されているインディケータ-IndicatorPeriodに対してパラメータは1個だけ適用されます。Expert Advisor の前バージョンからのNumberOfBars パラメータは名前を付け替えて IndicatorSegments となり、ここではポジションオープンの条件を満たすように既定のインディケータが上下するバー番号を表記します。

外部パラメータをもう一つ追加します。VolumeIncreaseStepでこれはポイント内にボリュームインディケータに対するステップを設定するのに使用することができます。

AllowedNumberOfBars 変数(ここでは AllowedNumberOfSegments)の値はカスタム関数GetBarsData() 内で調整されていました。それは今は個別の関数に入れられ初期化のときのみ呼ばれます。

ポジションオープンの条件はここではインディケータ値を用いてチェックされるため、割り当てられるこの値は常に3以上となります。すなわち、外部変数 IndicatorSegments が値1に割り当てられると、 AllowedNumberOfSegments 変数が値3に割り当てられるのです。これは条件を満たすため完了バーのインディケータ値が前回バーよりも大きな値である必要があるためです。このため最後のインディケータ値3個を取得する必要があります。

以下はCorrectInputParameters() 関数コードです。

//+------------------------------------------------------------------+
//| Adjusting input parameters                                       |
//+------------------------------------------------------------------+
void CorrectInputParameters()
  {
//--- Adjust the number of bars for the position opening condition
   if(AllowedNumberOfSegments<=0)
     {
      if(IndicatorSegments<=1)
         AllowedNumberOfSegments=3;                     // At least three bars are required
      if(IndicatorSegments>=5)
         AllowedNumberOfSegments=5;                     // but no more than 7
      else
         AllowedNumberOfSegments=IndicatorSegments+1;   // and always greater by two
     }
  }

インディケータを処理する前にトレードが許可されるか確認する関数-CheckTradingPermission()を作成します。関数内にリストアップされるあらゆる理由によりトレードが許可されるなら、値ゼロが返されます。これは次の試行が次のバーで行われる必要があることを意味します。

//+------------------------------------------------------------------+
//| Checking if trading is allowed                                   |
//+------------------------------------------------------------------+
bool CheckTradingPermission()
  {
//--- For real-time mode
   if(IsRealtime())
     {
      //--- Checking server connection
      if(!TerminalInfoInteger(TERMINAL_CONNECTED))
         return(1);
      //--- Permission to trade at the running program level
      if(!MQL5InfoInteger(MQL5_TRADE_ALLOWED))
         return(2);
      //--- Permission to trade at the terminal level
      if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
         return(3);
      //--- Permission to trade for the current account
      if(!AccountInfoInteger(ACCOUNT_TRADE_ALLOWED))
         return(4);
      //--- Permission to trade automatically for the current account
      if(!AccountInfoInteger(ACCOUNT_TRADE_EXPERT))
         return(5);
     }
//---
   return(0);
  }

それでは本稿の主要ポイントに取り掛かりましょう。インディケータ値にアクセスするにはまずそのハンドルを取得する必要があります。これはインディケータ名の短縮形から取られる名前を持ち、前に記号 'i'がくる特殊関数を用いて行われます。

たとえば移動平均 インディケータには対応する関数 iMA()があります。MetaTrader 5ターミナルのすべての標準インディケータハンドルはこれら関数を用いて取得可能です。リストの完全版は テクニカルインディケータと名前のついた MQL5 参考資料で入手可能です。カスタムインディケータのハンドルを取得する必要がある場合は、iCustom() 関数を使用します。

Indicator パラメータで選択されるインディケータに応じて対応するインディケータのハンドル値がグローバル変数 indicator_handle に割り当てられる GetIndicatorHandle() 関数を実装します。関数コードはトレードシグナル関数のライブラリ(\Include\TradeSignals.mqh ファイル)にあります。またインディケータハンドルを伴う変数は Expert Advisorのメインファイルに入っています。

//+------------------------------------------------------------------+
//| Getting the indicator handle                                     |
//+------------------------------------------------------------------+
void GetIndicatorHandle()
  {
//--- If the Moving Average indicator is selected
   if(Indicator==MA)
      indicator_handle=iMA(_Symbol,Period(),IndicatorPeriod,0,MODE_SMA,PRICE_CLOSE);
//--- If the CCI indicator is selected
   if(Indicator==CCI)
      indicator_handle=iCCI(_Symbol,Period(),IndicatorPeriod,PRICE_CLOSE);
//--- If the MultiRange_PCH indicator is selected
   if(Indicator==PCH)
      indicator_handle=iCustom(_Symbol,Period(),"MultiRange_PCH",IndicatorPeriod);
//--- If the indicator handle could not be obtained
   if(indicator_handle==INVALID_HANDLE)
      Print("Failed to get the indicator handle!");
  }

取得したインディケータハンドルを使用しその値を取得することができる関数GetDataIndicators() を作成します。これは記事"MQL5 Cookbook: Analyzing Position Properties in the MetaTrader 5 Strategy Tester"で考察された関数 CopyTime()、CopyClose()、 CopyOpen()、CopyHigh()、 CopyLow() を用いて値を取得するのと同様の方法で CopyBuffer() 関数をもちることで行います。

インディケータは複数のバッファ(値の行)を持つことができるため、バッファインデックスは2番目のパラメータとして CopyBuffer() 関数に渡されます。標準インディケータ用バッファインデックスは MQL5 参考資料にあります。カスタムインディケータについては、ソースコードが入手可能であれば、バッファインデックスはコードで確認できます。コードがない場合、実験によってストラテジーテスタの可視化モードで条件がどのように満たされているか観察しインデックスを見つける必要がります。

その前に、Expert Advisorのメインファイル内にインディケータバッファへの動的配列を作成する必要があります。

//--- Arrays for indicator values
double indicator_buffer1[];
double indicator_buffer2[];

以下が GetIndicatorsData() のコードです。

//+------------------------------------------------------------------+
//| Getting indicator values                                         |
//+------------------------------------------------------------------+
bool GetIndicatorsData()
  {
//--- If the indicator handle has been obtained
   if(indicator_handle!=INVALID_HANDLE)
     {
      //--- For the Moving Average or CCI indicator
      if(Indicator==MA || Indicator==CCI)
        {
         //--- Reverse the indexing order (... 3 2 1 0)
         ArraySetAsSeries(indicator_buffer1,true);
         //--- Get indicator values
         if(CopyBuffer(indicator_handle,0,0,AllowedNumberOfSegments,indicator_buffer1)<AllowedNumberOfSegments)
           {
            Print("Failed to copy the values ("+
                  _Symbol+"; "+TimeframeToString(Period())+") to the indicator_buffer1 array! Error ("+
                  IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError()));
            return(false);
           }
        }
      //--- For the MultiRange_PCH indicator
      if(Indicator==PCH)
        {
         //--- Reverse the indexing order (... 3 2 1 0)
         ArraySetAsSeries(indicator_buffer1,true);
         ArraySetAsSeries(indicator_buffer2,true);
         //--- Get indicator values
         if(CopyBuffer(indicator_handle,0,0,AllowedNumberOfSegments,indicator_buffer1)<AllowedNumberOfSegments || 
            CopyBuffer(indicator_handle,1,0,AllowedNumberOfSegments,indicator_buffer2)<AllowedNumberOfSegments)
           {
            Print("Failed to copy the values ("+
                  _Symbol+"; "+TimeframeToString(Period())+") to the indicator_buffer1 or indicator_buffer2 array! Error ("+
                  IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError()));
            return(false);
           }
        }
      //---
      return(true);
     }
//--- If the indicator handle has not been obtained, retry
   else
      GetIndicatorHandle();
//---
   return(false);
  }

GetTradingSignal() 関数は実質上変更されています。ポジション不在の場合とポジションが存在する場合では条件は異なります。インディケータMoving Average および CCI に対しては条件は同じです。MultiRange_PCHに対しては、条件は個別のブロックに作成されます。コードを読みやすくし、冗長をなくすため、補助関数 GetSignal()を作成します。そのようなポジションが存在し、がイプパラメータによって適切な処理が許可されているなら、それはポジションオープンまたはクローズに対するシグナルを返します。

以下が GetSignal() 関数のコードです。

//+------------------------------------------------------------------+
//| Checking the condition and returning a signal                    |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE GetSignal()
  {
//--- Check conditions for the Moving Average and CCI indicators
   if(Indicator==MA || Indicator==CCI)
     {
      //--- A Sell signal
      if(AllowedNumberOfSegments==3 && 
         indicator_buffer1[1]<indicator_buffer1[2])
         return(ORDER_TYPE_SELL);
      //---
      if(AllowedNumberOfSegments==4 && 
         indicator_buffer1[1]<indicator_buffer1[2] && 
         indicator_buffer1[2]<indicator_buffer1[3])
         return(ORDER_TYPE_SELL);
      //---
      if(AllowedNumberOfSegments==5 && 
         indicator_buffer1[1]<indicator_buffer1[2] && 
         indicator_buffer1[2]<indicator_buffer1[3] && 
         indicator_buffer1[3]<indicator_buffer1[4])
         return(ORDER_TYPE_SELL);
      //---
      if(AllowedNumberOfSegments==6 && 
         indicator_buffer1[1]<indicator_buffer1[2] && 
         indicator_buffer1[2]<indicator_buffer1[3] && 
         indicator_buffer1[3]<indicator_buffer1[4] && 
         indicator_buffer1[4]<indicator_buffer1[5])
         return(ORDER_TYPE_SELL);
      //---
      if(AllowedNumberOfSegments>=7 && 
         indicator_buffer1[1]<indicator_buffer1[2] && 
         indicator_buffer1[2]<indicator_buffer1[3] && 
         indicator_buffer1[3]<indicator_buffer1[4] && 
         indicator_buffer1[4]<indicator_buffer1[5] && 
         indicator_buffer1[5]<indicator_buffer1[6])
         return(ORDER_TYPE_SELL);

      //--- A Buy signal
      if(AllowedNumberOfSegments==3 && 
         indicator_buffer1[1]>indicator_buffer1[2])
         return(ORDER_TYPE_BUY);
      //---
      if(AllowedNumberOfSegments==4 && 
         indicator_buffer1[1]>indicator_buffer1[2] && 
         indicator_buffer1[2]>indicator_buffer1[3])
         return(ORDER_TYPE_BUY);
      //---
      if(AllowedNumberOfSegments==5 && 
         indicator_buffer1[1]>indicator_buffer1[2] && 
         indicator_buffer1[2]>indicator_buffer1[3] && 
         indicator_buffer1[3]>indicator_buffer1[4])
         return(ORDER_TYPE_BUY);
      //---
      if(AllowedNumberOfSegments==6 && 
         indicator_buffer1[1]>indicator_buffer1[2] && 
         indicator_buffer1[2]>indicator_buffer1[3] && 
         indicator_buffer1[3]>indicator_buffer1[4] && 
         indicator_buffer1[4]>indicator_buffer1[5])
         return(ORDER_TYPE_BUY);
      //---
      if(AllowedNumberOfSegments>=7 && 
         indicator_buffer1[1]>indicator_buffer1[2] && 
         indicator_buffer1[2]>indicator_buffer1[3] && 
         indicator_buffer1[3]>indicator_buffer1[4] && 
         indicator_buffer1[4]>indicator_buffer1[5] && 
         indicator_buffer1[5]>indicator_buffer1[6])
         return(ORDER_TYPE_BUY);
     }
//--- Block that checks conditions for the MultiRange_PCH indicator
   if(Indicator==PCH)
     {
      //--- A Sell signal
      if(close_price[1]<indicator_buffer2[1] && 
         open_price[1]>indicator_buffer2[1])
         return(ORDER_TYPE_SELL);
      //--- A Buy signal
      if(close_price[1]>indicator_buffer1[1] && 
         open_price[1]<indicator_buffer1[1])
         return(ORDER_TYPE_BUY);
     }
//--- No signal
   return(WRONG_VALUE);
  }

これで GetTradingSignal() 関数のコードは以下のようになります。

//+------------------------------------------------------------------+
//| Determining trading signals                                      |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE GetTradingSignal()
  {
//--- If there is no position
   if(!pos.exists)
     {
      //--- A Sell signal
      if(GetSignal()==ORDER_TYPE_SELL)
         return(ORDER_TYPE_SELL);
      //--- A Buy signal
      if(GetSignal()==ORDER_TYPE_BUY)
         return(ORDER_TYPE_BUY);
     }
//--- If the position exists
   if(pos.exists)
     {
      //--- Get the position type
      GetPositionProperties(P_TYPE);
      //--- Get the last deal price
      GetPositionProperties(P_PRICE_LAST_DEAL);
      //--- Block that checks conditions for the Moving Average and CCI indicators
      if(Indicator==MA || Indicator==CCI)
        {
         //--- A Sell signal
         if(pos.type==POSITION_TYPE_BUY && 
            GetSignal()==ORDER_TYPE_SELL)
            return(ORDER_TYPE_SELL);
         //---
         if(pos.type==POSITION_TYPE_SELL && 
            GetSignal()==ORDER_TYPE_SELL && 
            close_price[1]<pos.last_deal_price-CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point))
            return(ORDER_TYPE_SELL);
         //--- A Buy signal
         if(pos.type==POSITION_TYPE_SELL && 
            GetSignal()==ORDER_TYPE_BUY)
            return(ORDER_TYPE_BUY);
         //---
         if(pos.type==POSITION_TYPE_BUY && 
            GetSignal()==ORDER_TYPE_BUY && 
            close_price[1]>pos.last_deal_price+CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point))
            return(ORDER_TYPE_BUY);
        }
      //--- Block that checks conditions for the MultiRange_PCH indicator
      if(Indicator==PCH)
        {
         //--- A Sell signal
         if(pos.type==POSITION_TYPE_BUY && 
            close_price[1]<indicator_buffer2[1] && 
            open_price[1]>indicator_buffer2[1])
            return(ORDER_TYPE_SELL);
         //---
         if(pos.type==POSITION_TYPE_SELL && 

            close_price[1]<pos.last_deal_price-CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point))
            return(ORDER_TYPE_SELL);
         //--- A Buy signal
         if(pos.type==POSITION_TYPE_SELL && 
            close_price[1]>indicator_buffer1[1] && 
            open_price[1]<indicator_buffer1[1])
            return(ORDER_TYPE_BUY);
         //---
         if(pos.type==POSITION_TYPE_BUY && 
            close_price[1]>pos.last_deal_price+CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point))
            return(ORDER_TYPE_BUY);
        }
     }
//--- No signal
   return(WRONG_VALUE);
  }

ここではシンボルプロパティの一部であるモードInstant Execution および Market Execution を確認し、ポジションオープン関数OpenPosition() のコードを変更します。名前が自明であるモードもまた MQL5 参考資料で確認できます。

  • 即時実行
  • マーケット実行

Market Execution モードを処理するとき、レベルセットStop LossTake Profit ではポジションをオープンできないことを思い出してください。まずポジションをオープンし、それからレベル設定によってそれを変更する必要があります。

ビルド 803で開始すると、「マーケット実行」と「交換実行」モードに対してポジションをオープンするときストップロスおよびテイクプロフィットは設定可能です。

シンボルプロパティのストラクチャに実行モードを追加します。

//--- Symbol properties
struct symbol_properties
  {
   int               digits;           // Number of decimal places in the price
   int               spread;           // Spread in points
   int               stops_level;      // Stops level
   double            point;            // Point value
   double            ask;              // Ask price
   double            bid;              // Bid price
   double            volume_min;       // Minimum volume for a deal
   double            volume_max;       // Maximum volume for a deal
   double            volume_limit;     // Maximum permissible volume for a position and orders in one direction
   double            volume_step;      // Minimum volume change step for a deal
   double            offset;           // Offset from the maximum possible price for a transaction
   double            up_level;         // Upper Stop level price
   double            down_level;       // Lower Stop level price
   ENUM_SYMBOL_TRADE_EXECUTION execution_mode; // Execution mode
  };

列挙 ENUM_SYMBOL_PROPERTIES を適切に変更する必要があります。

//--- Enumeration of position properties
enum ENUM_SYMBOL_PROPERTIES
  {
   S_DIGITS          = 0,
   S_SPREAD          = 1,
   S_STOPSLEVEL      = 2,
   S_POINT           = 3,
   S_ASK             = 4,
   S_BID             = 5,
   S_VOLUME_MIN      = 6,
   S_VOLUME_MAX      = 7,
   S_VOLUME_LIMIT    = 8,
   S_VOLUME_STEP     = 9,
   S_FILTER          = 10,
   S_UP_LEVEL        = 11,
   S_DOWN_LEVEL      = 12,
   S_EXECUTION_MODE  = 13,
   S_ALL             = 14
  };

また GetSymbolProperties() 関数も変更します。

case S_EXECUTION_MODE: symb.execution_mode=(ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_EXEMODE);   break;
      //---
      case S_ALL           :
         symb.digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);
         symb.spread=(int)SymbolInfoInteger(_Symbol,SYMBOL_SPREAD);
         symb.stops_level=(int)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL);
         symb.point=SymbolInfoDouble(_Symbol,SYMBOL_POINT);
         symb.ask=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),symb.digits);
         symb.bid=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),symb.digits);
         symb.volume_min=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
         symb.volume_max=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
         symb.volume_limit=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_LIMIT);
         symb.volume_step=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
         symb.offset=NormalizeDouble(CorrectValueBySymbolDigits(lot_offset*symb.point),symb.digits);
         symb.up_level=NormalizeDouble(symb.ask+symb.stops_level*symb.point,symb.digits);
         symb.down_level=NormalizeDouble(symb.bid-symb.stops_level*symb.point,symb.digits);
         symb.execution_mode=(ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_EXEMODE);                       break;
         //---

結果 OpenPosition() 関数コードは以下のようになります。

//+------------------------------------------------------------------+
//| Opening a position                                               |
//+------------------------------------------------------------------+
void OpenPosition(double lot,
                  ENUM_ORDER_TYPE order_type,
                  double price,
                  double sl,
                  double tp,
                  string comment)
  {
//--- Set the magic number in the trading structure
   trade.SetExpertMagicNumber(MagicNumber);
//--- Set the slippage in points
   trade.SetDeviationInPoints(CorrectValueBySymbolDigits(Deviation));
//--- The Instant Execution mode
//    A position can be opened with the Stop Loss and Take Profit levels set
   if(symb.execution_mode==SYMBOL_TRADE_EXECUTION_INSTANT)
     {
      //--- If the position failed to open, print the relevant message
      if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment))
         Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError()));
     }
//--- The Market Execution mode 
//    First open a position and only then set the Stop Loss and Take Profit levels
//    *** Starting with build 803, Stop Loss and Take Profit can be set upon position opening ***
   if(symb.execution_mode==SYMBOL_TRADE_EXECUTION_MARKET)
     {
      //--- If there is no position, first open a position and then set Stop Loss and Take Profit
      if(!pos.exists)
        {
         //--- If the position failed to open, print the relevant message
         if(!trade.PositionOpen(_Symbol,order_type,lot,price,0,0,comment))
            Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError()));
         //--- Get the flag of presence/absence of the position
         pos.exists=PositionSelect(_Symbol);
         //--- If the position exists
         if(pos.exists)
           {
            //--- Set Stop Loss and Take Profit
            if(!trade.PositionModify(_Symbol,sl,tp))
               Print("Error modifying the position: ",GetLastError()," - ",ErrorDescription(GetLastError()));
           }
        }
      //--- If the position exists, increase its volume and leave the Stop Loss and Take Profit levels unchanged
      else
        {
         //--- If the position failed to open, print the relevant message
         if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment))
            Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError()));
        }
     }
  }

まだイベント処理関数に最後の重要な仕上げをする必要があります。

  • OnInit
    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit()
      {
    //--- Adjust the input parameters
       CorrectInputParameters();
    //--- Get indicator handles
       GetIndicatorHandle();
    //--- Initialize the new bar
       CheckNewBar();
    //--- Get the properties
       GetPositionProperties(P_ALL);
    //--- Set the info panel
       SetInfoPanel();
    //---
       return(0);
      }
  • OnDeinit
    //+------------------------------------------------------------------+
    //| Expert deinitialization function                                 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
      {
    //--- Print the deinitialization reason to the journal
       Print(GetDeinitReasonText(reason));
    //--- When deleting from the chart
       if(reason==REASON_REMOVE)
         {
          //--- Delete all objects relating to the info panel from the chart
          DeleteInfoPanel();
          //--- Delete the indicator handle
          IndicatorRelease(indicator_handle);
         }
      }
  • OnTick
    //+------------------------------------------------------------------+
    //| Expert tick function                                             |
    //+------------------------------------------------------------------+
    void OnTick()
      {
    //--- If the bar is not new, exit
       if(!CheckNewBar())
         {
          if(IsVisualMode() || IsRealtime())
            {
             //--- Get the properties and update the values on the panel
             GetPositionProperties(P_ALL);
             //--- Set/update the info panel
             SetInfoPanel();
            }
          return;
         }
    
    //--- If there is a new bar
       else
         {
          //--- If trading is allowed
          if(CheckTradingPermission()==0)
            {
             if(!GetIndicatorsData())
                return;
             GetBarsData();          // Get bar data
             TradingBlock();         // Check the conditions and trade
             ModifyTrailingStop();   // Modify the Trailing Stop level
            }
         }
    //--- Get the properties
       GetPositionProperties(P_ALL);
    //--- Update the info panel
       SetInfoPanel();
      }

これで関数はすべて準備完了。パラメータの最適化が可能です。メインのプログラムファイルからコードをコンパイルする必要があることを忘れないようにします。

 

パラメータの最適化と Expert Advisorの検証

「ストラテジーテスタ」は以下のように設定します。

図1 ストラテジーテスタ設定

図1 ストラテジーテスタ設定

それから最適化のために Expert Advisor のパラメータ設定を行います(添付にある設定を伴う *.set ファイルを参照ください)。

図2 Expert Advisor の設定

図2 Expert Advisor の設定

デュアルコアプロセッサでは最適化は約40分かかります。最適化チャートにより部分的に収益ゾーンの結果を基にしたトレーディングシステムのクオリティーを評価することができます。

図3 最適化チャート

図3 最適化チャート

以下は最大リカバリーファクタ検証結果です。

図4 最大リカバリーファクタ検証結果

図4 最大リカバリーファクタ検証結果

 

おわりに

ダウンロード可能なExpert Advisorのソースコードを伴うアーカイブを本稿に添付しています。それを抽出したら、 \TestIndicatorConditions ファイルフォルダを <Metatrader 5 terminal>\MQL5\Expertsに入れる必要があります。Expert Advisorの正しい処理を確認するには、インディケータ MultiRange_PCH をだ論ロードし、<Metatrader 5 terminal>\MQL5\Indicatorsに入れる必要があります。

MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/645

MQL5 クックブック:ポジションプロパティを取得するためのディール履歴と関数ライブラリ MQL5 クックブック:ポジションプロパティを取得するためのディール履歴と関数ライブラリ
ポジションプロパティについて先行記事で提供されている情報を簡単にまとめます。本稿では、ディールヒストリーにアクセスした後にのみ取得可能なプロパティを得る関数を数個追加して作成します。また便利な方法でポジションやシンボルプロパティにアクセスできるようにするデータストラクチャについても知識を得ます。
Expert Advisor パラメータのユーザーパネルからの『オンザフライ』の変更 Expert Advisor パラメータのユーザーパネルからの『オンザフライ』の変更
本稿ではパラメータをユーザーパネルから管理できる Expert Advisor の実装を示すちょっとした例を提供します。『オンザフライ』でパラメータを変更するとき、Expert Advisor はのちにファイルから読み込みパネル上で適切に表示するために情報パネルからファイルに取得した値を書きます。本稿はマニュアルでトレードを行う方または半自動モードでトレードを行う方に適しているでしょう。
MQL5 Cookbook:トレードレベルを設定/変更する際エラーを避ける方法 MQL5 Cookbook:トレードレベルを設定/変更する際エラーを避ける方法
シリーズの前稿 "MQL5 Cookbook: Analyzing Position Properties in the MetaTrader 5 Strategy Tester" からの Expert Advisor への取り組みの続編として、既存の関数を改良、最適化しつつ有用な関数を数多く用いて Expert Advisor を強化していきます。今回 Expert Advisor は MetaTrader 5 「ストラテジーテスタ」で最適化可能な外部パラメータを取得し、いくつかの点でシンプルなトレーディングシステムのようになります。
MQL5 クックブック:トリプルスクリーン戦略に基づくトレーディングシステムに対するフレームワーク作成 MQL5 クックブック:トリプルスクリーン戦略に基づくトレーディングシステムに対するフレームワーク作成
本稿では MQL5で「リプルスクリーン」戦略に基づくトレーディングシステムに対するフレームワークを作成します。Expert Advisor を一から作成することはしません。代わりに、実質上すでにわれわれの目的に役だっている先行記事 "MQL5 Cookbook: Using Indicators to Set Trading Conditions in Expert Advisors" のプログラムを変更するだけとします。よって本稿は既製プログラムのパターンを簡単に変更する方法もお伝えします。