English Русский 中文 Español Deutsch Português
preview
EAコンストラクタの開発の試み

EAコンストラクタの開発の試み

MetaTrader 5 | 17 1月 2022, 08:30
509 0
Vladimir Karputov
Vladimir Karputov

内容


はじめに

当初から、私の目的は標準ライブラリを使用することでした。最初のタスクは、最も単純な機能を実装することでした。CTrade取引クラスをインクルードして、BuyまたはSellメソッドを実行します。短く簡潔なコードが生成されるため、標準ライブラリを選択しました。以下の短いコードはスクリプトの形で実行されて1.0ロットのボリュームで買いポジションを開きます。

//+------------------------------------------------------------------+
//|                                                     Open Buy.mq5 |
//|                         Copyright © 2018-2021, Vladimir Karputov |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2018-2021, Vladimir Karputov"
#property version   "1.001"
//---
#include <Trade\Trade.mqh>
CTrade         m_trade;                      // trading object
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   m_trade.Buy(1.0); // open Buy position, volume 1.0 lot
  }

徐々に要件が複雑になり、新しいエキスパートアドバイザー(EA)を作成するたびに取引エラーに遭遇するようになったため、正しいコードを書きたいという私の願望はますます強くなりました。最後に、非常に重要な「マーケットでの公開前にトレードロボットに行うべき検査」稿が公開されました。この記事が公開されたとき、私はすでに取引注文の実行に対する信頼できる制御機能の必要性を認識していました。その瞬間から、コピー->ペーストを使用してEAに簡単に追加できる実証済みの機能を徐々に取得し始めました。

EAの作業はほとんどの場合指標の使用を伴うため、指標ハンドルを正しく作成し、指標データを受信するための関数を取得し始めました。

NB: MQL5スタイルは、指標ハンドルが1回作成されることを意味します。原則として、これはOnInitで行われます。

バージョン2.XXX頃から、2つの開発ブランチを維持し始めました。通常の手続き型コードとクラス形式のコード(クラスの主な目的はマルチカレンシーEAの実装)です。

作業の過程で、コンストラクタに徐々に最も人気のある設定を追加しました。

  • 決済逆指値と決済指値
  • トレール注文
  • リスクパーセンテージまたは一定/最小ロットとしてのロット計算
  • 取引が行われる時間間隔の制御
  • 市場での1つのポジションだけの存在
  • 取引シグナルの逆転
  • 反対のシグナルが表示された場合のポジションの強制決済

各入力には、コードブロックと新しい関数の作成が含まれていました。

日常的に使用するために、最も人気のあるすべての機能と入力のフルセットをTrading engine 3.mq5 EAに収集することにしました。実際、これは既製のEAであり、多くの日常業務から解放されます。 しなければならないのは、関数を追加/削除するか、それぞれの特定の場合にコードブロック間の相互作用を変更することだけです。


1. コンストラクタ後のEA機能

コンストラクタによって作成されたEAは、すぐに複数の設定を備えており、それらを組み合わせて独自のストラテジーを作成できます。バージョン4.XXXでは、次のルールを適用します。 

  • 現在の銘柄(EAが起動されるチャートの銘柄)が使用される
  • テイクプロフィット、ストップロス、トレーリングは入力のポイントで設定されるポイント - 相場の通貨での現在の銘柄ポイントサイズ。たとえば、「EURSD」では1.00055-1.00045=10ポイント。

十字ツールをドラッグすると、銘柄チャートに「ポイント」が常に表示されます。

ポイント

図1 ポイント

以下は、コンストラクタを使用して作成されたEAの入力です。

  • 取引設定
    • Working timeframe - 作業時間枠は、EAが起動されるチャートの時間枠とは異なる場合があります。これは、指標が作成される時間枠です(指標で別の時間枠が明示的に指定されていない場合)。また、新しいバーが作成された瞬間を追跡するためにも使用されます(新しいバーが表示されたときにのみ取引シグナルを検出する必要がある場合、または新しいバーが表示されたときにのみトレーリングを起動する場合)。
    • Stop Loss (0 – 無効)
    • Take Profit  (0 – 無効)
    • Trailing on ...  各ティック(バー#0(すべてのティック))または新しいバーが表示されたときのみ(バー#1(新しいバー))でトレーリング能力を確認します。
    • Search signals on ...  各ティック(バー#0(すべてのティック))または新しいバーが表示されたときのみ(バー#1(新しいバー))で取引シグナルを検索します。
    • Trailing Stop (min distance from price to Stop Loss)価格とポジションのストップロスの間の最小距離。トレーリングは、ポジション収益性があり、価格がトレーリングストップ+トレーリングステップ分始値から離れる場合にのみアクティブになります。 トレーリング操作はTrailingStopコードイメージに表示されます。
    • Trailing Step 
  • ポジションサイズ管理(ロット計算)
    • Money management lot: LotまたはRiskロット計算システム。ロットは静的(Money management= Constant lot、ロットサイズは「Money management」の値で設定されます)にも動的にできます。取引ごとのリスク%(Money management= Risk in percent for a deal、リスク%は「Money management」の値に設定されます。最小ロットに等しい定数ロットを設定することもできます(Money management= Lots Min)。
    • 「Money management」の値 
  • 取引モード
    • Trade mode: 買いポジションのみを許可売りポジションのみを許可 買いと売りのポジションを許可
  • DEMA カスタム指標パラメータ。これは、最終的に指標とそのパラメータを設定する場所です
    • DEMA: 平均期間
    • DEMA: 水平シフト
    • DEMA: 価格の種類
  • 時間制御作業時間。取引シグナルの検索が許可されている期間
    • Use time control  フラグ、時間制御を有効/無効化
    • Start Hour  期間の開始時間
    • Start Minute  期間の開始分
    • End Hour  期間の終了時間
    • End Minute  期間の終了分
  • 未決注文パラメータ  未決注文に関連するパラメータ
    • Pending: Expiration, in minutes (0 - OFF)未決注文の有効期限(0 - 無効) 
    • Pending: Indent現在の価格からの未決注文のインデント(未決注文価格が明示的に設定されていない場合)
    • Pending: Maximum spread (0 -> OFF)最大スプレッド(0 - 無効)現在のスプレッドが指定されたスプレッドを超える場合、未決注文は設定されません(EAはスプレッドが減少するのを待ちます)
    • Pending: Only one pending有効/無効フラグ。市場で許可されている未決注文は1つだけです
    • Pending: Reverse pending type有効/無効フラグ未決注文の反転
    • Pending: New pending -> delete previous ones未決注文を設定する場合は、他のすべての未決注文が事前に削除されます
  • 追加機能
    • Positions: Only one有効/無効フラグ。市場で許可されているポジションは1つだけです
    • Positions: Reverse有効/無効フラグ。取引注文の反転
    • Positions: Close opposite有効/無効フラグ。取引注文がある場合、注文を実行できるように、すべてのポジションが事前に決済されます
    • Print log 有効/無効フラグ。操作とエラーに関する拡張情報を表示します
    • Coefficient (Freeze==0またはStopsLevels==0の場合)  係数(Freeze == 0またはStopsLevels == 0の場合) ストップレベルを考慮した比率 
    • Deviation指定されたずれ
    • Magic numberEAの一意のID

2. コンストラクタの一般的なアルゴリズム

SPosition配列は、グローバルプログラムレベル(EAヘッダー内)で宣言され、STRUCT_POSITION構造体で構成されています。起動中、配列のサイズはゼロです。取引シグナルを処理した後、配列もゼロに戻ります。

OnTickから、SearchTradingSignals関数が呼び出されます。シグナルが存在する場合(市場にポジションがない場合)、関数は取引注文を形成します(配列内の取引注文ごとに単一のSTRUCT_POSITION構造体が作成されます)。 取引注文の存在はOnTickでチェックされます。SPosition配列サイズがチェックされ、ゼロを超える場合は取引注文があるので、OpenBuyまたはOpenSell実行するために送信されます。取引リクエストの実行の制御はOnTradeTransactionで行われます。

一般的なアルゴリズム(単純)

図2 一般的なアルゴリズム(単純)

EAは現在の銘柄(EAが配置されているチャート)で機能すると常に想定されています。例: USDPLNに配置されているEAはUSDPLNで機能します。

2.1. STRUCT_POSITION構造体

この構造体はEAの心臓部です。一度に2つの役割が果たされます。構造体は取引注文が設定されているフィールドを特徴とします(設定はSearchTradingSignalsで行われます)。また、構造体は 取引注文の実行を管理するためのフィールドを備えています(制御はOnTradeTransactionで行われます)。 

//+------------------------------------------------------------------+
//| Structure Positions                                              |
//+------------------------------------------------------------------+
struct STRUCT_POSITION
  {
   ENUM_POSITION_TYPE pos_type;              // position type
   double            volume;                 // position volume (if "0.0" -> the lot is "Money management")
   double            lot_coefficient;        // lot coefficient
   bool              waiting_transaction;    // waiting transaction, "true" -> it's forbidden to trade, we expect a transaction
   ulong             waiting_order_ticket;   // waiting order ticket, ticket of the expected order
   bool              transaction_confirmed;  // transaction confirmed, "true" -> transaction confirmed
   //--- Constructor
                     STRUCT_POSITION()
     {
      pos_type                   = WRONG_VALUE;
      volume                     = 0.0;
      lot_coefficient            = 0.0;
      waiting_transaction        = false;
      waiting_order_ticket       = 0;
      transaction_confirmed      = false;
     }
  };

一部のフィールドは取引注文自体を担当し、その他はその実行を処理します。 構造体には、コンストラクタ(STRUCT_POSITION()特殊関数)が含まれています。これは、構造体オブジェクトを作成するときに呼び出され、構造体要素を初期化するために使用されます。

取引注文フィールド:

  • pos_type - 開くポジションのタイプ(POSITION_TYPE_BUYまたはPOSITION_TYPE_SELL)
  • volume - ポジションボリューム。ボリュームが0.0の場合、入力の「Position size management (lot calculation)」グループから取得されます
  • lot_coefficient - 比率が0.0を超える場合、ポジションボリュームに比率を掛けます

取引注文実行制御のフィールド

  • waiting_transaction - 取引注文が正常に実行され、確認を待つ必要があることを示すフラグ
  • waiting_order_ticket - 取引注文の実行時に取得された注文のインデックス
  • transaction_confirmed - 取引注文の実行が確認されたことを示すフラグ 

transaction_confirmedでフラグを有効にすると、取引注文が構造体から削除されます。したがって、EAの操作に取引注文が含まれない場合、構造体のサイズはゼロになります。構造体のフィールドと制御の詳細については、「トランザクションの取得(簡略化されたコード)」セクションを参照してください。

そのようなアルゴリズムを使用する訳

最初は、Buyメソッドのtruefalseをチェックして、 trueの場合は、取引注文が実行されたと想定するだけで十分なように思われるかもしれません。多くの場合、このアプローチは実際に機能します。ただし、trueを返しても結果が保証されない場合があります。これは、BuyメソッドとSellメソッドに関するドキュメントに記載されています

メモ

メソッドが正常に完了したからといって、必ずしも取引操作が正常に実行されたとは限りません。ResultRetcode()ResultDeal()から返された値を使用して、取引リクエストの結果を確認する必要があります(取引サーバーリターンコード)。

取引履歴でのエントリの存在は、取引操作の実行の最終的かつ正確な確認として役立つ場合があります。したがって、次のアルゴリズムが選択されています。メソッドが正常に実行された場合は、ResultDeal(取引チケット)を確認し、ResultRetcode(実行結果コードのリクエスト)を確認して、ResultOrder (注文チケット)を保存します。注文チケットはOnTradeTransactionにあります。


3. 標準指標の追加 — Indicators Code.mq5ファイルの処理

さらに便利なように、既製のコードブロック(ハンドルの保存、入力、ハンドルの作成のための変数の宣言)は、Indicators Code.mq5 EAに集められています。ハンドルを格納するための指標入力と変数はEAの「ヘッダー」にあり、ハンドルの作成はOnInitで設定されます。ハンドルを格納するための変数の名前は「handle_」 + 「指標」として形成されます(例: handle_iStdDev)。Indicators Code.mq5の処理全体は、コピー-ペースト操作に要約されます。 

NB: MQL5スタイルは、指標ハンドルが1回作成されることを意味します。原則として、これはOnInitで行われます。

3.1. iRVI(Relative Vigor Index、RVI)指標の追加例

Add indicator.mq5 EAを作成します。 MetaEditorで、たとえば新をクリックし、[Expert Advisor (template)]を選択してMQLウィザードを実行します。

Expert Advisor (template)

図3 MQLウィザード ->[Expert Advisor (template)]

次のステップでは少なくとも1つの入力を追加することを強くお勧めします。 

Expert Advisor (template)

図4 Expert Advisor (template) -> パラメータの追加

これにより、入力ブロックの文字列をコードに自動的に追加できます。

//--- input parameters
input int      Input1=9;

MQLウィザードで空のEAが作成されました。次に、iRVI(Relative Vigor Index、RVI)指標を追加しましょう。Indicators Code.mq5で、 handle_iRVIを検索します(ctrl + Fを使用)。検索により、ハンドルが格納されている変数が生成されます。

iRVI

図5 RVIの処理

新しく見つかった文字列をコピーし、「Add indicator」EAヘッダーに挿入します

//--- input parameters
input int      Input1=9;
//---
int      handle_iRVI;                           // variable for storing the handle of the iRVI indicator
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()

検索を再開して、ハンドル作成ブロックを見つけます。

iRVI

図6 iRVIの処理

新しく見つかった文字列をコピーし、「Add indicator」EAのOnInitに挿入します

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- create handle of the indicator iRVI
   handle_iRVI=iRVI(m_symbol.Name(),Inp_RVI_period,Inp_RVI_ma_period);
//--- if the handle is not created
   if(handle_iRVI==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code
      PrintFormat("Failed to create handle of the iRVI indicator for the symbol %s/%s, error code %d",
                  m_symbol.Name(),
                  EnumToString(Inp_RVI_period),
                  GetLastError());
      //--- the indicator is stopped early
      m_init_error=true;
      return(INIT_SUCCEEDED);
     }
//---
   return(INIT_SUCCEEDED);
  }

次に、指標の入力を追加しましょう。Indicators Code.mq5で、たとえばInp_RVI_periodを中クリックして、入力ブロックにすぐに移動します。

iRVI

図7 iRVIの処理

文字列をコピーして、入力に挿入します

#property version   "1.00"
//--- input parameters
input group             "RVI"
input ENUM_TIMEFRAMES      Inp_RVI_period                = PERIOD_D1;      // RVI: timeframe
input int                  Inp_RVI_ma_period             = 15;             // RVI: averaging period
//---
int      handle_iRVI;                           // variable for storing the handle of the iRVI indicator
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+

コンパイルすると、m_symbolおよびm_init_errorエラーが発生します。これらの変数はコンストラクタ操作後に取得されたコードに存在するため、これは予想される動作です。一方、「Add indicator」EAは、Indicators Code.mq5ファイルの処理を示すためだけに作成されています。


4. カスタム指標の追加

MA on DeMarkerカスタム指標を追加します。まず、これはカスタム指標で、次にそれはグループを使用します。前のセクションと同様に、「Add custom indicator」EAを作成します。その後、カスタム指標から入力をコピーしてEAに挿入します。

#property version   "1.00"
//--- input parameters
input group             "DeMarker"
input int                  Inp_DeM_ma_period    = 14;             // DeM: averaging period
input double               Inp_DeM_LevelUP      = 0.7;            // DeM: Level UP
input double               Inp_DeM_LevelDOWN    = 0.3;            // DeM: Level DOWN
input group             "MA"
input int                  Inp_MA_ma_period     = 6;              // MA: averaging period
input ENUM_MA_METHOD       Inp_MA_ma_method     = MODE_EMA;       // MA: smoothing type
//---

Indicators Code.mq5で、カスタム指標ハンドルを格納するためのhandle_iCustom変数を見つけてEAに挿入します 。

//+------------------------------------------------------------------+
//|                                         Add custom indicator.mq5 |
//|                              Copyright © 2021, Vladimir Karputov |
//|                      https://www.mql5.com/en/users/barabashkakvn |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2021, Vladimir Karputov"
#property link      "https://www.mql5.com/en/users/barabashkakvn"
#property version   "1.00"
//--- input parameters
input group             "DeMarker"
input int                  Inp_DeM_ma_period    = 14;             // DeM: averaging period
input double               Inp_DeM_LevelUP      = 0.7;            // DeM: Level UP
input double               Inp_DeM_LevelDOWN    = 0.3;            // DeM: Level DOWN
input group             "MA"
input int                  Inp_MA_ma_period     = 6;              // MA: averaging period
input ENUM_MA_METHOD       Inp_MA_ma_method     = MODE_EMA;       // MA: smoothing type
//---
int      handle_iCustom;                        // variable for storing the handle of the iCustom indicator
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()

Indicators Code.mq5のOnInit()でカスタム指標ハンドル作成ブロックを見つけてEAに挿入します。

int      handle_iCustom;                        // variable for storing the handle of the iCustom indicator
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- create handle of the indicator iCustom
   handle_iCustom=iCustom(m_symbol.Name(),Inp_DEMA_period,"Examples\\DEMA",
                          Inp_DEMA_ma_period,
                          Inp_DEMA_ma_shift,
                          Inp_DEMA_applied_price);
//--- if the handle is not created
   if(handle_iCustom==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code
      PrintFormat("Failed to create handle of the iCustom indicator for the symbol %s/%s, error code %d",
                  m_symbol.Name(),
                  EnumToString(Inp_DEMA_period),
                  GetLastError());
      //--- the indicator is stopped early
      m_init_error=true;
      return(INIT_SUCCEEDED);
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |

ここでやるべきことがいくつかあります。時間枠(InpWorkingPeriod)、指標へのパス(指標フォルダのルートに保存されていると想定)、および入力を設定する必要があります。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- create handle of the indicator iCustom
   handle_iCustom=iCustom(m_symbol.Name(),InpWorkingPeriod,"MA on DeMarker",
                          "DeMarker",
                          Inp_DeM_ma_period,
                          Inp_DeM_LevelUP,
                          Inp_DeM_LevelDOWN,
                          "MA",
                          Inp_MA_ma_period,
                          Inp_MA_ma_method);
//--- if the handle is not created
   if(handle_iCustom==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code
      PrintFormat("Failed to create handle of the iCustom indicator for the symbol %s/%s, error code %d",
                  m_symbol.Name(),
                  EnumToString(InpWorkingPeriod),
                  GetLastError());
      //--- the indicator is stopped early
      m_init_error=true;
      return(INIT_SUCCEEDED);
     }
//---
   return(INIT_SUCCEEDED);
  }

5. トランザクションの取得(簡略化されたコード)

注意: これはEAの簡略版です。多くの関数のコードは本格的なコンストラクタに比べて短くなっています。

このEAによって開かれたポジションが市場にない場合、買いポジションを開くように取引要求を設定します。ポジションを開くための確認は、OnTradeTransactionOnTickから出力されます。以下は、SearchTradingSignals関数での取引注文の検索と書き込みです。

//+------------------------------------------------------------------+
//| Search trading signals                                           |
//+------------------------------------------------------------------+
bool SearchTradingSignals(void)
  {
   if(IsPositionExists())
      return(true);
//---
   int size_need_position=ArraySize(SPosition);
   if(size_need_position>0)
      return(true);
   ArrayResize(SPosition,size_need_position+1);
   SPosition[size_need_position].pos_type=POSITION_TYPE_BUY;
   if(InpPrintLog)
      Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY");
   return(true);
  }

市場にEAによって開かれたポジションがなく、SPosition配列サイズがゼロの場合は、配列サイズを1つ増やします。したがって、単一のSTRUCT_POSITION構造体オブジェクトを作成します。これにより、STRUCT_POSITION()コンストラクタが呼び出されます。コンストラクタを呼び出した後、構造体要素が初期化されます(たとえば、volume - ポジションボリュームは0.0に設定されるので、入力の「Position size management (lot calculation)」グループから取得されます。次に取引注文タイプを構造体に設定するだけです。この場合、「買いポジションを開く」と解釈できます。

取引注文を設定した後、SPosition配列は単一の構造体で構成され、構造体要素の値は次のとおりです。

要素 メモ 
 pos_type  POSITION_TYPE_BUY  SearchTradingSignalsで設定
 取引量  0.0  構造体コンストラクタで初期化
 lot_coefficient  0.0  構造体コンストラクタで初期化
 waiting_transaction  false  構造体コンストラクタで初期化
 waiting_order_ticket  0  構造体コンストラクタで初期化
 transaction_confirmed  false  構造体コンストラクタで初期化

5.1. 新しいティックでOnTickに到達する

以下は、OnTickの一般原則です。

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   int size_need_position=ArraySize(SPosition);
   if(size_need_position>0)
     {
      for(int i=size_need_position-1; i>=0; i--)
        {
         if(SPosition[i].waiting_transaction)
           {
            if(!SPosition[i].transaction_confirmed)
              {
               if(InpPrintLog)
                  Print(__FILE__," ",__FUNCTION__,", OK: ","transaction_confirmed: ",SPosition[i].transaction_confirmed);
               return;
              }
            else
               if(SPosition[i].transaction_confirmed)
                 {
                  ArrayRemove(SPosition,i,1);
                  return;
                 }
           }
         if(SPosition[i].pos_type==POSITION_TYPE_BUY)
           {
            SPosition[i].waiting_transaction=true;
            OpenPosition(i);
            return;
           }
         if(SPosition[i].pos_type==POSITION_TYPE_SELL)
           {
            SPosition[i].waiting_transaction=true;
            OpenPosition(i);
            return;
           }
        }
     }
//--- search for trading signals only at the time of the birth of new bar
   if(!RefreshRates())
      return;
//--- search for trading signals
   if(!SearchTradingSignals())
      return;
//---
  }

OnTickの開始時に、SPosition配列のサイズを確認します(これはSTRUCT_POSITION構造体配列です)。配列サイズがゼロを超える場合、次の2つのシナリオを使用して、ゼロへのトラバースを開始します。 

  • waiting_transaction構造体フラグがtrueの場合(取引注文が準備されている場合は、 確認を待つ)、transaction_confirmedフラグを確認します。 
    • falseの場合、トランザクションはまだ確認されていません(たとえば、 OnTradeTransactionにはまだ確認がないが、取引注文が送信され、新しいティックが到着した場合に発生する可能性があります)。適切なメッセージを印刷してreturnで終了します。新しいティックで情報が更新されることを期待して、新しいティックを待ちます。
    • trueの場合、トランザクションは確認されています。配列から構造を削除し、returnで終了します。
  • waiting_transaction構造体フラグがfalse(取引注文が指定されたばかりで、まだ実行されていない)、waiting_transactionフラグを有効にして、注文をOpenPositionにリダイレクトします。コードブロックは、次のように簡略化できます。

             SPosition[i].waiting_transaction=true;
             OpenPosition(i);
             return;
    ただし、EAコンストラクタの完全な形式を理解しやすくするために、このままにしておきます。
             if(SPosition[i].pos_type==POSITION_TYPE_BUY)
               {
                if(InpCloseOpposite)
                  {
                   if(count_sells>0)
                     {
                      ClosePositions(POSITION_TYPE_SELL);
                      return;
                     }
                  }
                if(InpOnlyOne)
                  {
                   if(count_buys+count_sells==0)
                     {
                      SPosition[i].waiting_transaction=true;
                      OpenPosition(i);
                      return;
                     }
                   else
                     {
                      ArrayRemove(SPosition,i,1);
                      return;
                     }
                  }
                SPosition[i].waiting_transaction=true;
                OpenPosition(i);
                return;
               }
             if(SPosition[i].pos_type==POSITION_TYPE_SELL)
               {
                if(InpCloseOpposite)
                  {
                   if(count_buys>0)
                     {
                      ClosePositions(POSITION_TYPE_BUY);
                      return;
                     }
                  }
                if(InpOnlyOne)
                  {
                   if(count_buys+count_sells==0)
                     {
                      SPosition[i].waiting_transaction=true;
                      OpenPosition(i);
                      return;
                     }
                   else
                     {
                      ArrayRemove(SPosition,i,1);
                      return;
                     }
                  }
                SPosition[i].waiting_transaction=true;
                OpenPosition(i);
                return;
               }

追跡を続けましょう。次のコードブロックを思い出してください。

         if(SPosition[i].pos_type==POSITION_TYPE_BUY)
           {
            SPosition[i].waiting_transaction=true;
            OpenPosition(i);
            return;
           }

取引注文が構造体に設定され(SearchTradingSignals関数で)、waiting_transactionフラグがfalseに設定されています。したがって、waiting_transactionフラグをtrueに設定し、iパラメータをOpenPosition関数に渡します。これは、OpenPosition配列の構造体のシリアル番号です。取引注文タイプはPOSITION_TYPE_BUYであるため、構造体のシリアル番号をOpenBuy関数に渡します。

5.2. OpenBuy関数

この関数の目的は、予備テストに合格し、BUYを開くための取引リクエストを送信し、結果をすぐに追跡することです。

1番目のチェック - SYMBOL_VOLUME_LIMIT

 SYMBOL_VOLUME_LIMIT この銘柄のポジションと一方向(買いまたは売り)の未決注文の最大許容合計ボリューム。たとえば、上限が5ロットの場合、5ロットのポジションがあって5ロットの売り指値注文も行うことができます。ただし、この場合、買い指値注文を出すことはできません(一方向の総量が指値を超えるため)。また、5ロットを超える売り指値注文を出すことはできません。

チェックに通らなかった場合は、構造体要素をSPosition配列から削除します。

2番目のチェック - 証拠金

取引操作後に残っている余剰証拠金(FreeMarginCheck)と取引操作に必要な証拠金(MarginCheck )を取得します。その後、念のために、合計を少なくともFreeMarginCheckと等しくするようにしてください。

   if(free_margin_check>margin_check)

チェックに通らなかった場合は、free_margin_check変数を出力し、SPosition配列から構造体要素を削除します。

3番目のチェック - 買い操作のブール結果

Buyメソッドがfalseを返した場合は、エラーを出力し、waiting_transactionfalseに設定します(最も一般的な理由はエラー10004のリクオートです)。したがって、新しいチケットで買いポジションを再開する試みが行われます。結果がtrueの場合(以下はBuyメソッドが trueを返すコードブロックです)。

         if(m_trade.ResultDeal()==0)
           {
            if(m_trade.ResultRetcode()==10009) // trade order went to the exchange
              {
               SPosition[index].waiting_transaction=true;
               SPosition[index].waiting_order_ticket=m_trade.ResultOrder();
              }
            else
              {
               SPosition[index].waiting_transaction=false;
               if(InpPrintLog)
                  Print(__FILE__," ",__FUNCTION__,", ERROR: ","#1 Buy -> false. Result Retcode: ",m_trade.ResultRetcode(),
                        ", description of result: ",m_trade.ResultRetcodeDescription());
              }
            if(InpPrintLog)
               PrintResultTrade(m_trade,m_symbol);
           }
         else
           {
            if(m_trade.ResultRetcode()==10009)
              {
               SPosition[index].waiting_transaction=true;
               SPosition[index].waiting_order_ticket=m_trade.ResultOrder();
              }
            else
              {
               SPosition[index].waiting_transaction=false;
               if(InpPrintLog)
                  Print(__FILE__," ",__FUNCTION__,", OK: ","#2 Buy -> true. Result Retcode: ",m_trade.ResultRetcode(),
                        ", description of result: ",m_trade.ResultRetcodeDescription());
              }
            if(InpPrintLog)
               PrintResultTrade(m_trade,m_symbol);
           }

その後ResultDeal(取引チケット)を確認します。

取引チケットがゼロの場合ResultRetcode(リクエスト実行結果コード)を確認します。結果のリターン コードは1000です(たとえば、取引注文は取引所などの外部取引システムに送信されたため、取引チケットがゼロです)。waiting_transactiontrueに設定します。 waiting_order_ticketResultOrder (注文チケット)を含みます。それ以外の場合(戻りコードは10009以外)、waiting_transactionfalseに設定されてエラーメッセージが印刷されます。

取引チケットがゼロでない場合(たとえば、実行が同じ取引サーバーで実行される場合)、同様のリターンコードチェックを実行し、値をwaiting_transactionおよびwaiting_order_ticketに書き込みます。

5.3. OnTradeTransaction

取引注文が正常に送信された場合は、取引が実行され、取引履歴に記録されたことの確認を待ちます。OnTradeTransactionでは、trans変数(MqlTradeTransaction型の構造体)を使用します。この構造体にある興味のある文字列はdealtypeの2つだけです。

struct MqlTradeTransaction
  {
   ulong                         deal;             // Deal ticket
   ulong                         order;            // Order ticket
   string                        symbol;           // Symbol name
   ENUM_TRADE_TRANSACTION_TYPE   type;             // Trading transaction type
   ENUM_ORDER_TYPE               order_type;       // Order type
   ENUM_ORDER_STATE              order_state;      // Order state
   ENUM_DEAL_TYPE                deal_type;        // Deal type
   ENUM_ORDER_TYPE_TIME          time_type;        // Order type by lifetime
   datetime                      time_expiration;  // Order expiration time
   double                        price;            // Price 
   double                        price_trigger;    // Stop Limit order trigger price
   double                        price_sl;         // Stop Loss level
   double                        price_tp;         // Take Profit level
   double                        volume;           // Volume in lots
   ulong                         position;         // Position ticket
   ulong                         position_by;      // Opposite position ticket
  };


OnTradeTransactionTRADE_TRANSACTION_DEAL_ADDを取得(履歴に取引を追加)するとすぐに、チェックを実行します。HistoryDealSelectを介して履歴内の取引を選択して、選択に失敗した場合は、エラーを出力します。取引が取引履歴に存在する場合は、SPosition配列をループで繰り返します。ループでは、waiting_transactiontrueに設定されている構造体のみを確認します。 waiting_order_ticketは、選択した取引の注文のチケットと同じです。一致が見つかった場合は、transaction_confirmedtrueに設定します。これは、取引注文が実行され、確認されたことを意味します。

//+------------------------------------------------------------------+
//| TradeTransaction function                                        |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction &trans,
                        const MqlTradeRequest &request,
                        const MqlTradeResult &result)
  {
//--- get transaction type as enumeration value
   ENUM_TRADE_TRANSACTION_TYPE type=trans.type;
//--- if transaction is result of addition of the transaction in history
   if(type==TRADE_TRANSACTION_DEAL_ADD)
     {
      ResetLastError();
      if(HistoryDealSelect(trans.deal))
         m_deal.Ticket(trans.deal);
      else
        {
         Print(__FILE__," ",__FUNCTION__,", ERROR: ","HistoryDealSelect(",trans.deal,") error: ",GetLastError());
         return;
        }
      if(m_deal.Symbol()==m_symbol.Name() && m_deal.Magic()==InpMagic)
        {
         if(m_deal.DealType()==DEAL_TYPE_BUY || m_deal.DealType()==DEAL_TYPE_SELL)
           {
            int size_need_position=ArraySize(SPosition);
            if(size_need_position>0)
              {
               for(int i=0; i<size_need_position; i++)
                 {
                  if(SPosition[i].waiting_transaction)
                     if(SPosition[i].waiting_order_ticket==m_deal.Order())
                       {
                        Print(__FUNCTION__," Transaction confirmed");
                        SPosition[i].transaction_confirmed=true;
                        break;
                       }
                 }
              }
           }
        }
     }
  }

新しいティックでOnTickに移動します。transaction_confirmedtrueがある構造体は、SPosition配列から削除されます。したがって、取引注文は、取引履歴に表示されるまで発行および追跡されています。


6. コンストラクタを使用したEA(ポジション開始シグナル)の作成

EAを開発する前に、その取引ストラテジーについて考える必要があります。iDEMA(二重指数移動平均、DEMA)指標に基づく簡単なストラテジーを考えてみましょう。 これは、コンストラクタで設定されるデフォルトのストラテジーです。オープンシグナルの検出は、新しいバーが表示されたときにのみ試行されますが、取引シグナル自体は順次上下する指標です。

DEMAストラテジー

図8 DEMAストラテジー

いかなるストラテジーもパラメータを調整することで大幅に変更できます。たとえば、テイクプロフィットとストップロスをそのままにして、トレーリングを無効にすることができます。またはその逆トレーリングをそのままにして、テイクプロフィットとストップロスを無効にします。買いまたは売りのみを許可することにより、取引の方向性を制限することもできます。時間制御を有効にして夜間の取引を制限したり、逆に夜間のみの取引を設定したりすることもできます。追加機能グループのパラメータを調整して、取引システムを大幅に変更することもできます。

一般に、取引ストラテジーのバックボーンはSearchTradingSignals関数に組み込まれていますが、他のすべてのパラメータは、最適なアプローチを探して市場を「調査」するためのものです。

EAブランクになる新しいファイルを作成しましょう(図3および4に示されている手順を実行します)。手順4で、EAの一意の名前を「iDEMAFullEA.mq5」に指定します。その結果、次のワークピースが得られます。

//+------------------------------------------------------------------+
//|                                                iDEMA Full EA.mq5 |
//|                              Copyright © 2021, Vladimir Karputov |
//|                      https://www.mql5.com/en/users/barabashkakvn |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2021, Vladimir Karputov"
#property link      "https://www.mql5.com/en/users/barabashkakvn"
#property version   "1.00"
//--- input parameters
input int      Input1=9;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   
  }
//+------------------------------------------------------------------+

次に、Trading engine 3.mq5からコード全体をコピーし、文字列の代わりにコードを挿入します。 次に、「EAヘッダー」を編集します。結果の「ヘッダー」は次のようになります。

//+------------------------------------------------------------------+
//|                                                iDEMA Full EA.mq5 |
//+------------------------------------------------------------------+
//|                                             Trading engine 3.mq5 |
//|                              Copyright © 2021, Vladimir Karputov |
//|                      https://www.mql5.com/en/users/barabashkakvn |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2021, Vladimir Karputov"
#property link      "https://www.mql5.com/en/users/barabashkakvn"
#property version   "4.003"
#property description "barabashkakvn Trading engine 4.003"
#property description "Take Profit, Stop Loss and Trailing - in Points (1.00055-1.00045=10 points)"
/*
   barabashkakvn Trading engine 4.003
*/
#include <Trade\PositionInfo.mqh>

「ヘッダー」を次のようにします。

//+------------------------------------------------------------------+
//|                                                iDEMA Full EA.mq5 |
//|                              Copyright © 2021, Vladimir Karputov |
//|                      https://www.mql5.com/en/users/barabashkakvn |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2021, Vladimir Karputov"
#property link      "https://www.mql5.com/en/users/barabashkakvn"
#property version   "1.001"
#property description "iDEMA EA"
#property description "Take Profit, Stop Loss and Trailing - in Points (1.00055-1.00045=10 points)"
/*
   barabashkakvn Trading engine 4.003
*/
#include <Trade\PositionInfo.mqh>

コンパイルすると、 エラーは発生しません。得られたEAでは取引することさえできます。

6.1. SearchTradingSignals関数

これは、取引注文の可用性をチェックする主な関数です。この関数をブロックごとに考えてみましょう。

バーごとに1つのポジションのみ:

   if(iTime(m_symbol.Name(),InpWorkingPeriod,0)==m_last_deal_in) // on one bar - only one deal
      return(true);

取引時間範囲の確認:

   if(!TimeControlHourMinute())
      return(true);

指標からのデータ受信指標データはdema配列に渡されます。ArraySetAsSeriesを使用すると、インデックスの逆順が設定されます([0]配列要素は、チャートの右端のバーに対応します)。データはiGetArrayカスタム関数を介して受信されます。

   double dema[];
   ArraySetAsSeries(dema,true);
   int start_pos=0,count=6;
   if(!iGetArray(handle_iCustom,0,start_pos,count,dema))
     {
      return(false);
     }
   int size_need_position=ArraySize(SPosition);
   if(size_need_position>0)
      return(true);

買いポジション開始シグナル必要に応じて(InpReverse変数はPositionsReverse入力値を格納します)、取引シグナルを反転させることができます。取引の方向性に制限がある場合(InpTradeMode変数はTrade mode:入力値を格納します)、 考慮されます。

//--- BUY Signal
   if(dema[m_bar_current]>dema[m_bar_current+1] && dema[m_bar_current+1]>dema[m_bar_current+3])
     {
      if(!InpReverse)
        {
         if(InpTradeMode!=sell)
           {
            ArrayResize(SPosition,size_need_position+1);
            SPosition[size_need_position].pos_type=POSITION_TYPE_BUY;
            if(InpPrintLog)
               Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY");
            return(true);
           }
        }
      else
        {
         if(InpTradeMode!=buy)
           {
            ArrayResize(SPosition,size_need_position+1);
            SPosition[size_need_position].pos_type=POSITION_TYPE_SELL;
            if(InpPrintLog)
               Print(__FILE__," ",__FUNCTION__,", OK: ","Signal SELL");
            return(true);
           }
        }
     }

売りシグナルのコードブロックも同様です。 


7. コンストラクタを使用したEA(未決注文シグナル)の作成

EAの名前はiDEMA Full EA Pending.mq5になります。iDEMA Full EA.mq5を開き、新しい名前で保存します。

取引ストラテジーは常に最初に開発され、その後にコードが続きます。セクション「6. コンストラクタを使用したEA(ポジション開始シグナル)の作成」で使用されているストラテジーを少し変更してみましょう。買いポジション開始シグナルは買いストップ未決注文1に置き換えられ、売りポジション開始シグナルは売りストップ未決注文に置き換えられます。未決注文には、次のパラメータが使用されます。

  • Pending: Expiration, in minutes (0 - OFF)600
  • Pending: Indent現在の価格からの未決注文のインデント(未決注文価格が明示的に設定されていない場合)-> 50
  • Pending: Maximum spread (0 -> OFF). 現在のスプレッドが指定されたものを超える場合、未決注文は設定されません(EAはスプレッドが減少するのを待ちます)-> 12
  • Pending: Only one pending有効/無効フラグ。市場で許可されている未決注文は1つだけです->true
  • Pending: Reverse pending type有効/無効フラグ未決注文の反転-> false
  • Pending: New pending -> delete previous ones未決注文を設定する場合は、他のすべての未決注文が事前に削除されます -> true

SearchTradingSignals関数は次のようになります。

//+------------------------------------------------------------------+
//| Search trading signals                                           |
//+------------------------------------------------------------------+
bool SearchTradingSignals(void)
  {
   if(iTime(m_symbol.Name(),InpWorkingPeriod,0)==m_last_deal_in) // on one bar - only one deal
      return(true);
   if(!TimeControlHourMinute())
      return(true);
   double dema[];
   ArraySetAsSeries(dema,true);
   int start_pos=0,count=6;
   if(!iGetArray(handle_iCustom,0,start_pos,count,dema))
     {
      return(false);
     }
   int size_need_pending=ArraySize(SPending);
   if(size_need_pending>0)
      return(true);
//---
   if(InpPendingOnlyOne)
      if(IsPendingOrdersExists())
         return(true);
   if(InpPendingClosePrevious)
      m_need_delete_all=true;
//--- BUY Signal
   if(dema[m_bar_current]>dema[m_bar_current+1] && dema[m_bar_current+1]>dema[m_bar_current+3])
     {
      if(!InpReverse)
        {
         if(InpTradeMode!=sell)
           {
            ArrayResize(SPending,size_need_pending+1);
            SPending[size_need_pending].pending_type=ORDER_TYPE_BUY_STOP;
            if(InpPrintLog)
               Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY STOP");
            return(true);
           }
        }
      else
        {
         if(InpTradeMode!=buy)
           {
            ArrayResize(SPending,size_need_pending+1);
            SPending[size_need_pending].pending_type=ORDER_TYPE_SELL_STOP;
            if(InpPrintLog)
               Print(__FILE__," ",__FUNCTION__,", OK: ","Signal SELL STOP");
            return(true);
           }
        }
     }
//--- SELL Signal
   if(dema[m_bar_current]<dema[m_bar_current+1] && dema[m_bar_current+1]<dema[m_bar_current+3])
     {
      if(!InpReverse)
        {
         if(InpTradeMode!=buy)
           {
            ArrayResize(SPending,size_need_pending+1);
            SPending[size_need_pending].pending_type=ORDER_TYPE_SELL_STOP;
            if(InpPrintLog)
               Print(__FILE__," ",__FUNCTION__,", OK: ","Signal SELL STOP");
            return(true);
           }
        }
      else
        {
         if(InpTradeMode!=sell)
           {
            ArrayResize(SPending,size_need_pending+1);
            SPending[size_need_pending].pending_type=ORDER_TYPE_BUY_STOP;
            if(InpPrintLog)
               Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY STOP");
            return(true);
           }
        }
     }
//---
   /*if(InpPendingOnlyOne)
      if(IsPendingOrdersExists())
         return(true);
   if(InpPendingClosePrevious)
      m_need_delete_all=true;
   int size_need_pending=ArraySize(SPending);
   ArrayResize(SPending,size_need_pending+1);
   if(!InpPendingReverse)
      SPending[size_need_pending].pending_type=ORDER_TYPE_BUY_STOP;
   else
      SPending[size_need_pending].pending_type=ORDER_TYPE_SELL_STOP;
   SPending[size_need_pending].indent=m_pending_indent;
   if(InpPendingExpiration>0)
      SPending[size_need_pending].expiration=(long)(InpPendingExpiration*60);
   if(InpPrintLog)
      Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY STOP");*/
//---
   return(true);
  }

未決注文価格はSPending構造体に設定しません。 これは、現在の価格とインデントが使用されることを意味します。

スプレッドが指定されたものより低くなったときにのみトリガーされた(未決注文が出された)取引シグナルを受け取りました。

iDEMA Full EA Pending

図9 iDEMA Full EA Pending


記事に添付されているファイル

名称 ファイルタイプ 説明
指標コード EA ハンドル、指標入力、指標作成ブロックを格納するための変数
Add indicator.mq5 EA Add indicator.mq5の操作例標準指標の追加
Add custom indicator.mq5 EA
カスタム指標の追加例
Trading engine 4.mq5 EA コンストラクタ
iDEMA Full EA.mq5
EA
コンストラクタの助けを借りて作成されたEA ポジション開始シグナル
iDEMA Full EA Pending.mq5
EA
コンストラクタの助けを借りて作成されたEA 未決注文シグナル

終わりに

この一連の取引機能が、絶えず変化する市場取引条件に対応できる、より信頼性の高いエキスパートアドバイザーの作成に役立つことを願っています。パラメータを試すことを躊躇しないでください。 一部のパラメータを有効にし、他のパラメータを無効にすることで、ストラテジーを大幅に変更できます。


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

添付されたファイル |
Indicators_Code.mq5 (88.76 KB)
Add_indicator.mq5 (4.55 KB)
Trading_engine_4.mq5 (177.98 KB)
iDEMA_Full_EA.mq5 (177.93 KB)
MQL5クックブック - 経済指標カレンダー MQL5クックブック - 経済指標カレンダー
この記事では、経済指標カレンダーのプログラミング機能に焦点を当て、カレンダーのプロパティに簡単にアクセスしてイベント値を受け取るためのクラスの作成について考察し検討します。実用的な例として役立つように、CFTCの投機筋ネットポジションを使用して指標を開発します。
時間の取扱い(第1部):基本 時間の取扱い(第1部):基本
時間の処理、証券会社のオフセット、夏時間または冬時間への変更を簡素化および明確化する関数とコードスニペット。正確なタイミングは取引において重要な要素になることがあります。現在時刻でロンドンやニューヨークの証券取引所がすでに開いているかまだ開いていないか、外国為替取引の取引時間はいつ開始および終了するかなどです。手動で取引して生活しているトレーダーにとって、これは大きな問題ではありません。
手動のチャート作成および取引ツールキット(第III部)最適化と新しいツール 手動のチャート作成および取引ツールキット(第III部)最適化と新しいツール
この記事では、キーボードショートカットを使用してチャート上にグラフィカルオブジェクトを描画するというアイデアをさらに発展させます。ライブラリに新しいツールが追加されました。これには、任意の頂点を通る直線や、反転時間とレベルの評価を可能にする一連の長方形が含まれます。また、この記事では、パフォーマンス向上のためにコードを最適化する可能性を示しています。実装例が書き直され、他の取引プログラムと一緒にShortcutsを使用できるようになりました。初心者より少し上回るコード知識レベルが必要とされます。
DoEasyライブラリのグラフィックス(第88部): グラフィカルオブジェクトコレクション - 動的に変化するオブジェクトのプロパティを格納するための2次元動的配列 DoEasyライブラリのグラフィックス(第88部): グラフィカルオブジェクトコレクション - 動的に変化するオブジェクトのプロパティを格納するための2次元動的配列
本稿では、任意の次元のデータ量を変更できる動的な多次元配列クラスを作成します。作成したクラスに基づいて、動的に変更されたグラフィックオブジェクトのプロパティを格納する2次元の動的配列を作成します。