English Español Deutsch 日本語
preview
Создаем простой мультивалютный советник с использованием MQL5 (Часть 4): Треугольная скользящая средняя — Сигналы индикатора

Создаем простой мультивалютный советник с использованием MQL5 (Часть 4): Треугольная скользящая средняя — Сигналы индикатора

MetaTrader 5Трейдинг | 22 марта 2024, 11:16
609 5
Roberto Jacobs
Roberto Jacobs

Введение

Под мультивалютным советником в этой статье понимается советник, или торговый робот, который может торговать (открывать/закрывать ордера, управлять ордерами, например, трейлинг-стоп-лоссом и трейлинг-профитом) более чем одной парой символов с одного графика. В этой статье советник будет торговать по 30 парам.

На этот раз мы будем использовать только один индикатор, а именно треугольную скользящую среднюю на одном или нескольких таймфреймах.
    В этой статье при расчете сигналов советника можно будет выбрать, активировать ли один или несколько таймфреймов.

    Треугольная скользящая средняя - это пользовательский индикатор для MetaTrader 5, созданный Младеном Ракичем (Mladen Rakic). Я получил разрешение от автора использовать его индикатор в качестве сигнала на мультивалютном советнике TriangularMA_MTF_MCEA.
    Спасибо Младену Ракичу за предоставленную возможность.

    Мы знаем, что мультивалютная торговля как в торговом терминале, так и в тестере стратегий, возможна благодаря MQL5.

    Таким образом, цель состоит в том, чтобы удовлетворить основные потребности трейдеров, которым нужны эффективные и действенные торговые роботы. Полагаясь на сильные стороны и возможности MQL5, мы можем создать простой мультивалютный советник, который в этой статье использует сигналы треугольной скользящей средней.

    Примечание: Мультивалютный советник TriangularMA_MTF_MCEA создан по просьбе трейдеров.


    Особенности

    1. Торговые пары.

    Советник будет торговать на следующих парах:

    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 = 28 пар

    Плюс 2 пары металлов: XAUUSD (золото) и XAGUSD (серебро).

    Всего 30 пар.

    В предыдущей статье мы использовали автоматическую функцию для обнаружения имен пар с префиксами и/или суффиксами.
    В этой статье мы упростили задачу, добавив специальные входные свойства для префикса и суффикса имени пары.
    Затем с помощью простой функции мы обрабатываем имена пар префиксов и/или суффиксов в сочетании с 30 зарегистрированными именами пар, так что если в MetaTrader 5 используется советник с такими специальными именами символов, все будет работать гладко.

    Недостаток функции обнаружения имен символов, имеющих префиксы и суффиксы, заключается в том, что она работает только с парами или именами символов для форекс и металлов в MetaTrader 5, но не работает со специальными символами и индексами.
    Кроме того, еще одним недостатком этого метода является необходимость избегать опечаток (необходимо вводить с учетом регистра) в названии префикса и/или суффикса пары.

    Как и в предыдущей статье, в этот советник мы также добавили 10 опционов на торгуемые пары.
    Одной из 10 пар опционов, которые будут торговаться, является Trader Wishes Pairs (трейдерские пары), где торгуемые пары должны быть введены трейдером вручную в свойствах советника. Не забывайте, что имя введенной пары уже должно быть в списке из 30 пар.

    Как и в предыдущей статье, в этой версии советника мы также добавили опцию торговой сессии (часовой пояс), поэтому торгуемые пары соответствуют времени торговой сессии.


    2. Индикатор сигналов.

    В описании треугольной скользящей средней автор пишет:

    "Использование:
    В качестве сигнала можно использовать смену цвета".

    Цвета индикатора треугольной скользящей средней по умолчанию:

    • 0-DarkGray = неизвестный сигнал
    • 1-DeepPink = сигнал на продажу
    • 2-MediumSeaGreen = сигнал на покупку.

    В этой версии советника мы создали два варианта использования таймфреймов при расчете сигнала треугольной скользящей средней.

    1. Расчет сигналов на основе мультитаймфрейма.
    В системе расчета с несколькими таймфреймами трейдеры должны выбрать из списка перечисления желаемую серию таймфреймов.
    Выбранная серия таймфреймов предоставлена в диапазоне от M5 до D1 (11 таймфреймов).
    Трейдеры могут выбрать серию таймфреймов - начало (например, M15) и конец (например, H4).
    Итак, советник будет рассчитывать сигнал треугольной скользящей средней, начиная с таймфрейма M15 и заканчивая H4.

    Расчеты треугольной скользящей средней на нескольких таймфреймах:

    • Сигнал на покупку, если на всех выбранных таймфреймах индикатор окрашен в цвет MediumSeaGreen, и
    • Сигнал на продажу, если на всех выбранных таймфреймах индикатор окрашен в цвет DeepPink.

    2. Расчет сигналов на основе одного таймфрейма.
    В системе расчета сигналов на одном таймфрейме трейдеры должны выбрать один таймфрейм из 11, начиная с M5 и заканчивая D1.
    Таким образом, советник рассчитает сигнал индикатора треугольной скользящей средней на выбранном таймфрейме.

    Между тем, расчет сигнала треугольной скользящей средней на одном таймфрейме выглядит так:

    • Сигнал на покупку, если предыдущие 2 бара — DeepPink, предыдущий 1 бар — MediumSeaGreen и текущий бар — MediumSeaGreen.
    • Сигнал на продажу, если предыдущие 2 бара — MediumSeaGreen, предыдущий 1 бар — DeepPink и текущий бар — DeepPink.

    Треугольную скользящую среднюю для сигналов покупки и продажи можно увидеть на рисунках 1 и 2.

    H4_TriangularMA01

      H4_TriangularMA02


      3. Управление торговлей и ордерами.

      Управление торговлей в этом мультивалютном советнике имеет несколько вариантов:

      1. Ордера стоп-лосс

      • Варианты: Use Order Stop Loss (Yes) или (No) - использовать ордер стоп-лосс: да или нет

                  При выборе Use Order Stop Loss (No) все ордера будут открываться без стоп-лосса.

                  При выборе Use Order Stop Loss (Yes):

                  Снова предоставляется выбор: Use Automatic Calculation Stop Loss (Yes) или (No) - использовать автоматически рассчитываемый стоп-лосс: да или нет

                  При выборе Automatic Calculation Stop Loss (Yes) стоп-лосс рассчитывается советником.

                  При выборе Automatic Calculation Stop Loss (No) трейдеру необходимо ввести значение стоп-лосса в пипсах.

                  Если Use Order Stop Loss (No):

                  Затем советник проверит состояние сигнала для каждого открытого ордера и оценит

                  потенциал прибыли. Если сигнал слабеет, значит ордер необходимо закрыть, чтобы сохранить

                  прибыль. Или сигнал указывает на смену направления, и ордер необходимо закрыть с убытком.

                  Примечание:
                  Перед закрытием сделки из-за слабого сигнала запрашивается подтверждение пользователя.


      2. Ордера тейк-профит

      • Варианты: Use Order Take Profit (Yes) или (No) - использовать тейк-профит ордера: да или нет

                  При выборе Use Order Take Profit (No) все ордера будут открываться без тейк-профита.

                  При Use Order Take Profit (Yes):

                  Снова предоставляется выбор: Use Automatic Calculation Order Take Profit (Yes) или (No) - использовать автоматически рассчитываемый тейк-профит: да или нет

                  При выборе Automatic Calculation Order Take Profit (Yes) тейк-профит рассчитывается советником.

                  При выборе Automatic Calculation Order Take Profit (No) трейдеру необходимо ввести значение тейк-профита в пипсах.


      3. Трейлинг-стоп и трейлинг тейк-профита

      • Варианты: Use Trailing SL/TP (Yes) или (No) - использовать стоп-лосс/тейк-профит трейлинга: да или нет

                  При Use Trailing SL/TP option (No) советник не будет использовать стоп-лосс и тейк-профит трейлинга.

                  При Use Trailing SL/TP (Yes):

                  Снова предоставляется выбор: Use Automatic Trailing (Yes) или (No) - использовать автоматический трейлинг: да или нет           

                  При Use Automatic Trailing (Yes) трейлинг-стоп выполняется советником с использованием 

                  нулевого буфера треугольной скользящей средней (данные индикатора) на таймфрейме, который автоматически выбирается советником, и одновременно

                  с получением скользящей прибыли на основе значения переменной TPmin (минимальное значение скользящей прибыли).

                  При Use Automatic Trailing (No) трейлинг-стоп выполняется советником с использованием значения входного параметра.

                  Примечание: Советник осуществляет трейлинг тейк-профита одновременно с трейлинг-стопом.


      Функция Trailing Stop Price:

      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. Ручное управление ордерами.

      Для повышения эффективности будет добавлено несколько кнопок.

      1. Set SL / TP All Orders (установить стоп-лосс/тейк-профит для всех ордеров)

      Если трейдер установит Use Order Stop Loss (No) и/или Use Order Take Profit (No),
      но затем захочет использовать стоп-лосс или тейк-профит для всех ордеров, ему необходимо лишь нажать на кнопку
      Set SL / TP All Orders для изменения всех ордеров и применения стоп-лосса и/или тейк-профита.

      2. Close All Orders
      Закрыть все ордера.

      3. Close All Orders Profit
      Если трейдер хочет закрыть все ордера, которые уже прибыльны, то достаточно одного нажатия кнопки
      Close All Orders Profit для закрытия всех открытых прибыльных ордеров.


      5. Management Orders and Chart Symbols.

      Очень полезной функцией для мультивалютных советников, торгующих 30 парами с одного графика, будет наличие единой панели кнопок, чтобы трейдеры могли менять графики или символы одним щелчком мыши.


      Реализация планирования в 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 используется для опций (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
        };
      //--


      Входные параметры советника

      //---
      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)
      //---


      В группе свойств входных данных Global Strategy EA Parameter советника трейдеры должны выбрать, использовать ли расчет сигналов на одном таймфрейме или нескольких.

      При выборе одного таймфрейма (STF) его необходимо указать.
      Во входном параметре советника выберите Select Single Calculation timeframe (выбрать один таймфрейм для расчета), значение по умолчанию - PERIOD_H1.

      При выборе нескольких таймфреймов (MTF), их необходимо указать.
      Во входном параметре советника выберите Select Multi Timeframe calculation start (начало расчета на нескольких таймфреймах) и Select Multi Timeframe calculation end (окончание расчета на нескольких таймфреймах).

      В строках 478-518 функции TriangularMA_MTF_MCEA_Config() объясняется, как работать с одним и несколькими таймфреймами.

          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_TIMEFRAMES TFs[] должна быть свойственна опции перечисления enum TFMTF

      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
        };
      //--


      Затем трейдер должен определить период индикатора Triangular MA. Период по умолчанию - 14.
      Кроме того, необходимо указать цену расчета Triangular MA. Цена по умолчанию - PRICE_CLOSE.

      В группе свойств входных данных Select Pairs to Trade необходимо выбрать пару для торговли из 10 предоставленных вариантов. Значение по умолчанию - All Forex 30 Pairs (все 30 форекс-пар).

      Чтобы настроить торгуемую пару, вызовем функцию 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().
      С ее помощью мы сможем обрабатывать имена символов, которые имеют префиксы и/или суффиксы.

      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()
      //---------//

      Примечание:
      Советник проверит пары.
      Если трейдер допустил ошибку при вводе названия пары или названия префикса/суффикса
      либо проверка пары не удалась, советник выдаст предупреждение и будет удален с графика.


      В группе свойств входных данных Trade on Specific Time, трейдеру нужно выбрать Trade on Specific Time Zone (Yes) или (No)
      - торговать в определенном часовом поясе: да или нет При Yes необходимо выбрать параметры перечисления:

      • Trading on Custom Session (пользовательская сессия)
      • Trading on New Zealand Session (новозеландская сессия)
      • Trading on Australia Sydney Session (сиднейская сессия)
      • Trading on Asia Tokyo Session (токийская сессия)
      • Trading on Europe London Session (лондонская сессия)
      • Trading on America New York Session (нью-йоркская сессия)

      Trading on Custom Session (пользовательская сессия): Трейдеры должны установить время или часы и минуты для начала торговли и часы и минуты для закрытия торговли.

      Таким образом, советник будет выполнять действия только в течение указанного времени.

      В остальных случаях время начала и окончания торговли выбирается советником.


      Чтобы объявить все переменные, объекты и функции, необходимые в этом мультивалютном советнике, мы создадим класс, чтобы указать конструкцию и рабочие настройки советника.

      В частности, переменные, используемые в функции для обработки имен префиксных символов и/или имен суффиксных символов, а также расчетов часовых поясов, мы сделали в классе 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(), - это TriangularMA_MTF_MCEA_Config().

      В функции TriangularMA_MTF_MCEA_Config() настраиваются все используемые символы, все применяемые индикаторы хэндлов и некоторые важные функции заголовка файла include.

      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. Функция Expert tick

      В функции Expert tick (OnTick()) мы будем вызывать одну из основных функций мультивалютного советника, а именно функцию ExpertActionTrade().

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


      Последовательность работы советника внутри этой функции.

      Функция 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, советник работает до завершения, а при false, советник будет выполнять только задачи Close Trade and Save profit due to weak signal (Yes) (закрыть сделку и сохранить прибыль из-за слабого сигнала (Да)) и Trailing stop (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() вызовет две функции, выполняющие расчет сигналов:

      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():

      • 1. int xx= PairsIdxArray(symbol)
      • 2. int tx=TFIndexArray(mtf).

      Функция 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;


      Итак, мы знаем, что:

      • 0-DarkGray = неизвестный сигнал
      • 1-DeepPink = сигнал на продажу
      • 2-MediumSeaGreen = сигнал на покупку.

      Итак, мы можем взять значение буфера 1 треугольной скользящей средней в качестве сигнала с помощью функции CopyBuffer, как и в функции TriaMASMTF().

          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

      Для большей эффективности мультивалютных советников создадим несколько кнопок для управления ордерами, а также
      изменения графиков и символов.

      //+------------------------------------------------------------------+
      //| 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()
      //---------//


      Поскольку мы добавляем торговую сессию или торговый часовой пояс и параметры торгуемых пар на одном или нескольких таймфреймах, нам нужно добавить новые данные в отображаемой торговой информации на графике. Для этого мы внесли изменения в функцию 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()
      //---------//


      Интерфейс мультивалютного советника TriangularMA_MTF_MCEA выглядит следующим образом.

      TradeInfo


      Как видите, под именем советника TriangularMA_MTF_MCEA расположены кнопки M, C и R

      Expert_manual_button

      При нажатии на M отобразится панель ручного управления

      Expert_manual_button_01

      Затем трейдер может управлять ордерами, как описано в разделе "Ручное управление ордерами".

      • 1. Set SL/TP All Orders (установить стоп-лосс/тейк-профит для всех ордеров)
      • 2. Close All Orders (закрыть все ордера)
      • 3. Close All Profits (закрыть все прибыльные ордера)


      При нажатии на C отобразится кнопка панели с 30 именами символов или пар, и трейдеры смогут щелкнуть по одному из названий пар или символов.
      При нажатии на любую из них символ графика будет немедленно заменен на тот, что указан на нажатой кнопке.

      Expert_manual_button_02


      При нажатии на R мультивалютный советник TriangularMA_MTF_MCEA удаляется с графика, поэтому трейдерам не нужно отключать советников вручную.



      Тестер стратегий

      Как известно, тестер стратеггий терминала MetaTrader 5 поддерживает и позволяет тестировать стратегии, торговать на нескольких символах или тестировать автоматическую торговлю для всех доступных символов и на всех доступных таймфреймах.

      Протестируем мультивалютный и мультитаймфреймовый советник TriangularMA_MTF_MCEA на одном и нескольких таймфреймах в тестере стратегий MetaTrader 5.

      1. Тест TriangularMA_MTF_MCEA на нескольких таймфреймах.

      st-mtf/p>


      st-mtf-result


      2. Тест TriangularMA_MTF_MCEA на одном таймфрейме.

      st-stf


      st-stf-result



      Заключение

      Вывод по итогам создания мультивалютного и мультитаймфреймового советника для работы с одним и несколькими таймфреймами с использованием MQL5 можно сделать следующий:

      • Создание мультивалютного советника на MQL5 мало чем отличается от разработки одновалютного. Но для мультивалютных советников с несколькими таймфреймами процесс немного сложнее, чем для советников с одним таймфреймом.
      • Создание мультивалютного советника повысит эффективность и результативность трейдеров, поскольку трейдерам не нужно открывать много графиков.
      • Правильная торговая стратегия увеличивает вероятность получения прибыли по сравнению с использованием одновалютного советника. Убытки по одной паре будут перекрываться прибылью в других парах.
      • Мультивалютный советник TriangularMA_MTF_MCEA является всего лишь примером для изучения и развития собственных идей. 
      • Результаты тестирования в тестере стратегий по-прежнему неудовлетворительны. При реализации лучшей стратегии с более точным расчетом сигналов и лучшими таймфреймами, результат, на мой взгляд, должен быть лучше текущего.
      • По результатам тестирования TriangularMA_MTF_MCEA в тестере стратегий выясняется, что результаты на одном таймфрейме лучше, чем на нескольких.

      Примечание:
      Если у вас есть идея создания простого мультивалютного советника на основе встроенных сигналов стандартного индикатора MQL5, предложите ее в комментариях.
      Надеюсь, что статья и мультивалютный советник будут полезны трейдерам в изучении и развитии идей. Спасибо за внимание!

      Перевод с английского произведен MetaQuotes Ltd.
      Оригинальная статья: https://www.mql5.com/en/articles/13770

      Прикрепленные файлы |
      Последние комментарии | Перейти к обсуждению на форуме трейдеров (5)
      Mohammed Yousif
      Mohammed Yousif | 22 нояб. 2023 в 14:17
      Как получить доступ к мультивалютному эксперту-трейдеру
      Fernando Carreiro
      Fernando Carreiro | 22 нояб. 2023 в 15:03
      @Mohammed Yousif #: Как получить доступ к мультивалютному эксперту-трейдеру

      Прочитав статью, изучив ее и загрузив пример кода в конце.

      Usman Akram
      Usman Akram | 7 дек. 2023 в 07:37
      Fernando Carreiro #:

      Прочитав статью, изучив ее и скачав пример кода в конце.

      Подскажите, пожалуйста, где можно скачать пример кода
      Roberto Jacobs
      Roberto Jacobs | 7 дек. 2023 в 11:15
      Usman Akram #:
      Подскажите, пожалуйста, где можно скачать пример кода

      Как объяснил модератор Фернандо Каррейро, посмотрите в самый низ статьи с надписью Прикрепленные файлы и щелкните по имени файла.

      Aleksandr Slavskii
      Aleksandr Slavskii | 24 мар. 2024 в 04:54
      Usman Akram #:
      Подскажите, пожалуйста, где можно скачать пример кода
      Скачать можно только на компьютере, если вы читаете статью на телефоне, то файл советника будет невидим.
      Нейросети — это просто (Часть 82): Модели Обыкновенных Дифференциальных Уравнений (NeuralODE) Нейросети — это просто (Часть 82): Модели Обыкновенных Дифференциальных Уравнений (NeuralODE)
      В данной статье я предлагаю познакомиться Вас с еще одним типом моделей, которые направлены на изучение динамики состояния окружающей среды.
      Разрабатываем мультивалютный советник (Часть 5): Переменный размер позиций Разрабатываем мультивалютный советник (Часть 5): Переменный размер позиций
      В предыдущих частях разрабатываемый советник имел возможность использовать только фиксированный размер позиций для торговли. Это допустимо для тестирования, но нежелательно при торговле на реальном счёте. Давайте обеспечим возможность торговли с переменным размером позиций.
      Риск-менеджер для ручной торговли Риск-менеджер для ручной торговли
      В данной статье мы подробно раскроем написание класса риск-менеджера для ручной торговли с нуля. Также данный класс может быть использован как базовый класс для наследования трейдерам, которые торгуют алгоритмически.
      Шаблоны проектирования в MQL5 (Часть 2): Структурные шаблоны Шаблоны проектирования в MQL5 (Часть 2): Структурные шаблоны
      В этой статье мы продолжим изучать шаблоны проектирования, которые позволяют разработчикам создавать расширяемые и надежные приложений не только на MQL5, но и на других языках программирования. В этот раз мы поговорим о другом типе — о структурных шаблонах. Будем учиться проектировать системы, используя имеющиеся классы для формирования более крупных структур.