English 中文 Español Deutsch 日本語 Português
preview
Создаем простой мультивалютный советник с использованием MQL5 (Часть 2): Сигналы индикатора - мультитаймфреймовый Parabolic SAR

Создаем простой мультивалютный советник с использованием MQL5 (Часть 2): Сигналы индикатора - мультитаймфреймовый Parabolic SAR

MetaTrader 5Примеры | 9 февраля 2024, 12:56
887 0
Roberto Jacobs
Roberto Jacobs

Введение

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

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

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



Особенности

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 pairs

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

Всего 30 пар.

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


2. Сигнальные индикаторы.

Мультивалютный советник будет использовать 1 сигнал индикатора на 5 таймфреймах, начиная с PERIOD_M15, PERIOD_M30, PERIOD_H1, PERIOD_H4 и PERIOD_D1.

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

Это означает, что советник FXSAR_MTF_MCEA можно использовать на любом таймфрейме от PERIOD_M1 до PERIOD_MN1, а FXSAR_MTF_MCEA по-прежнему будет рассчитывать сигналы на основе iSAR PERIOD_M15, PERIOD_M30, PERIOD_H1, PERIOD_H4 и PERIOD_D1.

Эти пять таймфреймов Parabolic SAR будут определять сигнал для открытия ордеров.

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

Чтобы использовать трейлинг-стоп и трейлинг-профит, используем iSAR PERIOD_H1.


Формула стратегии состояния сигналов iSAR:

UP (вверх)   = (PRICE_LOW[0] больше линии iSAR) или PRICE_LOW[0] > iSAR[0]

DOWN (вниз) = (PRICE-HIGH[0] меньше линии iSAR) или PRICE-HIGH[0] < iSAR[0]

Где получить сигнал на ПОКУПКУ или ПРОДАЖУ:

Пять таймфреймов индикатора iSAR должны в сумме составлять 5 x UP для ПОКУПКИ и 5 x DOWN для ПРОДАЖИ.

На рисунке 1 показан индикатор iSAR.

iSAR_Signal_Buy и Sell


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) трейлинг-стоп выполняется советником с использованием значения Parabolic SAR PERIOD_H1, одновременно получая скользящую прибыль на основе значения переменной TPmin (значение скользящей прибыли). При Use Automatic Trailing (No) трейлинг-стоп выполняется советником с использованием значения входного параметра.
Примечание: Советник осуществляет трейлинг тейк-профита одновременно с трейлинг-стопом.


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. Управление ордерами и графики символов.

Очень полезной функцией для мультивалютных советников, торгующих 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;
//---


Перечисление YN используется для опций (Yes) или (No) в параметрах советника.

enum YN
 {
   No,
   Yes
 };


Перечисление для использования размера лота в управлении капиталом

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


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

//---
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
//--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 = 2023102;          // Expert ID (Magic Number)
//---


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

//+------------------------------------------------------------------+
//| 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;
    int              posCur1,
                     posCur2;        
    //--
    double           LotPS;
    double           slv,
                     tpv,
                     pip,
                     xpip;
    double           differ;                 
    double           floatprofit,
                     fixclprofit;
    //--
    string           pairs,
                     hariini,
                     daytrade,
                     trade_mode;
    //--
    double           OPEN[],
                     HIGH[],
                     LOW[],
                     CLOSE[];
    datetime         TIME[];
    datetime         closetime;
     
    //------------
    int              DirectionMove(const string symbol);
    int              GetPSARSignalMTF(string symbol);
    int              PARSAR05(const string symbol);
    int              PARSARMTF(const string symbol,ENUM_TIMEFRAMES mtf);
    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:
    
    //-- FXSAR_MTF_MCEA Config --
    string           DIRI[],
                     AS30[];
    string           expname;
    int              hPar05[];   // Handle for the iSAR indicator for M5 Timeframe
    int              hPSAR[][5]; // Handle Indicator, where each Symbol has 5 arrays for Timeframe starting from TF_M15 to TF_D1
    int              ALO,
                     dgts,
                     arrsar,
                     arrsymbx;
    int              sall,
                     arper;
    ulong            slip;        
    //--
    double           SARstep,
                     SARmaxi;
    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,
                     TFT05,
                     TFSAR[];
    //--
    bool             PanelExtra;
    //------------
                     MCEA(void);
                     ~MCEA(void);            
    //------------
    virtual void     FXSAR_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              TFIndexArray(ENUM_TIMEFRAMES TF);
    int              GetOpenPosition(const string symbol);
    int              GetCloseInWeakSignal(const string symbol,int exis);
    int              ThisTime(const int reqmode);
    //--
    string           getUninitReasonText(int reasonCode);
    //------------
//---
  }; //-end class MCEA


Самая первая и главная функция в работе мультивалютного советника, вызываемая из OnInit(), - это FXSAR_MTF_MCEA_Config().

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(void)
  {
//---
   mc.FXSAR_MTF_MCEA_Config();
   //--
   return(INIT_SUCCEEDED);
//---
  } //-end OnInit()


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

//+------------------------------------------------------------------+
//| Expert Configuration                                             |
//+------------------------------------------------------------------+
void MCEA::FXSAR_MTF_MCEA_Config(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
    //--
    sall=ArraySize(All30);
    ArrayResize(AS30,sall,sall);
    ArrayCopy(AS30,All30,0,0,WHOLE_ARRAY);
    //--
    arrsymbx=sall;
    ArraySymbolResize();
    ArrayCopy(DIRI,All30,0,0,WHOLE_ARRAY);
    for(int x=0; x<arrsymbx; x++) {SymbolSelect(DIRI[x],true);}
    pairs="Multi Currency 30 Pairs";
    //--
    TFT05=PERIOD_M5;
    ENUM_TIMEFRAMES TFA[]={PERIOD_M15,PERIOD_M30,PERIOD_H1,PERIOD_H4,PERIOD_D1};
    TFArrays=ArraySize(TFA);
    ArrayResize(TFSAR,TFArrays,TFArrays);
    ArrayCopy(TFSAR,TFA,0,0,WHOLE_ARRAY);
    //--
    TFt=TFSAR[2];
    //--
    //-- iSAR Indicators handle for all symbol
    for(int x=0; x<arrsymbx; x++) 
      {
        hPar05[x]=iSAR(DIRI[x],TFT05,SARstep,SARmaxi);  //-- Handle for the iSAR indicator for M5 Timeframe
        //--
        for(int i=0; i<TFArrays; i++)
          {
            hPSAR[x][i]=iSAR(DIRI[x],TFSAR[i],SARstep,SARmaxi); // Handle for iSAR Indicator array sequence of the requested timeframe
          }
      }
    //--
    ALO=(int)mc_account.LimitOrders()>arrsymbx ? arrsymbx : (int)mc_account.LimitOrders();
    //--
    LotPS=(double)ALO;
    //--
    mc_trade.SetExpertMagicNumber(magicEA);
    mc_trade.SetDeviationInPoints(slip);
    mc_trade.SetMarginMode();
    //--
    return;
//---
  } //-end FXSAR_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.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()


3. Получение торговых сигналов для открытия/закрытия позиции

Чтобы получить сигнал индикатора, вызовем функцию GetOpenPosition(symbol) для получения сигнала на открытие.

int MCEA::GetOpenPosition(const string symbol) // Signal Open Position 
  {
//---
    int ret=0;
    int rise=1,
        down=-1;
    //--
    int dirmov=DirectionMove(symbol);
    int parsOp=GetPSARSignalMTF(symbol);
    //--
    if(parsOp==rise && dirmov==rise) ret=rise;
    if(parsOp==down && dirmov==down) ret=down;
    //--
    return(ret);
//---
  } //-end GetOpenPosition()

Функция GetOpenPosition() вызовет две сигнальные функции и сохранит их в переменной OpOr[].

1. DirectionMove(symbol);         //-- Функция проверки наличия цены на свечном баре на таймфрейме советника.
2. GetPSARSignalMTF(symbol);   //-- Функция расчета формулы Parabolic iSAR на запрошенном таймфрейме.
int MCEA::GetPSARSignalMTF(string symbol) // iSAR MTF signal calculation
  {
//---
    int mv=0;
    int rise=1,
        down=-1;
    //--
    int sarup=0,
        sardw=0;
    //--    
    for(int x=0; x<TFArrays; x++) // The TFArrays variable has a value of 5 which is taken from the number of time frames from TF_M1 to TF_H1.
      {
        if(PARSARMTF(symbol,TFSAR[x])>0) sarup++;
        if(PARSARMTF(symbol,TFSAR[x])<0) sardw++;
      }   
    //--
    if(sarup==TFArrays) mv=rise;
    if(sardw==TFArrays) mv=down;
    //--
    return(mv);
//---
  } //- end GetPSARSignalMTF()


Функция GetPSARSignalMTF() вызовет функцию PARSARMTF(), которая вычисляет сигнал iSAR в соответствии с запрошенным таймфреймом.

Как видите, внутри функции PARSARMTF() мы используем и вызываем две функции:

1. int xx= PairsIdxArray(symbol)

2. int tx=TFIndexArray(mtf).

Функция PairsIdxArray() используется для получения имени запрошенного символа, а функция TFIndexArray() — для получения последовательности массива запрошенного таймфрейма.

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

int MCEA::PARSARMTF(const string symbol,ENUM_TIMEFRAMES mtf) // formula Parabolic iSAR on the requested Timeframe
  {
//---
    int ret=0;
    int rise=1,
        down=-1;
    //--
    int br=2;
    //--
    double PSAR[];
    ArrayResize(PSAR,br,br);
    ArraySetAsSeries(PSAR,true);
    int xx=PairsIdxArray(symbol);
    int tx=TFIndexArray(mtf);
    CopyBuffer(hPSAR[xx][tx],0,0,br,PSAR);
    //--
    double OPN0=iOpen(symbol,TFSAR[tx],0);
    double HIG0=iHigh(symbol,TFSAR[tx],0);
    double LOW0=iLow(symbol,TFSAR[tx],0);
    double CLS0=iClose(symbol,TFSAR[tx],0);
    //--
    if(PSAR[0]<LOW0 && CLS0>OPN0) ret=rise;
    if(PSAR[0]>HIG0 && CLS0<OPN0) ret=down;
    //--
    return(ret);
//---
  } //-end PARSARMTF()


int MCEA::PairsIdxArray(const string symbol)
  {
//---
    int pidx=0;
    //--
    for(int x=0; x<arrsymbx; x++)
      {
        if(DIRI[x]==symbol)
          {
            pidx=x;
            break;
          }
      } 
    //--
    return(pidx);
//---
  } //-end PairsIdxArray()

int MCEA::TFIndexArray(ENUM_TIMEFRAMES TF)
  {
//---
    int res=-1;
    //--
    for(int x=0; x<TFArrays; x++)
      {
        if(TF==TFSAR[x])
          {
            res=x;
            break;
          }
      }
    //--
    return(res);
//---
  } //-end TFIndexArray() 


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.PairsIdxArray(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()


Если свойство советника Display Trading Info on Chart равно Yes, на графике, на котором размещен советник, будет отображаться торговая информация путем вызова функции TradeInfo().

void MCEA::TradeInfo(void) // function: write comments on the chart
  {
//----
   Pips(Symbol());
   double spread=SymbolInfoInteger(Symbol(),SYMBOL_SPREAD)/xpip;
   //--
   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      :  "+ EnumToString(TFt)+
      "\n      :: Today Trading   :  "+ TradingDay()+" : "+hariini+
      "\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()  


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

FXSAR_MTF_MCEA_look


Как видите, под именем советника FXSAR_MTF_MCEA есть кнопки M, C и R.

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

MCR_Combine

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

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

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

3. Close All Profits (закрыть все прибыльные ордера)

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

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



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

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

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




Заключение

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

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


Примечания:

Если у вас есть идея создания простого мультивалютного советника на основе встроенных сигналов стандартного индикатора MQL5, предложите ее в комментариях.

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

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

Прикрепленные файлы |
FXSAR_MTF_MCEA.mq5 (80.52 KB)
Балансировка риска при одновременной торговле нескольких торговых инструментов Балансировка риска при одновременной торговле нескольких торговых инструментов
Данная статья позволит новичку с нуля написать реализацию скрипта для балансировки рисков при одновременной торговле нескольких торговых инструментов, а опытным пользователям возможно даст новые идеи для реализации своих решений в части предложенных вариантов в данной статье.
Теория категорий в MQL5 (Часть 22): Другой взгляд на скользящие средние Теория категорий в MQL5 (Часть 22): Другой взгляд на скользящие средние
В этой статье мы попытаемся упростить описание концепций, рассматриваемых в этой серии, остановившись только на одном индикаторе - наиболее распространенном и, вероятно, самом легком для понимания. Речь идет о скользящей средней. Также мы рассмотрим значение и возможные применения вертикальных естественных преобразований.
Нейросети — это просто (Часть 76): Изучение разнообразных режимов взаимодействия (Multi-future Transformer) Нейросети — это просто (Часть 76): Изучение разнообразных режимов взаимодействия (Multi-future Transformer)
В данной статье мы продолжаем тему прогнозирования предстоящего ценового движения. И предлагаю Вам познакомиться с архитектурой Multi-future Transformer. Основная идея которого заключается в разложении мультимодального распределение будущего на несколько унимодальных распределений, что позволяет эффективно моделировать разнообразные модели взаимодействия между агентами на сцене.
Разрабатываем мультивалютный советник (Часть 2): Переход к виртуальным позициям торговых стратегий Разрабатываем мультивалютный советник (Часть 2): Переход к виртуальным позициям торговых стратегий
Продолжим разработку мультивалютного советника с несколькими параллельно работающими стратегиями. Попробуем перенести всю работу, связанную с открытием рыночных позиций с уровня стратегий на уровень эксперта, управляющего стратегиями. Сами стратегии будут торговать только виртуально, не открывая рыночных позиций.