MQL5を使ったシンプルな多通貨エキスパートアドバイザーの作り方(第4回):三角移動平均 — 指標シグナル

Roberto Jacobs | 20 3月, 2024

はじめに

この記事における多通貨EAの定義は、1つの銘柄チャートからのみ複数の銘柄ペアの取引(注文を出す、注文を決済する、注文を管理するなど)ができるEAまたは自動売買ロボットです。この記事では、EAは30ペアを取引します。

今回は、多時間枠または単一時間枠の「三角移動平均」という1つの指標のみを使用します。
この記事では、EAのシグナル計算を多時間枠をアクティブにするか単一時間枠をアクティブにするかを選択できます。

三角移動平均は著者Mladen RakicによるMT5のカスタム指標です。私は著者からその指標を多通貨EA TriangularMA_MTF_MCEAのシグナルとして使用する許可を受けています。
Rakic氏に敬意を表し、感謝します。

取引ターミナルとストラテジーテスターの両方で、MQL5が提供するパワー、機能、機能を使用して複数通貨取引が可能であることは誰もが知っています。

そのため、この記事では、効率的で効果的な自動売買ロボットを求めるトレーダーの本質的なニーズを満たすことを目的とし、信頼性の高いMQL5が提供する長所、能力、機能に頼ることで、指標シグナルを使用するシンプルな多通貨EAを作成します。三角移動平均指標です。

注:多通貨EA TriangularMA_MTF_MCEAの作成は、トレーダーの提案とリクエストによっておこなわれました。


計画と機能

1.通貨ペアの取引

この多通貨EAは、以下の銘柄またはペアで取引するように計画されています。

28ペア:EURUSD、GBPUSD、AUDUSD、NZDUSD、USDCAD、USDCHF、USDJPY、EURGBP、EURAUD、EURNZD、EURCAD、EURCHF、EURJPY、GBPAUD、GBPNZD、GBPCAD、GBPCHF、GBPJPY、AUDNZD、AUDCAD、AUDCHF、AUDJPY、NZDCAD、NZDCHF、NZDJPY、CADCHF、CADJPY、CHFJPY

メタル2ペア:XAUUSD(金)とXAGUSD(銀)

合計30ペア

前回の記事では、プレフィックスやサフィックスを持つ特別なペア名を持つブローカー上のペアについて、自動関数を使用してプレフィックスやサフィックスを持つペア名を検出しました。
今回は、ペア名のプレフィックスとペア名のサフィックスに特別な入力プロパティを追加することで、それを簡単にします。
次に、簡単な関数を使用して、プレフィックスおよび/またはサフィックスのペア名と、登録されている30個のペア名を組み合わせて処理します。そのため、そのような特殊な銘柄名を持つブローカーからEAがMetaTrader5で使用された場合、すべてがスムーズに実行されます。

プレフィックスとサフィックスを持つ銘柄名を検出する関数の弱点は、この関数がMT5の外国為替および金属銘柄のペアまたは名前に対してのみ機能し、特殊な銘柄やインデックスに対しては機能しないことです。
それとは別に、この方法のもう1つの弱点は、トレーダーがペアのプレフィックスおよび/またはサフィックスの名前にタイプミス(入力の大文字と小文字は区別されるなど)をした場合です。

前回の記事と同様に、このEAでも、現時点で取引されるペアのオプションを10個追加しました。
取引される10のオプションペアの1つは「トレーダーウィッシュペア」で、取引されるペアはトレーダーがEA入力プロパティに手動で入力する必要があります。ただし、入力したペアの名前がす​​でに30ペアのリストに含まれている必要があることを常に覚えておく必要があります。

前回の記事と同様に、このバージョンのEAでは、取引セッション(タイムゾーン)のオプションも追加したため、取引されるペアは取引セッションの時間に対応する可能性があります。


2.シグナル指標

三角移動平均指標の説明の中で、著者は次のように述べています。

「使用法:
色の変化をシグナルとして使用できます...」

デフォルトでは、三角移動平均指標の色は次のとおりです。

このバージョンのEAでは、三角移動平均指標シグナルの計算に時間枠を使用するための2つのオプションを作成しました。

1.多時間枠に基づくシグナル計算
多時間枠計算システムでは、トレーダーは列挙リストから目的の時間枠シリーズを選択する必要があります。
選択した時間枠シリーズの範囲はM5からD1(11時間枠)です。
また、トレーダーは時間枠シリーズを選択し、開始を選択します(例:M15)と終了(例:H4)を選択します。
この場合、EAは、時間枠M15から時間枠H4までの三角移動平均指標シグナルを計算します。

多時間枠での三角移動平均シグナルの計算は次のとおりです。

2.単一時間枠に基づくシグナル計算
単一時間枠シグナル計算システムでは、トレーダーはM5時間枠からD1時間枠までの11時間枠から1つの時間枠を選択する必要があります。
EAは、選択された時間枠から三角移動平均指標シグナルを計算します。

一方、単一時間枠での三角移動平均シグナルの計算は次のようになります。

買いまたは売りシグナルの三角移動平均指標の図を図1と図2に示します。

H4_TriangularMA01

H4_TriangularMA02


3.取引と注文の管理

この多通貨EAの取引管理には、いくつかのオプションが与えられています。

1.ストップロス注文

            UseOrderStopLossでNoを選択すると、すべての注文はストップロスなしで発注されます。

            オプションUse Order Stop LossがYesの場合:

            再びオプションが与えられます。Use Automatic Calculation Stop LossでYes/Noを指定することになります。

            Use Automatic Calculation Stop LossがYesの場合、ストップロスの計算はEAによって自動的に実行されます。

            Use Automatic Calculation Stop LossでNoを選択すると、トレーダーはストップロスの値をPipsで入力する必要があります。

            オプションUse Order Stop LossがNoの場合:

            EAは開かれた各注文について、シグナル状態がまだ良好であるかどうかを確認し、注文します。

            利益を維持できるか、シグナルが弱まり、保存するには注文を閉じる必要がある状態が維持される可能性があります。

            利益またはシグナル状態の方向が逆転したため、損失状態で注文を決済する必要があります。

            注:
            特に弱いシグナルによる取引決済と利益の保存については、それをアクティブにするかどうかのオプションが与えられます。
            アクティブ化されていない場合(No)、シグナルが弱まっても注文は維持されるか、利益を保存するために決済されません。


2.テイクプロフィット注文

            UseOrderTakeProfitでNoを選択した場合、すべての注文はテイクプロフィットなしで発注されます。

            オプションUse Order Take ProfitがYesの場合:

            再びオプションが与えられます。Use Automatic Calculation Order Take Profit:Yes/Noオプションを指定することになります。

            Use Automatic Calculation Order Take ProfitでYesを選択すると、テイクプロフィット注文の計算はEAで自動的におこなわれます。

            Use Automatic Calculation Order Take ProfitでNoを選択した場合、トレーダーは注文のテイクプロフィット値をPipsで入力する必要があります。


3.トレーリングストップとトレーリングテイクプロフィット

            Use Trailing SL/TPがNoの場合、EAはトレーリングストップロスおよびトレーリングテイクプロフィットをおこないません。

            オプションUse Trailing SL/TPがYesの場合:

            再びオプションが与えられます。Use Automatic Trailing:Yes/Noを指定することになります。           

            オプションUse Automatic TrailingがYesの場合、EAは以下を使用してトレーリングストップを実行します。 

            EAによって自動的に選択される時間枠上の三角移動平均バッファ0(指標データ)

            変数値TPmin(最小トレーリング利益値)に基づいてトレーリング利益を得ることによる

            Use Automatic TrailingでNoを選択すると、EAによってトレーリングストップが入力プロパティの値を使用して実行されます。

            注:EAはトレーリングストップと同時にトレーリングテイクプロフィットを実行します。


以下は、トレーリングストップ価格関数です。

double MCEA::TSPrice(const string xsymb,ENUM_POSITION_TYPE ptype,int TS_type)
  {
//---
    int br=2;
    double pval=0.0;
    int x=PairsIdxArray(xsymb);
    Pips(xsymb);
    //--
    switch(TS_type)
      {
        case 0:
          {
            RefreshTick(xsymb);
            if(ptype==POSITION_TYPE_BUY)  pval=mc_symbol.NormalizePrice(mc_symbol.Bid()-TSval*pip);
            if(ptype==POSITION_TYPE_SELL) pval=mc_symbol.NormalizePrice(mc_symbol.Ask()+TSval*pip);
            break;
          }
        case 1:
          {
            double TriMAID[];
            //--
            ArrayResize(TriMAID,br,br);
            ArraySetAsSeries(TriMAID,true);
            CopyBuffer(hTriMAt[x],0,0,br,TriMAID); // Copy buffer 0 from the hTriMAt indicator handle
            //--
            RefreshTick(xsymb);
            if(ptype==POSITION_TYPE_BUY  && (mc_symbol.Bid()>mc_symbol.NormalizePrice(TriMAID[0]+TSval*pip))) pval=TriMAID[0];
            if(ptype==POSITION_TYPE_SELL && (mc_symbol.Ask()<mc_symbol.NormalizePrice(TriMAID[0]-TSval*pip))) pval=TriMAID[0];
            break;
          }
      }
    //--
    return(pval);
//---
  } //-end TSPrice()
//---------//


SL/TP機能を変更します。

bool MCEA::ModifySLTP(const string symbx,int TS_type)
  {
//---
   ResetLastError();
   MqlTradeRequest req={};
   MqlTradeResult  res={};
   MqlTradeCheckResult check={};
   //--
   int TRSP=TS_type;
   bool modist=false;
   int x=PairsIdxArray(symbx);
   Pips(symbx);
   //--
   int total=PositionsTotal();
   //--        
   for(int i=total-1; i>=0; i--) 
     {
       string symbol=PositionGetSymbol(i);
       if(symbol==symbx && mc_position.Magic()==magicEA)
         {
           ENUM_POSITION_TYPE opstype = mc_position.PositionType();
           if(opstype==POSITION_TYPE_BUY) 
             {
               RefreshTick(symbol);
               double price = mc_position.PriceCurrent();
               double vtrsb = mc_symbol.NormalizePrice(TSPrice(symbx,opstype,TRSP));
               double pos_open   = mc_position.PriceOpen();
               double pos_stop   = mc_position.StopLoss();
               double pos_profit = mc_position.Profit();
               double pos_swap   = mc_position.Swap();
               double pos_comm   = mc_position.Commission();
               double netp=pos_profit+pos_swap+pos_comm;
               double modstart=mc_symbol.NormalizePrice(pos_open+TSmin*pip);
               double modminsl=mc_symbol.NormalizePrice(vtrsb+TSmin*pip);
               double modbuysl=vtrsb;
               double modbuytp=mc_symbol.NormalizePrice(price+TPmin*pip);
               bool modbuy = (price>modminsl && modbuysl>modstart && (pos_stop==0.0||modbuysl>pos_stop));
               //--
               if(modbuy && netp>0.05)
                 {
                   modist=mc_trade.PositionModify(symbol,modbuysl,modbuytp);
                 }  
             }
           if(opstype==POSITION_TYPE_SELL) 
             {
               RefreshTick(symbol);
               double price = mc_position.PriceCurrent();
               double vtrss = mc_symbol.NormalizePrice(TSPrice(symbx,opstype,TRSP));
               double pos_open   = mc_position.PriceOpen();
               double pos_stop   = mc_position.StopLoss();
               double pos_profit = mc_position.Profit();
               double pos_swap   = mc_position.Swap();
               double pos_comm   = mc_position.Commission();
               double netp=pos_profit+pos_swap+pos_comm;
               double modstart=mc_symbol.NormalizePrice(pos_open-TSmin*pip);
               double modminsl=mc_symbol.NormalizePrice(vtrss-TSmin*pip);
               double modselsl=vtrss;
               double modseltp=mc_symbol.NormalizePrice(price-TPmin*pip);
               bool modsel = (price<modminsl && modselsl<modstart && (pos_stop==0.0||modselsl<pos_stop)); 
               //--
               if(modsel && netp>0.05)
                 {
                   modist=mc_trade.PositionModify(symbol,modselsl,modseltp);
                 }  
             }
         }
     }
    //--
    return(modist);
//---
  } //-end ModifySLTP()
//---------//


4.手動注文管理

この多通貨EAの効率をサポートするために、いくつかの手動クリックボタンが追加されます。

1.Set SL / TP All Orders

トレーダー入力パラメータが、Use Order Stop Loss:Noおよび/またはUse Order Take Profit:Noに設定されているが
すべての注文でストップロスまたはテイクプロフィットを使用する場合、
[Set SL / TP All Orders]ボタンを1回クリックするだけで済みます。すべての注文が変更され、ストップロスやテイクプロフィットが適用されます。

2.Close All Orders
すべての注文を決済したい場合、[Close All Orders]ボタンを1回クリックするだけで、すべての未決注文が決済されます。

3.Close All Orders Profit
すでに利益を上げている注文をすべて決済したい場合、
[Close All Orders Profit]ボタンを1回クリックするだけで、すでに利益が出ているすべての未処理の注文が決済されます。


5.注文管理とチャート銘柄

1つのチャート銘柄から30ペアを取引する多通貨EAの場合、すべての銘柄にボタンパネルが用意されていれば、トレーダーはワンクリックでチャートや銘柄を変更でき、非常に効果的かつ効率的です。


MQL5プログラムでの実装計画

1.プログラムヘッダーと入力プロパティ

ヘッダーファイルMQL5をインクルードします。

//+------------------------------------------------------------------+
//|                             Include                              |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\SymbolInfo.mqh>
#include <Trade\AccountInfo.mqh>
//--
CTrade              mc_trade;
CSymbolInfo         mc_symbol;
CPositionInfo       mc_position; 
CAccountInfo        mc_account;
//---


使用するタイムゾーンの列挙

//--
enum tm_zone
 {
   Cus_Session,        // Trading on Custom Session
   New_Zealand,        // Trading on New Zealand Session
   Australia,          // Trading on Autralia Sydney Session
   Asia_Tokyo,         // Trading on Asia Tokyo Session
   Europe_London,      // Trading on Europe London Session
   US_New_York         // Trading on US New York Session
 };
//--


時間を選択するための列挙

//--
enum swhour
  {
    hr_00=0,   // 00:00
    hr_01=1,   // 01:00
    hr_02=2,   // 02:00
    hr_03=3,   // 03:00
    hr_04=4,   // 04:00
    hr_05=5,   // 05:00
    hr_06=6,   // 06:00
    hr_07=7,   // 07:00
    hr_08=8,   // 08:00
    hr_09=9,   // 09:00
    hr_10=10,  // 10:00
    hr_11=11,  // 11:00
    hr_12=12,  // 12:00
    hr_13=13,  // 13:00
    hr_14=14,  // 14:00
    hr_15=15,  // 15:00
    hr_16=16,  // 16:00
    hr_17=17,  // 17:00
    hr_18=18,  // 18:00
    hr_19=19,  // 19:00
    hr_20=20,  // 20:00
    hr_21=21,  // 21:00
    hr_22=22,  // 22:00
    hr_23=23   // 23:00
  };
//--


時間、分を選択するための列挙

//--
enum inmnt
  {
    mn_00=0,   // Minute 0
    mn_05=5,   // Minute 5
    mn_10=10,  // Minute 10
    mn_15=15,  // Minute 15
    mn_20=20,  // Minute 20
    mn_25=25,  // Minute 25
    mn_30=30,  // Minute 30
    mn_35=35,  // Minute 35
    mn_40=40,  // Minute 40
    mn_45=45,  // Minute 45
    mn_50=50,  // Minute 50
    mn_55=55   // Minute 55
  };
//--


取引するオプションペアを選択するための列挙

//--
enum PairsTrade
 {
   All30,  // All Forex 30 Pairs
   TrdWi,  // Trader Wishes Pairs 
   Usds,   // Forex USD Pairs
   Eurs,   // Forex EUR Pairs
   Gbps,   // Forex GBP Pairs
   Auds,   // Forex AUD Pairs
   Nzds,   // Forex NZD Pairs
   Cads,   // Forex CDD Pairs
   Chfs,   // Forex CHF Pairs
   Jpys    // Forex JPY Pairs
 };   
//--


列挙体YNは、EA入力プロパティのオプション(Yes)または(No)に使用されます

//--
enum YN
  {
   No,
   Yes
  };
//--


以下は、資金管理ロットサイズを使用する列挙体です。

//--
enum mmt
  {
   FixedLot,   // Fixed Lot Size
   DynamLot    // Dynamic Lot Size
  };
//--


以下は、多時間枠と単一時間枠で使用される時間枠を選択するための列挙体です。

//--
enum TFMTF
  {
   TFM5,     // PERIOD_M5
   TFM15,    // PERIOD_M15
   TFM30,    // PERIOD_M30
   TFH1,     // PERIOD_H1
   TFH2,     // PERIOD_H2
   TFH3,     // PERIOD_H3
   TFH4,     // PERIOD_H4
   TFH6,     // PERIOD_H6
   TFH8,     // PERIOD_H8
   TFH12,    // PERIOD_H12
   TFD1      // PERIOD_D1
  };
//--


以下は、多時間枠または単一時間枠を使用するための列挙体です。

//--
enum SMTF
  {
    MTF,   // Use Multi-Timeframe
    STF    // Use Single-Timeframe
  };
//--


EA入力プロパティ

//---
input group               "=== Global Strategy EA Parameter ==="; // Global Strategy EA Parameter
input SMTF                tfinuse = MTF;              // Select Calculation in Multi or Single Timeframe
input TFMTF              singletf = TFH1;             // Select Single Calculation TimeFrame, default PERIOD_H1
input TFMTF               tfstart = TFM15;            // Select Multi Timeframe calculation start 
input TFMTF               tfclose = TFH4;             // Select Multi Timeframe calculation end
input int              Trmaperiod = 14;               // Input Triangular MA Indicator period, default 14
input ENUM_APPLIED_PRICE  Trprice = PRICE_CLOSE;      // Select Triangular MA Applied Price, default Price Close
//---
input group               "=== Select Pairs to Trade ===";  // Selected Pairs to trading
input PairsTrade         usepairs = All30;           // Select Pairs to Use
input string         traderwishes = "eg. eurusd,usdchf"; // If Use Trader Wishes Pairs, input pair name here, separate by comma
input string           sym_prefix = "";              // Input the symbol prefix in case sensitive (if any)
input string           sym_suffix = "";              // Input the symbol suffix in case sensitive (if any)
//--
input group               "=== Money Management Lot Size Parameter ==="; // Money Management Lot Size Parameter
input mmt                  mmlot = DynamLot;         // Money Management Type
input double                Risk = 10.0;             // Percent Equity Risk per Trade (Min=1.0% / Max=10.0%)
input double                Lots = 0.01;             // Input Manual Lot Size FixedLot
//--Trade on Specific Time
input group               "=== Trade on Specific Time ==="; // Trade on Specific Time
input YN           trd_time_zone = Yes;              // Select If You Like to Trade on Specific Time Zone
input tm_zone            session = Cus_Session;      // Select Trading Time Zone
input swhour            stsescuh = hr_00;            // Time Hour to Start Trading Custom Session (0-23)
input inmnt             stsescum = mn_15;            // Time Minute to Start Trading Custom Session (0-55)
input swhour            clsescuh = hr_23;            // Time Hour to Stop Trading Custom Session (0-23)
input inmnt             clsescum = mn_55;            // Time Minute to Stop Trading Custom Session (0-55)
//--Day Trading On/Off
input group               "=== Day Trading On/Off ==="; // Day Trading On/Off
input YN                    ttd0 = No;               // Select Trading on Sunday (Yes) or (No)
input YN                    ttd1 = Yes;              // Select Trading on Monday (Yes) or (No)
input YN                    ttd2 = Yes;              // Select Trading on Tuesday (Yes) or (No)
input YN                    ttd3 = Yes;              // Select Trading on Wednesday (Yes) or (No)
input YN                    ttd4 = Yes;              // Select Trading on Thursday (Yes) or (No)
input YN                    ttd5 = Yes;              // Select Trading on Friday (Yes) or (No)
input YN                    ttd6 = No;               // Select Trading on Saturday (Yes) or (No)
//--Trade & Order management Parameter
input group               "=== Trade & Order management Parameter ==="; // Trade & Order management Parameter
input YN                  use_sl = No;               // Use Order Stop Loss (Yes) or (No)
input YN                  autosl = Yes;              // Use Automatic Calculation Stop Loss (Yes) or (No)
input double               SLval = 30;               // If Not Use Automatic SL - Input SL value in Pips
input YN                  use_tp = Yes;               // Use Order Take Profit (Yes) or (No)
input YN                  autotp = Yes;              // Use Automatic Calculation Take Profit (Yes) or (No)
input double               TPval = 10;               // If Not Use Automatic TP - Input TP value in Pips
input YN            TrailingSLTP = Yes;              // Use Trailing SL/TP (Yes) or (No)
input YN                 autotrl = Yes;              // Use Automatic Trailing (Yes) or (No)
input double               TSval = 5;                // If Not Use Automatic Trailing Input Trailing value in Pips
input double               TSmin = 5;                // Minimum Pips to start Trailing Stop
input double               TPmin = 25;               // Input Trailing Profit Value in Pips
input YN           Close_by_Opps = Yes;              // Close Trade By Opposite Signal (Yes) or (No)
input YN               SaveOnRev = Yes;              // Close Trade and Save profit due to weak signal (Yes) or (No)
//--Others Expert Advisor Parameter
input group               "=== Others Expert Advisor Parameter ==="; // Others EA Parameter
input YN                  alerts = Yes;              // Display Alerts / Messages (Yes) or (No)
input YN           UseEmailAlert = No;               // Email Alert (Yes) or (No)
input YN           UseSendnotify = No;               // Send Notification (Yes) or (No)
input YN      trade_info_display = Yes;              // Select Display Trading Info on Chart (Yes) or (No)
input ulong               magicEA = 2023111;          // Expert ID (Magic Number)
//---


EA入力プロパティグループのグローバルストラテジーEAパラメータでは、トレーダーは多時間枠または単一時間枠のどちらのシグナル計算を使用するかを選択する必要があります。

単一時間枠(STF)を選択した場合、使用する時間枠を決定する必要があります。
EA入力プロパティで、単一計算時間枠(デフォルトはPERIOD_H1)を選択します。

多時間枠(MTF)を選択した場合、使用する時間枠シリーズを決定する必要があります。
EA入力プロパティでは、「多時間枠計算の開始を選択」および「多時間枠計算の終了を選択」するように指示されます。

TriangularMA_MTF_MCEA_Config()関数の478行目から518行目では、多時間枠と単一時間枠の処理方法が説明されています。

    ENUM_TIMEFRAMES TFs[]={PERIOD_M5,PERIOD_M15,PERIOD_M30,PERIOD_H1,PERIOD_H2,PERIOD_H3,PERIOD_H4,PERIOD_H6,PERIOD_H8,PERIOD_H12,PERIOD_D1};
    int arTFs=ArraySize(TFs);
    //--
    for(int x=0; x<arTFs; x++)
      {
        if(singletf==x) TFt=TFs[x]; // TF for single-timeframe
        if(tfstart==x)  arstr=x;    // multi-timeframe start calculation timeframe
        if(tfclose==x)  arend=x;    // multi-timeframe end calculation timeframe
      }
    //--
    if(arstr>=arend)
      {
        Alert("Error selecting Start and End Timeframe, Start Timeframe must be smaller than End Timeframe");
        Alert("-- "+expname+" -- ",Symbol()," -- expert advisor will be Remove from the chart.");
        ExpertRemove();
      }
    //--
    switch(tfinuse)
      {
        case MTF: 
          {
            TFArrays=arend-arstr+1;
            ArrayResize(TFTri,TFArrays,TFArrays);
            ArrayCopy(TFTri,TFs,0,0,WHOLE_ARRAY);
            tfcinws=arstr+1;
            tftrlst=(int)TFArrays/2;
            TFts=TFs[tftrlst+arstr-1];   // TF for Trailing Stop
            TFCWS=TFs[tfcinws];          // TF for Close Order in weak signal
            break;
          }
        case STF: 
          {
            TFArrays=arTFs;
            ArrayResize(TFTri,TFArrays,TFArrays);
            ArrayCopy(TFTri,TFs,0,0,WHOLE_ARRAY);
            tfcinws=TFIndexArray(TFt)-2 <=0 ? 1 : TFIndexArray(TFt)-2;
            TFts=TFt;            // TF for Trailing Stop
            TFCWS=TFs[tfcinws];  // TF for Close Order in weak signal
            break;
          }
      }


変数ENUM_TIMEFRAMESTFs[]は、列挙オプションenumTFMTFに固有である必要があります。

ENUM_TIMEFRAMES TFs[]={PERIOD_M5,PERIOD_M15,PERIOD_M30,PERIOD_H1,PERIOD_H2,PERIOD_H3,PERIOD_H4,PERIOD_H6,PERIOD_H8,PERIOD_H12,PERIOD_D1};

//--
enum TFMTF
  {
   TFM5,     // PERIOD_M5
   TFM15,    // PERIOD_M15
   TFM30,    // PERIOD_M30
   TFH1,     // PERIOD_H1
   TFH2,     // PERIOD_H2
   TFH3,     // PERIOD_H3
   TFH4,     // PERIOD_H4
   TFH6,     // PERIOD_H6
   TFH8,     // PERIOD_H8
   TFH12,    // PERIOD_H12
   TFD1      // PERIOD_D1
  };
//--


次に、三角MA指標の期間、デフォルト期間14を決定します。
さらに、三角MA適用価格、デフォルトのPRICE_CLOSEも指定する必要があります。

EA入力プロパティグループの[Select Pairs to Trade]では、提供される10のオプションから取引するペアを選択します。デフォルトでは[All Forex 30 Pairs]が決定されます。

取引されるペアを設定するには、HandlingSymbolArrays()関数を呼び出します。
HandlingSymbolArrays()関数を使用して、取引されるすべてのペアを処理します。

void MCEA::HandlingSymbolArrays(void)
  {
//---
    string All30[]={"EURUSD","GBPUSD","AUDUSD","NZDUSD","USDCAD","USDCHF","USDJPY","EURGBP",
                    "EURAUD","EURNZD","EURCAD","EURCHF","EURJPY","GBPAUD","GBPNZD","GBPCAD",
                    "GBPCHF","GBPJPY","AUDNZD","AUDCAD","AUDCHF","AUDJPY","NZDCAD","NZDCHF",
                    "NZDJPY","CADCHF","CADJPY","CHFJPY","XAUUSD","XAGUSD"}; // 30 pairs
    string USDs[]={"USDCAD","USDCHF","USDJPY","AUDUSD","EURUSD","GBPUSD","NZDUSD","XAUUSD","XAGUSD"}; // USD pairs
    string EURs[]={"EURAUD","EURCAD","EURCHF","EURGBP","EURJPY","EURNZD","EURUSD"}; // EUR pairs
    string GBPs[]={"GBPAUD","GBPCAD","GBPCHF","EURGBP","GBPJPY","GBPNZD","GBPUSD"}; // GBP pairs
    string AUDs[]={"AUDCAD","AUDCHF","EURAUD","GBPAUD","AUDJPY","AUDNZD","AUDUSD"}; // AUD pairs
    string NZDs[]={"AUDNZD","NZDCAD","NZDCHF","EURNZD","GBPNZD","NZDJPY","NZDUSD"}; // NZD pairs
    string CADs[]={"AUDCAD","CADCHF","EURCAD","GBPCAD","CADJPY","NZDCAD","USDCAD"}; // CAD pairs
    string CHFs[]={"AUDCHF","CADCHF","EURCHF","GBPCHF","NZDCHF","CHFJPY","USDCHF"}; // CHF pairs
    string JPYs[]={"AUDJPY","CADJPY","CHFJPY","EURJPY","GBPJPY","NZDJPY","USDJPY"}; // JPY pairs
    //--
    sall=ArraySize(All30);
    arusd=ArraySize(USDs);
    aretc=ArraySize(EURs);
    ArrayResize(VSym,sall,sall);
    ArrayCopy(VSym,All30,0,0,WHOLE_ARRAY);
    //--
    if(usepairs==TrdWi && StringFind(traderwishes,"eg.",0)<0)
      {
        string to_split=traderwishes; // A string to split into substrings pairs name
        string sep=",";               // A separator as a character 
        ushort u_sep;                 // The code of the separator character 
        //--- Get the separator code 
        u_sep=StringGetCharacter(sep,0);
        //--- Split the string to substrings 
        int p=StringSplit(to_split,u_sep,SPC); 
        if(p>0)
          {
            for(int i=0; i<p; i++) StringToUpper(SPC[i]);
            //--
            for(int i=0; i<p; i++)
              {
                if(ValidatePairs(SPC[i])<0) ArrayRemove(SPC,i,1);
              }
          }
        arspc=ArraySize(SPC);
      }
    //--
    SetSymbolNamePS();      // With this function we will detect whether the Symbol Name has a prefix and/or suffix
    //--
    if(inpre>0 || insuf>0)
      {
        if(usepairs==TrdWi && arspc>0)
          {
            for(int t=0; t<arspc; t++)
              {
                SPC[t]=pre+SPC[t]+suf;
              }
          }
        //--
        for(int t=0; t<sall; t++)
          {
            All30[t]=pre+All30[t]+suf;
          }
        for(int t=0; t<arusd; t++)
          {
            USDs[t]=pre+USDs[t]+suf;
          }
        for(int t=0; t<aretc; t++)
          {
            EURs[t]=pre+EURs[t]+suf;
          }
        for(int t=0; t<aretc; t++)
          {
            GBPs[t]=pre+GBPs[t]+suf;
          }
        for(int t=0; t<aretc; t++)
          {
            AUDs[t]=pre+AUDs[t]+suf;
          }
        for(int t=0; t<aretc; t++)
          {
            NZDs[t]=pre+NZDs[t]+suf;
          }
        for(int t=0; t<aretc; t++)
          {
            CADs[t]=pre+CADs[t]+suf;
          }
        for(int t=0; t<aretc; t++)
          {
            CHFs[t]=pre+CHFs[t]+suf;
          }
        for(int t=0; t<aretc; t++)
          {
            JPYs[t]=pre+JPYs[t]+suf;
          }
      }
    //--
    ArrayCopy(VSym,All30,0,0,WHOLE_ARRAY);
    ArrayResize(AS30,sall,sall);
    ArrayCopy(AS30,All30,0,0,WHOLE_ARRAY);
    for(int x=0; x<sall; x++) {SymbolSelect(AS30[x],true);}
    if(ValidatePairs(Symbol())>=0) symbfix=true;
    if(!symbfix) 
      {
        Alert("Expert Advisors will not trade on pairs "+Symbol());
        Alert("-- "+expname+" -- ",Symbol()," -- expert advisor will be Remove from the chart.");
        ExpertRemove();
      }
    //--
    switch(usepairs)
      {
        case 0: // All Forex 30 Pairs
          {
            ArrayResize(DIRI,sall,sall);
            arrsymbx=sall;
            ArraySymbolResize();
            ArrayCopy(DIRI,All30,0,0,WHOLE_ARRAY);
            pairs="Multi Currency 30 Pairs";
            //--
            break;
          }
        case 1: // Trader wishes pairs
          {
            ArrayResize(DIRI,arspc,arspc);
            arrsymbx=arspc;
            ArraySymbolResize();
            ArrayCopy(DIRI,SPC,0,0,WHOLE_ARRAY);
            pairs="("+string(arspc)+") Trader Wishes Pairs";
            //--
            break;
          }
        case 2: // USD pairs
          {
            ArrayResize(DIRI,arusd,arusd);
            arrsymbx=arusd;
            ArraySymbolResize();
            ArrayCopy(DIRI,USDs,0,0,WHOLE_ARRAY);
            pairs="("+string(arusd)+") Multi Currency USD Pairs";
            //--
            break;
          }
        case 3: // EUR pairs
          {
            ArrayResize(DIRI,aretc,aretc);
            arrsymbx=aretc;
            ArraySymbolResize();
            ArrayCopy(DIRI,EURs,0,0,WHOLE_ARRAY);
            pairs="("+string(aretc)+") Forex EUR Pairs";
            //--
            break;
          }
        case 4: // GBP pairs
          {
            ArrayResize(DIRI,aretc,aretc);
            arrsymbx=aretc;
            ArraySymbolResize();
            ArrayCopy(DIRI,GBPs,0,0,WHOLE_ARRAY);
            pairs="("+string(aretc)+") Forex GBP Pairs";
            //--
            break;
          }
        case 5: // AUD pairs
          {
            ArrayResize(DIRI,aretc,aretc);
            arrsymbx=aretc;
            ArraySymbolResize();
            ArrayCopy(DIRI,AUDs,0,0,WHOLE_ARRAY);
            pairs="("+string(aretc)+") Forex AUD Pairs";
            //--
            break;
          }
        case 6: // NZD pairs
          {
            ArrayResize(DIRI,aretc,aretc);
            arrsymbx=aretc;
            ArraySymbolResize();
            ArrayCopy(DIRI,NZDs,0,0,WHOLE_ARRAY);
            pairs="("+string(aretc)+") Forex NZD Pairs";
            //--
            break;
          }
        case 7: // CAD pairs
          {
            ArrayResize(DIRI,aretc,aretc);
            arrsymbx=aretc;
            ArraySymbolResize();
            ArrayCopy(DIRI,CADs,0,0,WHOLE_ARRAY);
            pairs="("+string(aretc)+") Forex CAD Pairs";
            //--
            break;
          }
        case 8: // CHF pairs
          {
            ArrayResize(DIRI,aretc,aretc);
            arrsymbx=aretc;
            ArraySymbolResize();
            ArrayCopy(DIRI,CHFs,0,0,WHOLE_ARRAY);
            pairs="("+string(aretc)+") Forex CHF Pairs";
            //--
            break;
          }
        case 9: // JPY pairs
          {
            ArrayResize(DIRI,aretc,aretc);
            arrsymbx=aretc;
            ArraySymbolResize();
            ArrayCopy(DIRI,JPYs,0,0,WHOLE_ARRAY);
            pairs="("+string(aretc)+") Forex JPY Pairs";
            //--
            break;
          }
      }
    //--
    return;
//---
  } //-end HandlingSymbolArrays()
//---------//


HandlingSymbolArrays()関数内でSetSymbolNamePS()関数を呼び出します。
SetSymbolNamePS()関数を使用すると、プレフィックスやサフィックスを持つ銘柄名を処理できるようになります。

void MCEA::SetSymbolNamePS(void)
  {
//---
   symbfix=false;
   int ptriml;
   int ptrimr;
   string insymbol=Symbol();
   int sym_Lenpre=StringLen(prefix);
   int sym_Lensuf=StringLen(suffix);
   if(sym_Lenpre>0)
     {
       ptriml=StringTrimLeft(suffix);
       ptriml=StringTrimRight(suffix);
     }
   if(sym_Lensuf>0)
     {
       ptrimr=StringTrimLeft(suffix);
       ptrimr=StringTrimRight(suffix);
     }
   string sym_pre=prefix;
   string sym_suf=suffix;
   //--
   pre=sym_pre;
   suf=sym_suf;
   inpre=StringLen(pre);
   insuf=StringLen(suf);
   posCur1=inpre;
   posCur2=posCur1+3;
   //--
   return;
//---
  } //-end SetSymbolNamePS()
//---------//

注:
EAがペアを検証します。
トレーダーがペア名、ペアプレフィックス名、ペアサフィックス名の入力を間違えた場合(タイプミス)や
ペアの検証が失敗した場合、EAは警告を発し、EAがチャートから削除されます。


EA入力プロパティグループ[Trade on Specific Time]では、[Trade on Specific Time Zone]でYesまたはNoを選択します。
Yesの場合は、列挙オプションを選択します。

カスタムセッションでの取引:このセッションでは、トレーダーは取引を開始する時刻、または取引を終了する時間と分を設定する必要があります。

したがって、EAは開始から終了までの指定された時間内のみアクティビティを実行します。

ニュージーランドセッションでの取引から米国ニューヨークセッションでの取引では、取引開始から取引終了までの時間がEAによって計算されます。


この多通貨EAに必要なすべての変数、オブジェクト、関数を宣言するために、EAのワークフローにおける構築と構成を指定するクラスを作成します。

特に、プレフィックス銘柄名やサフィックス銘柄名を処理する関数で使用される変数、およびタイムゾーンの計算は、MCEAクラスで作成されました。

//+------------------------------------------------------------------+
//| Class for working Expert Advisor                                 |
//+------------------------------------------------------------------+
class MCEA
  {
//---
    private:
    //---- 
    int              x_year;       // Year 
    int              x_mon;        // Month 
    int              x_day;        // Day of the month 
    int              x_hour;       // Hour in a day 
    int              x_min;        // Minutes 
    int              x_sec;        // Seconds
    //--
    int              oBm,
                     oSm,
                     ldig;
    //--- Variables used in prefix and suffix symbols
    int              posCur1,
                     posCur2;
    int              inpre,
                     insuf;
    bool             symbfix;
    string           pre,suf;
    string           prefix,suffix;       
    //--- Variables are used in Trading Time Zone
    int              ishour,
                     onhour;
    int              tftrlst,
                     tfcinws;
    datetime         rem,
                     znop,
                     zncl,
                     zntm;
    datetime         SesCuOp,
                     SesCuCl,
                     Ses01Op,
                     Ses01Cl,
                     Ses02Op,
                     Ses02Cl,
                     Ses03Op,
                     Ses03Cl,
                     Ses04Op,
                     Ses04Cl,
                     Ses05Op,
                     Ses05Cl,
                     SesNoOp,
                     SesNoCl;
    //--
    string           tz_ses,
                     tz_opn,
                     tz_cls;
    //--
    string           tmopcu,
                     tmclcu,
                     tmop01,
                     tmcl01,
                     tmop02,
                     tmcl02,
                     tmop03,
                     tmcl03,
                     tmop04,
                     tmcl04,
                     tmop05,
                     tmcl05,
                     tmopno,
                     tmclno;      
    //----------------------    
    //--
    double           LotPS;
    double           slv,
                     tpv,
                     pip,
                     xpip;              
    double           floatprofit,
                     fixclprofit;
    //--
    string           pairs,
                     hariini,
                     daytrade,
                     trade_mode;
    //--
    double           OPEN[],
                     HIGH[],
                     LOW[],
                     CLOSE[];
    datetime         TIME[];
    datetime         closetime;
    //--
    //------------
     
    //------------
    void             SetSymbolNamePS(void);
    void             HandlingSymbolArrays(void);
    void             Set_Time_Zone(void);
    void             Time_Zone(void);
    bool             Trade_session(void);
    string           PosTimeZone(void);
    int              ThisTime(const int reqmode);
    int              ReqTime(datetime reqtime,const int reqmode);
    //--
    int              DirectionMove(const string symbol,const ENUM_TIMEFRAMES stf);
    int              TriaMASMTF(const string symbol,ENUM_TIMEFRAMES mtf);
    int              GetTriaMASignalMTF(string symbol);
    int              TriaMASignalSTF(const string symbol);
    int              LotDig(const string symbol);
    //--
    double           MLots(const string symbx);
    double           NonZeroDiv(double val1,double val2);
    double           OrderSLSet(const string xsymb,ENUM_ORDER_TYPE type,double atprice);
    double           OrderTPSet(const string xsymb,ENUM_ORDER_TYPE type,double atprice);
    double           SetOrderSL(const string xsymb,ENUM_POSITION_TYPE type,double atprice);
    double           SetOrderTP(const string xsymb,ENUM_POSITION_TYPE type,double atprice);
    double           TSPrice(const string xsymb,ENUM_POSITION_TYPE ptype,int TS_type);
    //--
    string           ReqDate(int d,int h,int m);
    string           TF2Str(ENUM_TIMEFRAMES period);
    string           timehr(int hr,int mn);
    string           TradingDay(void);
    string           AccountMode();
    string           GetCommentForOrder(void)             { return(expname); }
    //------------

    public:
    //---
    
    //-- TriangularMA_MTF_MCEA Config --
    string           DIRI[],
                     AS30[],
                     VSym[];
    string           SPC[];
    string           USD[];
    string           EUR[];
    string           GBP[];
    string           AUD[];
    string           NZD[];
    string           CAD[];
    string           CHF[];
    string           JPY[];             
    //--                 
    string           expname;
    string           indiname;
    //--
    int              hTriMAt[];
    int              hTriMAs[];
    int              hTriMAm[];
    int              hTriMAb[][11];
    int              ALO,
                     dgts,
                     arrsar,
                     arrsymbx;
    int              sall,
                     arusd,
                     aretc,
                     arspc,
                     arper;
    ulong            slip;        
    //--
    double           profitb[],
                     profits[];
    //--
    int              Buy,
                     Sell;
    int              ccur,
                     psec,
                     xtto,
                     TFArrays,
                     checktml;
    int              OpOr[],xob[],xos[];         
    //--
    int              year,  // Year 
                     mon,   // Month 
                     day,   // Day 
                     hour,  // Hour 
                     min,   // Minutes 
                     sec,   // Seconds 
                     dow,   // Day of week (0-Sunday, 1-Monday, ... ,6-Saturday) 
                     doy;   // Day number of the year (January 1st is assigned the number value of zero)
    //--
    ENUM_TIMEFRAMES  TFt,
                     TFts,
                     TFT05,
                     TFCWS;
    ENUM_TIMEFRAMES  TFTri[];
    //--
    bool             PanelExtra;
    //------------
                     MCEA(void);
                     ~MCEA(void);            
    //------------
    //--
    virtual void     TriangularMA_MTF_MCEA_Config(void);
    virtual void     ExpertActionTrade(void);
    //--
    void             ArraySymbolResize(void);
    void             CurrentSymbolSet(const string symbol);
    void             Pips(const string symbol);
    void             TradeInfo(void);
    void             Do_Alerts(const string symbx,string msgText);
    void             CheckOpenPMx(const string symbx);
    void             SetSLTPOrders(void);
    void             CloseBuyPositions(const string symbol);
    void             CloseSellPositions(const string symbol);
    void             CloseAllOrders(void);
    void             CheckClose(const string symbx);
    void             TodayOrders(void);
    void             UpdatePrice(const string symbol,ENUM_TIMEFRAMES xtf);
    void             RefreshPrice(const string symbx,ENUM_TIMEFRAMES xtf,int bars);
    //--
    bool             RefreshTick(const string symbx);  
    bool             TradingToday(void);
    bool             OpenBuy(const string symbol);
    bool             OpenSell(const string symbol);
    bool             ModifyOrderSLTP(double mStop,double ordtp);
    bool             ModifySLTP(const string symbx,int TS_type);          
    bool             CloseAllProfit(void);
    bool             ManualCloseAllProfit(void);
    //--
    int              PairsIdxArray(const string symbol);
    int              ValidatePairs(const string symbol);
    int              TFIndexArray(ENUM_TIMEFRAMES TF);
    int              GetOpenPosition(const string symbol);
    int              GetSignalMidTF(const string symbol);
    int              GetCloseInWeakSignal(const string symbol,int exis);
    //--
    string           getUninitReasonText(int reasonCode);
    //--
    //------------
//---
  }; //-end class MCEA
//---------//


OnInit()から呼び出される他通貨EAワークプロセスの最初で最も重要な関数はTriangularMA_MTF_MCEA_Config()です。

TriangularMA_MTF_MCEA_Config()関数では、使用するすべての銘柄が設定され、すべてのハンドル指標が使用され、エキスパートアドバイザワークフローのインクルードファイルヘッダーのいくつかの重要な機能が設定されます。

void MCEA::TriangularMA_MTF_MCEA_Config(void) 
  {
//---
    //--
    HandlingSymbolArrays(); // With this function we will handle all pairs that will be traded
    //--
    int arstr=0,
        arend=0;
    TFT05=PERIOD_M5;
    ENUM_TIMEFRAMES TFs[]={PERIOD_M5,PERIOD_M15,PERIOD_M30,PERIOD_H1,PERIOD_H2,PERIOD_H3,PERIOD_H4,PERIOD_H6,PERIOD_H8,PERIOD_H12,PERIOD_D1};
    int arTFs=ArraySize(TFs);
    //--
    for(int x=0; x<arTFs; x++)
      {
        if(singletf==x) TFt=TFs[x]; // TF for single-timeframe
        if(tfstart==x)  arstr=x;    // multi-timeframe start calculation timeframe
        if(tfclose==x)  arend=x;    // multi-timeframe end calculation timeframe
      }
    //--
    if(arstr>=arend)
      {
        Alert("Error selecting Start and End Timeframe, Start Timeframe must be smaller than End Timeframe");
        Alert("-- "+expname+" -- ",Symbol()," -- expert advisor will be Remove from the chart.");
        ExpertRemove();
      }
    //--
    switch(tfinuse)
      {
        case MTF: 
          {
            TFArrays=arend-arstr+1;
            ArrayResize(TFTri,TFArrays,TFArrays);
            ArrayCopy(TFTri,TFs,0,0,WHOLE_ARRAY);
            tfcinws=arstr+1;
            tftrlst=(int)TFArrays/2;
            TFts=TFs[tftrlst+arstr-1];   // TF for Trailing Stop
            TFCWS=TFs[tfcinws];          // TF for Close Order in weak signal
            break;
          }
        case STF: 
          {
            TFArrays=arTFs;
            ArrayResize(TFTri,TFArrays,TFArrays);
            ArrayCopy(TFTri,TFs,0,0,WHOLE_ARRAY);
            tfcinws=TFIndexArray(TFt)-2 <=0 ? 1 : TFIndexArray(TFt)-2;
            TFts=TFt;            // TF for Trailing Stop
            TFCWS=TFs[tfcinws];  // TF for Close Order in weak signal
            break;
          }
      }
    //--
    //-- Triangular MA Indicators handle for all symbol
    for(int x=0; x<arrsymbx; x++) 
      {
        hTriMAs[x]=iCustom(DIRI[x],TFT05,indiname,Trmaperiod,Trprice);
        hTriMAm[x]=iCustom(DIRI[x],TFCWS,indiname,Trmaperiod,Trprice);
        hTriMAt[x]=iCustom(DIRI[x],TFts,indiname,Trmaperiod,Trprice);
        //--
        for(int i=0; i<TFArrays; i++)
          {
            if(tfinuse==MTF) // MTF indicator handle
              {
                hTriMAb[x][i]=iCustom(DIRI[x],TFTri[i],indiname,Trmaperiod,Trprice);
              }
            if(tfinuse==STF)
              {
                if(TFs[i]==TFt) // Single-TF indicator handle
                  {
                    hTriMAb[x][i]=iCustom(DIRI[x],TFs[i],indiname,Trmaperiod,Trprice);
                    break;
                  }
              }
          }
      }
    //--
    ALO=(int)mc_account.LimitOrders()>sall ? sall : (int)mc_account.LimitOrders();
    //--
    LotPS=(double)ALO;
    //--
    mc_trade.SetExpertMagicNumber(magicEA);
    mc_trade.SetDeviationInPoints(slip);
    mc_trade.SetMarginMode();
    Set_Time_Zone();
    //--
    return;
//---
  } //-end TriangularMA_MTF_MCEA_Config()
//---------//


2.EAティック関数

EAのティック関数(OnTick()関数)の中で、多通貨EAのメイン関数の1つである関数ExpertActionTrade()を呼び出します。

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(void)
  {
//---
    mc.ExpertActionTrade();
    //--
    return;
//---
  } //-end OnTick()
//---------//


この関数内のEAワークプロセスのシーケンス。

ExpertActionTrade()関数は、オープン注文、クローズ注文、トレーリングストップまたは取引利益、その他の追加アクティビティから始まるすべてのアクティビティを実行し、自動取引を管理します。

void MCEA::ExpertActionTrade(void)
  {
//---
    //--Check Trading Terminal
    ResetLastError();
    //--
    if(!MQLInfoInteger(MQL_TRADE_ALLOWED) && mc.checktml==0) //-- Check whether MT5 Algorithmic trading is Allow or Prohibit
      {
        mc.Do_Alerts(Symbol(),"Trading Expert at "+Symbol()+" are NOT Allowed by Setting.");
        mc.checktml=1;  //-- Variable checktml is given a value of 1, so that the alert is only done once.
        return;
      }
    //--
    if(!DisplayManualButton("M","C","R")) DisplayManualButton(); //-- Show the expert manual button panel
    //--
    if(trade_info_display==Yes) mc.TradeInfo(); //-- Displayed Trading Info on Chart
    //---
    //--
    int mcsec=mc.ThisTime(mc.sec); 
    //--
    if(fmod((double)mcsec,5.0)==0) mc.ccur=mcsec;
    //--
    if(mc.ccur!=mc.psec)
      {
        string symbol;
        //-- Here we start with the rotation of the name of all symbol or pairs to be traded
        for(int x=0; x<mc.arrsymbx && !IsStopped(); x++) 
          {
            //-- 
            if(mc.DIRI[x]==Symbol()) symbol=Symbol();
            else symbol=mc.DIRI[x];
            //--
            mc.CurrentSymbolSet(symbol);
            //--
            if(mc.TradingToday() && mc.Trade_session())
              {
                //--
                mc.OpOr[x]=mc.GetOpenPosition(symbol); //-- Get trading signals to open positions
                //--                                   //-- and store in the variable OpOr[x]
                if(mc.OpOr[x]==mc.Buy) //-- If variable OpOr[x] get result of GetOpenPosition(symbol) as "Buy" (value=1)
                  {
                    //--
                    mc.CheckOpenPMx(symbol);
                    //--
                    if(Close_by_Opps==Yes && mc.xos[x]>0) mc.CloseSellPositions(symbol);
                    //--
                    if(mc.xob[x]==0 && mc.xtto<mc.ALO) mc.OpenBuy(symbol);
                    else
                    if(mc.xtto>=mc.ALO)
                      {
                        //--
                        mc.Do_Alerts(symbol,"Maximum amount of open positions and active pending orders has reached"+
                                            "\n the limit = "+string(mc.ALO)+" Orders ");
                        //--
                        mc.CheckOpenPMx(symbol);
                        //--
                        if(mc.xos[x]>0 && mc.profits[x]<-1.02 && mc.xob[x]==0) {mc.CloseSellPositions(symbol); mc.OpenBuy(symbol);}
                        else
                        if(SaveOnRev==Yes) mc.CloseAllProfit();
                      }
                  }
                if(mc.OpOr[x]==mc.Sell) //-- If variable OpOr[x] get result of GetOpenPosition(symbol) as "Sell" (value=-1)
                  {
                    //--
                    mc.CheckOpenPMx(symbol);
                    //--
                    if(Close_by_Opps==Yes && mc.xob[x]>0) mc.CloseBuyPositions(symbol);
                    //--
                    if(mc.xos[x]==0 && mc.xtto<mc.ALO) mc.OpenSell(symbol);
                    else
                    if(mc.xtto>=mc.ALO)
                      {
                        //--
                        mc.Do_Alerts(symbol,"Maximum amount of open positions and active pending orders has reached"+
                                            "\n the limit = "+string(mc.ALO)+" Orders ");
                        //--
                        mc.CheckOpenPMx(symbol);
                        //--
                        if(mc.xob[x]>0 && mc.profitb[x]<-1.02 && mc.xos[x]==0) {mc.CloseBuyPositions(symbol); mc.OpenSell(symbol);}
                        else
                        if(SaveOnRev==Yes) mc.CloseAllProfit();
                      }
                  }
              }
            //--
            mc.CheckOpenPMx(symbol);
            //--
            if(mc.xtto>0)
              {
                //--
                if(SaveOnRev==Yes) //-- Close Trade and Save profit due to weak signal (Yes)
                  {
                    mc.CheckOpenPMx(symbol);
                    if(mc.profitb[x]>0.02 && mc.xob[x]>0 && mc.GetCloseInWeakSignal(symbol,mc.Buy)==mc.Sell) 
                      {
                        mc.CloseBuyPositions(symbol); 
                        mc.Do_Alerts(symbol,"Close BUY order "+symbol+" to save profit due to weak signal.");
                      }
                    if(mc.profits[x]>0.02 && mc.xos[x]>0 && mc.GetCloseInWeakSignal(symbol,mc.Sell)==mc.Buy)
                      {
                        mc.CloseSellPositions(symbol); 
                        mc.Do_Alerts(symbol,"Close SELL order "+symbol+" to save profit due to weak signal.");
                      }
                  }
                //--
                if(TrailingSLTP==Yes) //-- Use Trailing SL/TP (Yes)
                  {
                    if(autotrl==Yes) mc.ModifySLTP(symbol,1); //-- If Use Automatic Trailing (Yes)
                    if(autotrl==No)  mc.ModifySLTP(symbol,0); //-- Use Automatic Trailing (No)
                  }
              }
            //--
            mc.CheckClose(symbol);
          }
        //--
        mc.psec=mc.ccur;
      }
    //--
    return;
//---
  } //-end ExpertActionTrade()
//---------//


特にタイムゾーン取引の場合、ExpertActionTrade()関数にブール型Trade_session()関数の呼び出しが追加されます。
Trade_session()がtrueの場合、EAの作業プロセスは終了するまで続行されますが、falseの場合、EAは「シグナルが弱いため取引を終了して利益を保存する(Yes)」および「」タスクのみを実行します。トレーリングストップ(Yes)」。

bool MCEA::Trade_session(void)
  {
//---
   bool trd_ses=false;
   ishour=ThisTime(hour);
   if(ishour!=onhour) Set_Time_Zone();
   datetime tcurr=TimeCurrent(); // Server Time
   //--
   switch(session)
     {
       case Cus_Session:
         {
           if(tcurr>=SesCuOp && tcurr<=SesCuCl) trd_ses=true;
           break;
         }
       case New_Zealand:
         {
           if(tcurr>=Ses01Op && tcurr<=Ses01Cl) trd_ses=true;
           break;
         }
       case Australia:
         {
           if(tcurr>=Ses02Op && tcurr<=Ses02Cl) trd_ses=true;
           break;
         }
       case Asia_Tokyo:
         {
           if(tcurr>=Ses03Op && tcurr<=Ses03Cl) trd_ses=true;
           break;
         }
       case Europe_London:
         {
           if(tcurr>=Ses04Op && tcurr<=Ses04Cl) trd_ses=true;
           break;
         }
       case US_New_York:
         {
           if(tcurr>=Ses05Op && tcurr<=Ses05Cl) trd_ses=true;
           break;
         }
     }
   //--
   if(trd_time_zone==No) 
     {
      if(tcurr>=SesNoOp && tcurr<=SesNoCl) trd_ses=true;
     }
   //--
   onhour=ishour;
   //--
   return(trd_ses);
//---  
  } //-end Trade_session()
//---------//


3.オープンポジションの取引シグナルの取得

シグナルを取得するには、ExpertActionTrade()関数はGetOpenPosition()関数を呼び出します。

int MCEA::GetOpenPosition(const string symbol) // Signal Open Position 
  {
//---
    int ret=0;
    int rise=1,
        down=-1;
    //--
    int trimOp=GetTriaMASignalMTF(symbol);
    int getmid=GetSignalMidTF(symbol);
    if(trimOp==rise && getmid==rise) ret=rise;
    if(trimOp==down && getmid==down) ret=down;
    //--
    return(ret);
//---
  } //-end GetOpenPosition()
//---------//


GetOpenPosition()関数は、シグナル計算を実行する2つの関数を呼び出します。

1. GetSignalMidTF(const string symbol);          //--中間時間​​枠と価格変動ポジションのシグナルを取得する関数

int MCEA::GetSignalMidTF(const string symbol) // Signal Indicator Position Close in profit
  {
//---
    int ret=0;
    int rise=1,
        down=-1;
    //--
    int br=2;
    //--
    double TriMACI[];
    //--
    ArrayResize(TriMACI,br,br);
    ArraySetAsSeries(TriMACI,true);
    int xx=PairsIdxArray(symbol);
    CopyBuffer(hTriMAm[xx],1,0,br,TriMACI);
    //#property indicator_color1  clrDarkGray,clrDeepPink,clrMediumSeaGreen
    //                                 0          1             2
    //--
    int dirmove=DirectionMove(symbol,TFCWS);
    //--
    if(TriMACI[0]==2.0 && dirmove==rise) ret=rise;
    if(TriMACI[0]==1.0 && dirmove==down) ret=down;
    //--
    return(ret);
//---
  } //-end GetSignalMidTF()
//---------//


2.GetTriaMASignalMTF(const string symbol);    //--三角移動平均の計算式への関数

GetTriaMASignalMTF()関数は、要求された時間枠に従って三角移動平均シグナルを計算する関数TriaMASMTF()を呼び出します。

int MCEA::GetTriaMASignalMTF(string symbol)
  {
//---
    int mv=0;
    int rise=1,
        down=-1;
    int tfloop=tfinuse==MTF ? TFArrays : 1;
    //--
    int trimup=0,
        trimdw=0;
    //--    
    for(int x=0; x<tfloop; x++)
      {
        if(TriaMASMTF(symbol,TFTri[x])>0) trimup++;
        if(TriaMASMTF(symbol,TFTri[x])<0) trimdw++;
      }   
    //--
    if(trimup==tfloop) mv=rise;
    if(trimdw==tfloop) mv=down;
    //--
    return(mv);
//---
  } //- end GetTriaMASignalMTF()
//---------//


int MCEA::TriaMASMTF(const string symbol,const ENUM_TIMEFRAMES mtf) // formula Triangular MA on the requested Timeframe
  {
//---
    int ret=0;
    int rise=1,
        down=-1;
    int br=3;
    ENUM_TIMEFRAMES TFUse=tfinuse==MTF ? mtf : TFt;
    //--
    double TriMACI[];
    ArrayResize(TriMACI,br,br);
    ArraySetAsSeries(TriMACI,true);
    int xx=PairsIdxArray(symbol);
    int tx=TFIndexArray(TFUse);
    CopyBuffer(hTriMAb[xx][tx],1,0,br,TriMACI);
    //#property indicator_color1  clrDarkGray,clrDeepPink,clrMediumSeaGreen
    //                                 0          1             2
    //Print("Symbol = "+symbol+" TF = "+EnumToString(mtf)+" TriMACI[0] = "+string(TriMACI[0]));
    //--
    switch(tfinuse)
      {
        case MTF:
          {
            if(TriMACI[0]==2.0) ret=rise;
            if(TriMACI[0]==1.0) ret=down;
            //--
            break;
          }
        case STF:
          {
            if(TriMACI[2]==1.0 && TriMACI[1]==2.0 && TriMACI[0]==2.0) ret=rise;
            if(TriMACI[2]==2.0 && TriMACI[1]==1.0 && TriMACI[0]==1.0) ret=down;
            //--
            break;
          }
      }
    //--
    return(ret);
//---
  } //-end TriaMASMTF()
//---------//


ご覧のとおり、TriaMASMTF()関数内で2つの関数を使用して呼び出します。

PairsIdxArray()関数は、要求された銘柄の名前を取得するために使用され、TFIndexArray()関数は、要求された時間枠の時間枠配列シーケンスを取得するために使用されます。
次に、適切な指標ハンドルが呼び出されて、その時間枠から三角移動平均シグナルのバッファ値を取得します。

三角移動平均指標の作者は次のように述べています。
「使用法:
色の変化をシグナルとして使用できます...」

では、三角移動平均指標のシグナルをどのように取得するのでしょうか。

三角移動平均指標のプロパティ:

#property indicator_color1  clrDarkGray,clrDeepPink,clrMediumSeaGreen
//                               0            1             2
SetIndexBuffer(1,valc,INDICATOR_COLOR_INDEX);
valc[i] = (i>0) ?(val[i]>val[i-1]) ? 2 :(val[i]<val[i-1]) ? 1 : valc[i-1]: 0;


したがって、次のことがわかります。

したがって、TriaMASMTF()関数と同様に、CopyBuffer関数によって三角移動平均指標のバッファ1の値をシグナルとして取得できます。

    double TriMACI[];
    ArrayResize(TriMACI,br,br);
    ArraySetAsSeries(TriMACI,true);
    int xx=PairsIdxArray(symbol);
    int tx=TFIndexArray(TFUse);
    CopyBuffer(hTriMAb[xx][tx],1,0,br,TriMACI);
    //#property indicator_color1  clrDarkGray,clrDeepPink,clrMediumSeaGreen
    //                                 0           1             2


4.ChartEvent関数

多通貨EAの使用における有効性と効率性をサポートするには、注文の管理およびチャートや銘柄の変更用にいくつかの手動ボタンを作成する必要があると
考えられます。

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
//--- handling CHARTEVENT_CLICK event ("Clicking the chart")
   ResetLastError();
   //--
   ENUM_TIMEFRAMES CCS=mc.TFt;
   //--
   if(id==CHARTEVENT_OBJECT_CLICK) 
     {
       int lensymbol=StringLen(Symbol());
       int lensparam=StringLen(sparam);
       //--
       //--- if "Set SL All Orders" button is click
       if(sparam=="Set SL/TP All Orders") 
         { 
           mc.SetSLTPOrders();
           Alert("-- "+mc.expname+" -- ",Symbol()," -- Set SL/TP All Orders");
           //--- unpress the button 
           ObjectSetInteger(0,"Set SL/TP All Orders",OBJPROP_STATE,false);
           ObjectSetInteger(0,"Set SL/TP All Orders",OBJPROP_ZORDER,0);
           CreateManualPanel();
         }
       //--- if "Close All Order" button is click
       if(sparam=="Close All Order") 
         { 
           mc.CloseAllOrders();
           Alert("-- "+mc.expname+" -- ",Symbol()," -- Close All Orders");
           //--- unpress the button 
           ObjectSetInteger(0,"Close All Order",OBJPROP_STATE,false);
           ObjectSetInteger(0,"Close All Order",OBJPROP_ZORDER,0);
           CreateManualPanel();
         }
       //--- if "Close All Profit" button is click
       if(sparam=="Close All Profit") 
         { 
           mc.ManualCloseAllProfit();
           Alert("-- "+mc.expname+" -- ",Symbol()," -- Close All Profit");
           //--- unpress the button 
           ObjectSetInteger(0,"Close All Profit",OBJPROP_STATE,false);
           ObjectSetInteger(0,"Close All Profit",OBJPROP_ZORDER,0);
           CreateManualPanel();
         }
       //--- if "X" button is click
       if(sparam=="X") 
         { 
           ObjectsDeleteAll(0,0,OBJ_BUTTON);
           ObjectsDeleteAll(0,0,OBJ_LABEL);
           ObjectsDeleteAll(0,0,OBJ_RECTANGLE_LABEL);
           //--- unpress the button 
           ObjectSetInteger(0,"X",OBJPROP_STATE,false);
           ObjectSetInteger(0,"X",OBJPROP_ZORDER,0);
           //--
           DeleteButtonX();
           mc.PanelExtra=false;
           DisplayManualButton();
         }
       //--- if "M" button is click
       if(sparam=="M") 
         { 
           //--- unpress the button 
           ObjectSetInteger(0,"M",OBJPROP_STATE,false);
           ObjectSetInteger(0,"M",OBJPROP_ZORDER,0);
           mc.PanelExtra=true;
           CreateManualPanel();
         }
       //--- if "C" button is click
       if(sparam=="C") 
         { 
           //--- unpress the button 
           ObjectSetInteger(0,"C",OBJPROP_STATE,false);
           ObjectSetInteger(0,"C",OBJPROP_ZORDER,0);
           mc.PanelExtra=true;
           CreateSymbolPanel();
         }
       //--- if "R" button is click
       if(sparam=="R") 
         { 
           Alert("-- "+mc.expname+" -- ",Symbol()," -- expert advisor will be Remove from the chart.");
           ExpertRemove();
           //--- unpress the button 
           ObjectSetInteger(0,"R",OBJPROP_STATE,false);
           ObjectSetInteger(0,"R",OBJPROP_ZORDER,0);
           if(!ChartSetSymbolPeriod(0,Symbol(),Period()))
             ChartSetSymbolPeriod(0,Symbol(),Period());
           DeletePanelButton();
           ChartRedraw(0);
         }
       //--- if Symbol button is click
       if(lensparam==lensymbol)
         {
           int sx=mc.ValidatePairs(sparam);
           ChangeChartSymbol(mc.AS30[sx],CCS);
           mc.PanelExtra=false;
         }
       //--
     }
    //--
    return;
//---
  } //-end OnChartEvent()
//---------//


ワンクリックでチャート銘柄を変更するには、銘柄名のいずれかをクリックすると、OnChartEvent()が関数ChangeChartSymbol()として呼び出されます。

void ChangeChartSymbol(string c_symbol,ENUM_TIMEFRAMES cstf)
  {
//---
   //--- unpress the button 
   ObjectSetInteger(0,c_symbol,OBJPROP_STATE,false);
   ObjectSetInteger(0,c_symbol,OBJPROP_ZORDER,0);
   ObjectsDeleteAll(0,0,OBJ_BUTTON);
   ObjectsDeleteAll(0,0,OBJ_LABEL);
   ObjectsDeleteAll(0,0,OBJ_RECTANGLE_LABEL);
   //--
   ChartSetSymbolPeriod(0,c_symbol,cstf);
   //--
   ChartRedraw(0);
   //--
   return;
//---
  } //-end ChangeChartSymbol()
//---------//


EA取引モードの多時間枠または単一時間枠、取引セッションまたは取引タイムゾーン、および取引されるペアのオプションを追加しているため、チャートに表示される取引情報に追加情報が必要です。
チャートに表示される取引情報に情報を追加するために、TradeInfo()関数に変更を加えました。

void MCEA::TradeInfo(void) // function: write comments on the chart
  {
//----
   Pips(Symbol());
   double spread=SymbolInfoInteger(Symbol(),SYMBOL_SPREAD)/xpip;
   rem=zntm-TimeCurrent();
   string postime=PosTimeZone();
   string eawait=" - Waiting for active time..!";
   //--
   string tradetf=tfinuse==MTF ? EnumToString(Period()) : EnumToString(TFts);
   string eamode=tfinuse==MTF ? "Multi-Timeframe" : "Single-Timeframe";
   string comm="";
   TodayOrders();
   //--
   comm="\n     :: Server Date Time : "+string(ThisTime(year))+"."+string(ThisTime(mon))+"."+string(ThisTime(day))+ "   "+TimeToString(TimeCurrent(),TIME_SECONDS)+
        "\n     ------------------------------------------------------------"+
        "\n      :: Broker               :  "+ TerminalInfoString(TERMINAL_COMPANY)+
        "\n      :: Expert Name      :  "+ expname+
        "\n      :: Acc. Name         :  "+ mc_account.Name()+
        "\n      :: Acc. Number      :  "+ (string)mc_account.Login()+
        "\n      :: Acc. TradeMode :  "+ AccountMode()+
        "\n      :: Acc. Leverage    :  1 : "+ (string)mc_account.Leverage()+
        "\n      :: Acc. Equity       :  "+ DoubleToString(mc_account.Equity(),2)+
        "\n      :: Margin Mode     :  "+ (string)mc_account.MarginModeDescription()+
        "\n      :: Magic Number   :  "+ string(magicEA)+
        "\n      :: Trade on TF      :  "+ tradetf+
        "\n      :: Trade Mode      :  "+ eamode+
        "\n      :: Today Trading   :  "+ TradingDay()+" : "+hariini+
        "\n      :: Trading Session :  "+ tz_ses+
        "\n      :: Trading Time    :  "+ postime;
        if(TimeCurrent()<zntm)
          {
            comm=comm+
            "\n      :: Time Remaining :  "+(string)ReqTime(rem,hour)+":"+(string)ReqTime(rem,min)+":"+(string)ReqTime(rem,sec) + eawait;
          }
        comm=comm+
        "\n     ------------------------------------------------------------"+
        "\n      :: Trading Pairs     :  "+pairs+
        "\n      :: BUY Market      :  "+string(oBm)+
        "\n      :: SELL Market     :  "+string(oSm)+
        "\n      :: Total Order       :  "+string(oBm+oSm)+
        "\n      :: Order Profit      :  "+DoubleToString(floatprofit,2)+
        "\n      :: Fixed Profit       :  "+DoubleToString(fixclprofit,2)+
        "\n      :: Float Money     :  "+DoubleToString(floatprofit,2)+
        "\n      :: Nett Profit        :  "+DoubleToString(floatprofit+fixclprofit,2);
   //--
   Comment(comm);
   ChartRedraw(0);
   return;
//----
  } //-end TradeInfo()  
//---------//


また、TradeInfo()関数の一部として、取引タイムゾーンの条件に従って時間を記述する関数も追加しました。

string MCEA::PosTimeZone(void)
  {
//---
    string tzpos="";
    //--
    if(ReqTime(zntm,day)>ThisTime(day))
     {
       tzpos=tz_opn+ " Next day to " +tz_cls + " Next day";
     }
    else
    if(TimeCurrent()<znop)
      {
        if(ThisTime(day)==ReqTime(znop,day) && ThisTime(day)==ReqTime(zncl,day))
          tzpos=tz_opn+" to " +tz_cls+ " Today";
        //else
        if(ThisTime(day)==ReqTime(znop,day) && ThisTime(day)<ReqTime(zncl,day))
          tzpos=tz_opn+ " Today to " +tz_cls+ " Next day";
      }
    else
    if(TimeCurrent()>=znop && TimeCurrent()<zncl)
      {
        if(ThisTime(day)<ReqTime(zncl,day))
          tzpos=tz_opn+ " Today to " +tz_cls+ " Next day";
        else
        if(ThisTime(day)==ReqTime(zncl,day))
          tzpos=tz_opn+" to " +tz_cls+ " Today";
      }
    else
    if(ThisTime(day)==ReqTime(znop,day) && ThisTime(day)<ReqTime(zncl,day))
      {
        tzpos=tz_opn+" Today to " +tz_cls+ " Next day";
      }
    //--
    return(tzpos);
//----
  } //-end PosTimeZone()
//---------//


多通貨EA TriangularMA_MTF_MCEAのインターフェイスは次の図のようになります。

情報


ご覧のとおり、EA名TriangularMA_MTF_MCEAの下に[M]、[C]、[R]ボタンがあります。

Expert_manual_button

[M]ボタンがクリックされると、以下のように手動クリックボタンパネルが表示されます。

Expert_manual_button_01

その後、トレーダーは手動注文管理で説明されているように注文を管理できます。


[C]ボタンをクリックすると、30個の銘柄名またはペアのパネルボタンが表示され、いずれかのペア名または銘柄名をクリックできます。
ペア名または銘柄のいずれかがクリックされると、チャート銘柄は即座にクリックされた名前の銘柄に置き換わります。

Expert_manual_button_02


[R]ボタンをクリックすると、多通貨EA TriangularMA_MTF_MCEAがチャートから削除されます。
そのため、EAを手動で切り離す必要はありません。



ストラテジーテスター

知られているように、MetaTrader 5ターミナルのストラテジーテスターは、戦略のテスト、複数の銘柄の取引、または利用可能なすべての銘柄と利用可能なすべての時間枠の自動取引のテストをサポートしており、これを可能にします。

したがって、この機会に、MetaTrader 5ストラテジーテスタープラットフォーム上の多通貨EAで多時間枠および単一時間枠としてTriangularMA_MTF_MCEAをテストします。

1. TriangularMA_MTF_MCEAを多時間枠モードでテストします。

st-mtf/p>


st-mtf-result


2.TriangularMA_MTF_MCEAを単一時間枠モードでテストします。

st-stf


st-stf-result



結論

MQL5を使用して多時間枠モードと単一時間枠モードの両方で多通貨EAを作成した結論は次のとおりです。

注:
組み込みのMQL5標準指標シグナルに基づいてシンプルな複数通貨EAを作成するアイデアをお持ちの方は、コメントでご提案ください。
この記事とMQL5多通貨EAプログラムが、トレーダーの皆さんの学習とアイデアの開発に役立つことを願っています。ご精読ありがとうございました。