English Русский Español Deutsch 日本語 Português
preview
如何利用 MQL5 创建简单的多币种智能交易系统(第 6 部分):两条 RSI 指标相互交叉

如何利用 MQL5 创建简单的多币种智能交易系统(第 6 部分):两条 RSI 指标相互交叉

MetaTrader 5示例 | 17 十月 2024, 17:03
101 0
Roberto Jacobs
Roberto Jacobs

概述

多货币智能系统是一款智能交易系统或交易机器人,可以自一个品种图表中交易(开单、平单和管理订单,例如:尾随止损和尾随止盈)超过多于一个品种对,在本文中,智能系统能交易 30 对。
在本文中,我们将使用两个 RSI 指标伴以交叉信号,快速 RSI 与慢速 RSI 交叉。

正如在之前的文章中所证明的那样,我们都知道,借助 MQL5 提供的强劲能力和设施,无论是在交易终端还是在策略测试器中,多货币交易已经成为可能。

为了满足交易者想要高效和有效交易机器人的重要需求,如此依托非常可靠的 MQL5 提供的强劲能力和设施,我们可以想到各种思路和策略来创建一款简单的多货币智能系统,在本文中,我们将使用两条 RSI 指标线彼此相交。


计划和功能


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 对。

对于名称含有前缀和/或后缀的品种或货币对,对于本文中的智能交易系统,我调用该函数自动处理含有前缀和/或后缀的品种名称,如此这般,当在含有该类特殊品种名称的经纪商上使用 EA 时,也能一切顺利。
但是检测含有前缀和后缀的品种名称的函数仅适用于 MetaTrader 5 中的外汇和贵金属品种对名称,不适用于特殊品种和指数。

关于我上一篇文章中的多币种智能系统,有一些交易者询问如何将多币种 EA 用作单一货币 EA 或单立 EA。

其实,在上一篇文章的智能系统中,有一个工具或选项,可令该 EA 仅针对单一货币进行交易,或作为单立的 EA 运作。

这次,在 EA 交易中,我们仍然选用 10 种将要交易的货币对。将要交易的 10 个选项对之一是 “交易者期望对”,其中要交易的对必须由交易者在智能系统输入属性中手工录入。不过,您必须始终记住,您录入的对名称必须已经在 30 对列表之中。

这个“交易者的期望对”选项实际上可令智能系统只针对单一货币进行交易,或作为一个单立的 EA 运作,只需输入一个所需的货币对名称,然后智能系将只针对该货币对交易或处理。

智能系统录入参数必须按照下图所示设置。

单立-twp

在上面的输入属性示例中,交易者仅输入 XAUUSD 对的名称,那么在这种情况下,智能交易系统将仅针对 XAUUSD 对进行交易。无论智能系统置于何处,虽有 30 对可用,但智能系统仅针对 XAUUSD 对进行交易。

除此之外,在本文的智能系统中,我添加了一个选项来选择交易对条件,是进行单一货币交易、还是多货币交易。

EA 输入参数需要如下图所示设置。

交易对选项

单立-sp

在 “SP” 或单一对选项中,智能系统仅基于放置智能系统的货币对上进行交易。例如,如果智能系统被放置在 EURUSD 对上,则其将只基于 EURUSD 对上进行交易。

故此,在本文中的智能系统中,有两种方法可以交易单一货币,或作为单立的智能系统运作。

1. 坚持使用多对或 “MP” 选项,并选择交易者所需的对选项,但仅输入一个对名称,例如 XAUUSD。
在该选项中,无论将智能系统放置在哪个货币对上,其都仅基于 "Trader Wishes Pairs" 中输入的货币对名称进行交易。

2. 在选择交易对模式中,选择 “SP” 或单对。
如果智能系统被放置在 EURUSD 对上,则其仅基于 EURUSD 对进行交易。

进而,在 “Trade on Specific Time” 组中,为那些打算在该时区进行交易的交易者提供了选项。也许很多交易者都想根据时区进行交易,所以打算交易的货币对可以与交易时段的时间相对应,如此在这个智能系统中,我们仍然可用交易时段(时区)的选项。


2. 信号指标。

相对强弱指数(RSI)由 J. Welles Wilder 开发,并发表在 1978 年的《技术交易系统的新概念》一书当中,以及 1978 年 6 月号的《商品》杂志(现为《现代交易者》)当中。它已成为最流行的振荡器指数之一。

相对强弱指数或 RSI 是金融市场分析中所用的技术指标。它旨在根据最近交易区间的收盘价绘制股票或市场的当前和历史强弱图表。

相对强弱指数技术指标或 RSI 是一个价格跟踪振荡器,范围在 0 到 100 之间。当 Wilder 引入相对强弱指数时,他建议采用 14-周期的 RSI。从那时起,9-周期和 25-周期的相对强弱指数指标也越来越普及。

RSI 最常用在 14-天时间帧,以 0 到 100 的等级衡量,高位和低位分别标记为 70 和 30。较短或较长的时间帧则用于轮替短线及长线的前景。高位和低位 — 80 和 20;或 90 和 10 — 出现的频率较低,但表明走势更强劲。

进而,在技术分析中,MetaTrader 5 把 RSI 信号定位于图表分析:

  • 顶和底
  • 图表形成
  • 失效摇摆(支撑或阻力突破)
  • 支撑和阻力位
  • 背离

故此,RSI 交易策略有太多的变体。

甚至一位分析师和投资者在他的文章的问答里,是这样回答这个问题:

“日间交易的最佳 RSI 设置是什么?

不幸的是,RSI 在日间柱线上效果最好。我们利用日内数据进行了大量回溯测试,但它并不是特别实用。”

“您如何配合 RSI 进行交易?

首先,我们首选使用日间柱线。其次,我们更喜欢在设置中采用较短的天数,首选最大 5 天。第三,RSI 作用于股票最佳,意味着资产回归依靠隔夜优势。我们在外汇方面未能成功。”

不过,在本文中,我将使用来自快速 RSI 穿越慢速 RSI,或 RSI 穿越 RSI 的信号进行外汇交易。无论它是否成功,这一切都仍然需要实验和测试。

图例 1 和图例 2 是快速 RSI 信号穿过慢速 RSI 线的描绘。

图例 1
RSIxRSI_signal_00

图例 2
RSIcross_variation


3. 交易和订单管理

使用该多币种智能系统,可有若干种方式管理您的交易:

3.1. 止损单

选项:使用订单止损(是)或(否)

  • 如果选中“使用订单止损(否)”选项,则所有订单在开单时都不带止损。
  • 如果选项“使用订单止损(是)”:再次给出选项:使用自动计算止损(是)或(否)
  • 如果选项是“自动计算止损(是)”,则将由智能系统自动执行止损计算。
  • 如果选项“自动计算止损(否)”,则交易者必须以点数为单位输入止损值。
  • 如果选项“使用订单止损(否)”:则智能系统将检查每笔开单,信号条件是否仍然良好,订单是否可维持盈利;或信号疲软,需要平单以保障盈利;或信号条件已逆转方向,订单必须以亏损条件了结。
注意:特别是对于因信号疲软而了结交易并保障盈利,会给出一个选项,是否激活它。

  • 如果它没有被激活(否),即使信号已经疲软,订单仍将持有、或不会了结以保障盈利。
  • 如果激活(Yes),则快速 RSI 和慢速 RSI 指标的条件为:

 

对于多头订单平仓: 

当快速 RSI 高于慢速 RSI,并且当前柱线上的快速 RSI 值小于前一根柱线上的快速 RSI 值时,多头订单将被平仓。


对于空头订单平仓:

当快速 RSI 低于慢速 RSI,并且当前柱线上的快速 RSI 值大于前一根柱线上的快速 RSI 值时,空头订单将被关闭。

设置止损单的代码如下:

double MCEA::OrderSLSet(const string xsymb,ENUM_ORDER_TYPE type,double atprice)
  {
//---
    slv=0.0;
    int x=PairsIdxArray(xsymb);
    Pips(xsymb);
    RefreshTick(xsymb);
    //--
    switch(type) 
      { 
       case (ORDER_TYPE_BUY):
         {
           if(use_sl==Yes && autosl==Yes) slv=mc_symbol.NormalizePrice(atprice-38*pip);
           else
           if(use_sl==Yes && autosl==No)  slv=mc_symbol.NormalizePrice(atprice-SLval*pip);
           else slv=0.0;
           //--
           break;
         }
       case (ORDER_TYPE_SELL):
         {
           if(use_sl==Yes && autosl==Yes) slv=mc_symbol.NormalizePrice(atprice+38*pip);
           else
           if(use_sl==Yes && autosl==No)  slv=mc_symbol.NormalizePrice(atprice+SLval*pip);
           else slv=0.0;
         }
      }
    //---
    return(slv);
//---
  } //-end OrderSLSet()
//---------//

因信号疲软而平仓并保障盈利的代码如下:

int MCEA::GetCloseInWeakSignal(const string symbol,int exis) // Signal Indicator Position Close in profit
  {
//---
    int ret=0;
    int rise=1,
        down=-1;
    int bar=3;
    //--
    double rdif=rsidiff;
    double RSIFast[],
           RSISlow[];
    //--
    ArrayResize(RSIFast,bar,bar);
    ArrayResize(RSISlow,bar,bar);
    ArraySetAsSeries(RSIFast,true);
    ArraySetAsSeries(RSISlow,true);
    //--
    int x=PairsIdxArray(symbol);
    UpdatePrice(symbol,TFt);
    //--
    CopyBuffer(hRSIFast[x],0,0,bar,RSIFast);
    CopyBuffer(hRSISlow[x],0,0,bar,RSISlow);
    //--
    if(exis==down && RSIFast[1]<=RSISlow[1] && RSIFast[1]<RSIFast[2] && RSIFast[0]>RSIFast[1]+rdif) ret=rise;
    if(exis==rise && RSIFast[1]>=RSISlow[1] && RSIFast[1]>RSIFast[2] && RSIFast[0]<RSIFast[1]-rdif) ret=down;
    //--
    return(ret);
//---
  } //-end GetCloseInWeakSignal()
//---------//


2. 止盈单。

选项:“使用订单止盈(是)或(否)”

  • 如果选中“使用订单止盈(否)”选项,则在开单时,所有订单都不带止盈。
  • 如果选项是“使用订单止盈“(是):再次给出选项:使用自动计算订单止盈(是)或(否)
  • 如果选项“自动计算订单止盈(是)”,则由智能系统自动执行止盈计算。
  • 如果选项“自动计算订单止盈(否)“,则交易者必须以点数输入订单止盈值。

设置止盈订单的代码如下:

double MCEA::OrderTPSet(const string xsymb,ENUM_ORDER_TYPE type,double atprice)
  {
//---
    tpv=0.0;
    int x=PairsIdxArray(xsymb);
    Pips(xsymb);
    RefreshTick(xsymb);
    //--
    switch(type) 
      { 
       case (ORDER_TYPE_BUY):
         {
           if(use_tp==Yes && autotp==Yes) tpv=mc_symbol.NormalizePrice(atprice+50*pip);
           else
           if(use_tp==Yes && autotp==No)  tpv=mc_symbol.NormalizePrice(atprice+TPval*pip);
           else tpv=0.0;
           //--
           break;
         }
       case (ORDER_TYPE_SELL):
         {
           if(use_tp==Yes && autotp==Yes) tpv=mc_symbol.NormalizePrice(atprice-50*pip);
           else
           if(use_tp==Yes && autotp==No)  tpv=mc_symbol.NormalizePrice(atprice-TPval*pip);
           else tpv=0.0;
         }
      }
    //---
    return(tpv);
//---
  } //-end OrderTPSet()
//---------//

3. 尾随止损和尾随止盈

选项:“使用尾随止损/止盈(是)或(否)”

  • 如果”使用尾随止损/止盈(否)“选项,则智能系统不会执行尾随止损和尾随止盈。
  • 如果选项“使用追踪止损/止盈(是)”,交易者可以在 2 个选项之间进行选择:

1. 按价格尾随。
尾随止损将由 EA 按价格走势和输入属性中的值来执行,同时基于 TPmin(最小尾随盈利值)变量值执行尾随止盈。

2. 按指标尾随。
尾随止损将由 EA 利用 VIDYA 指标执行,同时基于 TPmin(最小尾随盈利值)变量值执行尾随止盈。

注意: EA 将在尾随止损的同时执行尾随止盈。

根据我的研究和实验,与抛物线 SAR,或移动平均线指标的几种变体相比,VIDYA 指标略好,非常适合尾随止损。

与抛物线 SAR 指标相比,VIDYA 指标更接近价格走势,而与 AMA、DEMA 和 MA 指标相比,VIDYA 指标离价格走势更远。

故此,在本文中,我决定将 VIDYA 指标作为尾随止损函数的基准指标。

尾随止损价和指标函数的代码:

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 VIDyAv[];
            ArrayResize(VIDyAv,br,br);
            ArraySetAsSeries(VIDyAv,true);
            CopyBuffer(hVIDyAv[x],0,0,br,VIDyAv);
            RefreshPrice(xsymb,TFt,br);
            //--
            if(ptype==POSITION_TYPE_BUY  && (VIDyAv[0]<mc_symbol.NormalizePrice(mc_symbol.Bid()-TSval*pip)))
               pval=VIDyAv[0];
            if(ptype==POSITION_TYPE_SELL && (VIDyAv[0]>mc_symbol.NormalizePrice(mc_symbol.Ask()+TSval*pip)))
               pval=VIDyAv[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=(Close_by_Opps==No && TS_type==1) ? 0 : 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-1.0)*pip));
               double modbuysl=vtrsb;
               double modbuytp=mc_symbol.NormalizePrice(price+TPval*pip);
               bool modbuy = (price>modminsl && modbuysl>modstart && (pos_stop==0.0||modbuysl>pos_stop));
               //--
               if(modbuy && netp>minprofit)
                 {
                   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+1.0)*pip));
               double modselsl=vtrss;
               double modseltp=mc_symbol.NormalizePrice(price-TPval*pip);
               bool modsel = (price<modminsl && modselsl<modstart && (pos_stop==0.0||modselsl<pos_stop)); 
               //--
               if(modsel && netp>minprofit)
                 {
                   modist=mc_trade.PositionModify(symbol,modselsl,modseltp);
                 }  
             }
         }
     }
    //--
    return(modist);
//---
  } //-end ModifySLTP()
//---------//


4. 手工订单管理。

在这个多币种智能系统中,添加了几个手工按钮点击,为交易者提供高效和有效手段,监控智能系统的运作。

4.1. 为所有订单设置止损/止盈:
如果交易者输入了参数集合“使用订单止损(否)和/或使用订单止盈(否)”,但随后交易者想在所有订单上使用止损或止盈,那么只需单击“所有订单设置止损/止盈”按钮,所有订单将被修改,并应用止损和/或止盈。

4.2. 所有订单平仓:
如果交易者希望所有订单平仓,只需单击“所有订单平仓”按钮即可把所有持单了结。

4.3. 所有盈利订单平仓:

如果交易者想要把所有已经盈利的订单了结,只需单击 “所有盈利订单平仓” 按钮即可把所有已经盈利的持单了结。


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

所用时区的枚举

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

选择 10 个要交易选项对的枚举

//--
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 枚举用于智能系统属性中的(是)或(否)选项。

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

资金管理手数的枚举

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

选择计算信号指标时间帧的枚举

//--
enum TFUSE
  {
   TFM5,     // 00_PERIOD_M5
   TFM15,    // 01_PERIOD_M15
   TFM30,    // 02_PERIOD_M30
   TFH1,     // 03_PERIOD_H1
   TFH2,     // 04_PERIOD_H2
   TFH3,     // 05_PERIOD_H3
   TFH4,     // 06_PERIOD_H4
   TFH6,     // 07_PERIOD_H6
   TFH8,     // 08_PERIOD_H8
   TFH12,    // 09_PERIOD_H12
   TFD1      // 10_PERIOD_D1
  };
//--

配以 TFUSE 枚举,我把计算智能交易时间帧的限制在仅从 TF-M5 到 TF-D1。

在尾随止损计算中选择要用的类型枚举

//--
enum TrType
  {
    byprice, // Trailing Stop by Price
    byindi   // Trailing Stop by Indicator
  };
//--

枚举是为选择智能系统的交易类型,单一货币或多货币。

//--
enum MS
 {
   SP, // Single Pair
   MP  // Multi Pairs
 };
//--

智能系统输入属性

//---
input group               "=== Global Strategy EA Parameter ==="; // Global Strategy EA Parameter
input TFUSE               tfinuse = TFH4;             // Select Expert TimeFrame, default PERIOD_H4
input int                 rsifast = 10;               // Input Period for Fast RSI
input ENUM_APPLIED_PRICE  frsiapp = PRICE_WEIGHTED;   // Select Fast RSI Applied Price
input int                 rsislow = 30;               // Input Period for Slow RSI
input ENUM_APPLIED_PRICE  srsiapp = PRICE_WEIGHTED;   // Select Slow RSI Applied Price
input double              rsidiff = 4.56;             // Input Differentiation between RSIs
//---
input group               "=== Select Pairs to Trade ===";  // Selected Pairs to trading
input MS                trademode = MP;              // Select Trading Pairs Mode (Multi or Single)
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 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.0;             // 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 = 60.0;             // If Not Use Automatic TP - Input TP value in Pips
input YN            TrailingSLTP = Yes;              // Use Trailing SL/TP (Yes) or (No)
input TrType               trlby = byindi;           // Select Trailing Stop Type
input double               TSval = 10.0;             // If Use Trailing Stop by Price Input value in Pips
input double               TSmin = 5.0;              // Minimum Pips to start Trailing Stop
input double               TPmin = 25.0;             // 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 = 20240111;         // Expert ID (Magic Number)
//---
//---------//

注意:如果输入属性 "Expert ID (Magic Number)” 留空,则智能系统就能够管理手工开单。

在 EA 全局策略输入属性组中,指导交易者为计算指标信号选择时间帧,并输入参数:

  1. 输入快速 RSI 的周期,及所应用的价格
  2. 输入慢速 RSI 的周期,及所应用的价格
  3. 输入 RSI 之间的差值

在智能系统的 “Select Pairs to Trade” 属性组中,交易者需要从提供的 10 个选项中选择要交易的货币对;默认情况下,设置为所有外汇 30 对。

为了配置要交易的货币对,我们将调用 HandlingSymbolArrays() 函数。WithHandlingSymbolArrays() 函数,我们将处理所有将要交易的货币对。

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);
    areur=ArraySize(EURs);
    aretc=ArraySize(JPYs);
    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<areur; 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 & Metal 30 Pairs
          {
            ArrayResize(DIRI,sall,sall);
            arrsymbx=sall;
            ArraySymbolResize();
            ArrayCopy(DIRI,All30,0,0,WHOLE_ARRAY);
            pairs="Multi Currency "+string(sall)+" 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,areur,areur);
            arrsymbx=aretc;
            ArraySymbolResize();
            ArrayCopy(DIRI,EURs,0,0,WHOLE_ARRAY);
            pairs="("+string(aretc)+") Forex EUR Pairs";
            //--
            break;
          }
        case 4: // GBP pairs
          {
            ArrayResize(DIRI,aretc,aretc);
            arrsymbx=aretc;
            ArraySymbolResize();
            ArrayCopy(DIRI,GBPs,0,0,WHOLE_ARRAY);
            pairs="("+string(aretc)+") Forex GBP Pairs";
            //--
            break;
          }
        case 5: // AUD pairs
          {
            ArrayResize(DIRI,aretc,aretc);
            arrsymbx=aretc;
            ArraySymbolResize();
            ArrayCopy(DIRI,AUDs,0,0,WHOLE_ARRAY);
            pairs="("+string(aretc)+") Forex AUD Pairs";
            //--
            break;
          }
        case 6: // NZD pairs
          {
            ArrayResize(DIRI,aretc,aretc);
            arrsymbx=aretc;
            ArraySymbolResize();
            ArrayCopy(DIRI,NZDs,0,0,WHOLE_ARRAY);
            pairs="("+string(aretc)+") Forex NZD Pairs";
            //--
            break;
          }
        case 7: // CAD pairs
          {
            ArrayResize(DIRI,aretc,aretc);
            arrsymbx=aretc;
            ArraySymbolResize();
            ArrayCopy(DIRI,CADs,0,0,WHOLE_ARRAY);
            pairs="("+string(aretc)+") Forex CAD Pairs";
            //--
            break;
          }
        case 8: // CHF pairs
          {
            ArrayResize(DIRI,aretc,aretc);
            arrsymbx=aretc;
            ArraySymbolResize();
            ArrayCopy(DIRI,CHFs,0,0,WHOLE_ARRAY);
            pairs="("+string(aretc)+") Forex CHF Pairs";
            //--
            break;
          }
        case 9: // JPY pairs
          {
            ArrayResize(DIRI,aretc,aretc);
            arrsymbx=aretc;
            ArraySymbolResize();
            ArrayCopy(DIRI,JPYs,0,0,WHOLE_ARRAY);
            pairs="("+string(aretc)+") Forex JPY Pairs";
            //--
            break;
          }
      }
    //--
    return;
//---
  } //-end HandlingSymbolArrays()
//---------//

在 HandlingSymbolArrays() 函数中,我们将调用 SetSymbolNamePS() 函数。配合 SetSymbolNamePS(),我们就能够处理含有前缀和/或后缀的品种名称。

void MCEA::SetSymbolNamePS(void)
  {
//---
   int sym_Lenpre=0;
   int sym_Lensuf=0;
   string sym_pre="";
   string sym_suf="";
   SymbolSelect(Symbol(),true);
   string insymbol=Symbol();
   int inlen=StringLen(insymbol);
   int toseek=-1;
   string dep="";
   string bel="";
   string sym_use ="";
   int pairx=-1;
   string xcur[]={"EUR","GBP","AUD","NZD","USD","CAD","CHF"}; // 7 major currency
   int xcar=ArraySize(xcur);
   //--
   for(int x=0; x<xcar; x++)
     {
       toseek=StringFind(insymbol,xcur[x],0);
       if(toseek>=0)
         {
           pairx=x;
           break;
         }
     }
   if(pairx>=0)
     {
       int awl=toseek-3 <0 ? 0 : toseek-3;
       int sd=StringFind(insymbol,"SD",0);
       if(toseek==0 && sd<4)
         {
           dep=StringSubstr(insymbol,toseek,3);
           bel=StringSubstr(insymbol,toseek+3,3);
           sym_use=dep+bel;
         }
       else
       if(toseek>0)
         {
           dep=StringSubstr(insymbol,toseek,3);
           bel=StringSubstr(insymbol,toseek+3,3);
           sym_use=dep+bel;
         }
       else
         {
           dep=StringSubstr(insymbol,awl,3);
           bel=StringSubstr(insymbol,awl+3,3);
           sym_use=dep+bel;
         }
     }
   //--
   string sym_nmx=sym_use;
   int lensx=StringLen(sym_nmx);
   //--
   if(inlen>lensx && lensx==6)
     {
       sym_Lenpre=StringFind(insymbol,sym_nmx,0);
       sym_Lensuf=inlen-lensx-sym_Lenpre;
       //--
       if(sym_Lenpre>0)
         {
           sym_pre=StringSubstr(insymbol,0,sym_Lenpre);
           for(int i=0; i<xcar; i++)
             if(StringFind(sym_pre,xcur[i],0)>=0) sym_pre="";
         }
       if(sym_Lensuf>0)
         {
           sym_suf=StringSubstr(insymbol,sym_Lenpre+lensx,sym_Lensuf);
           for(int i=0; i<xcar; i++)
             if(StringFind(sym_suf,xcur[i],0)>=0) sym_suf="";
         }
     }
   //--
   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)" 中,交易者将在此处选择 “Trade on Specific Time Zone (Yes) or (No)"。

如果 "Trade on Specific Time Zone" 选项指定为 No,则智能系统会在 MT5 的 00:15 至 23:59 之间进行交易。

如果 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 Specific Time Zones(在特定时区交易)"设置为 Yes(是),并设置为 "Trading on Custom Sessions(在自定义时段交易)"。

在自定义时段进行交易:
在该时段中,交易者必须设置开始交易时间的小时和分钟,以及停止交易的小时和分钟。这意味着 EA 仅在指定的开始到结束时间段内执行活动。

意即,在新西兰交易时段到纽约美国交易时段,从交易开始到结束的时间由 EA 计算。


EA 的工作类。

为了构建和配置智能系统工作流程,我们已创建了一个类,它声明了多货币智能系统所需的所有变量、对象和函数。

//+------------------------------------------------------------------+
//| 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           point;
    double           slv,
                     tpv,
                     pip,
                     xpip;
    double           SARstep,
                     SARmaxi;
    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              GetRSIxx(const string symbol);
    int              PARSAR05(const string symbol);
    int              PARSAR15(const string symbol);
    int              LotDig(const string symbol);
    //--
    bool             CheckProfit(const string symbol,ENUM_POSITION_TYPE intype);
    bool             CheckLoss(const string symbol,ENUM_POSITION_TYPE intype);
    //--
    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:
    //---
    
    //-- RSIxRSI_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;
    //--
    int              hRSIFast[],
                     hRSISlow[];
    int              hVIDyAv[];
    int              hPar05[],
                     hPar15[];
    int              ALO,
                     dgts,
                     arrsar,
                     arrsymbx;
    int              sall,
                     arusd,
                     areur,
                     aretc,
                     arspc,
                     arper;
    ulong            slip;        
    //--
    double           profitb[],
                     profits[];
    double           minprofit;
    //--
    int              Buy,
                     Sell;
    int              ccur,
                     psec,
                     xtto,
                     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,
                     TFT15;
    //--
    bool             PanelExtra;
    //------------
                     MCEA(void);
                     ~MCEA(void);            
    //------------
    //--
    virtual void     RSIxRSI_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             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);
    bool             CheckProfitLoss(const string symbol);
    bool             CloseBuyPositions(const string symbol);
    bool             CloseSellPositions(const string symbol);
    //--
    int              PairsIdxArray(const string symbol);
    int              ValidatePairs(const string symbol);
    int              GetOpenPosition(const string symbol);
    int              GetCloseInWeakSignal(const string symbol,int exis);
    //--
    string           getUninitReasonText(int reasonCode);
    //--
    //------------
//---
  }; //-end class MCEA
//---------//
 
MCEA mc;

//---------//

多币种智能系统工作流程中第一个也是最重要的函数是从 OnInit() 调用的 RSIxRSI_MCEA_Config()。

RSIxRSI_MCEA_Config() 函数配置所有要用到的品种、所有时间帧、所有指标句柄、以及智能系统工作流程包含文件头里的一些重要函数。

RSIxRSI_MCEA_Config() 函数描述并实现如何处理时间帧,并为智能系统工作流程中用到的所有指标创建指标句柄。

//+------------------------------------------------------------------+
//| Expert Configuration                                             |
//+------------------------------------------------------------------+
void MCEA::RSIxRSI_MCEA_Config(void) 
  {
//---
    //--
    HandlingSymbolArrays(); // With this function we will handle all pairs that will be traded
    //--
    TFT05=PERIOD_M5;
    TFT15=PERIOD_M15;
    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(tfinuse==x) TFt=TFs[x]; // TF for calculation signal
    //--
    //-- Indicators handle for all symbol
    for(int x=0; x<arrsymbx; x++) 
      {
        hRSISlow[x]=iRSI(DIRI[x],TFt,rsislow,srsiapp);          //-- Handle for the Slow RSI indicator
        hRSIFast[x]=iRSI(DIRI[x],TFt,rsifast,frsiapp);          //-- Handle for the Fast RSI indicator
        hVIDyAv[x]=iVIDyA(DIRI[x],TFt,9,12,0,PRICE_WEIGHTED);   //-- Handle for the VIDYA indicator for Trailing Stop
        hPar05[x]=iSAR(DIRI[x],TFT05,SARstep,SARmaxi);          //-- Handle for the iSAR indicator for M5 Timeframe
        hPar15[x]=iSAR(DIRI[x],TFT15,SARstep,SARmaxi);          //-- Handle for the iSAR indicator for M15 Timeframe
        //--
      }
    //--
    minprofit=NormalizeDouble(TSmin/100.0,2);
    //--
    ALO=(int)mc_account.LimitOrders()>sall ? sall : (int)mc_account.LimitOrders();
    if(Close_by_Opps==No) 
      {
        if((int)mc_account.LimitOrders()>=(sall*2)) ALO=sall*2;
        else 
        ALO=(int)(mc_account.LimitOrders()/2);
      }
    //--
    LotPS=(double)ALO;
    //--
    mc_trade.SetExpertMagicNumber(magicEA);
    mc_trade.SetDeviationInPoints(slip);
    mc_trade.SetMarginMode();
    Set_Time_Zone();
    //--
    return;
//---
  } //-end RSIxRSI_MCEA_Config()
//---------//


2. 智能系统即刻报价函数

在智能系统的即刻报价函数 OnTick() 中,我们将调用多币种智能系统的最重要函数之一,即 ExpertActionTrade() 函数。EA 的整个交易过程都包含在这个函数当中。

//+------------------------------------------------------------------+
//| 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++) 
          {
            //--
            switch(trademode)
              {
                case SP:
                  {
                    if(mc.DIRI[x]!=Symbol()) continue;
                    symbol=Symbol();
                    mc.pairs=mc.pairs+" ("+symbol+")";
                    break;
                  }
                case MP:
                  {
                    if(mc.DIRI[x]==Symbol()) symbol=Symbol();
                    else symbol=mc.DIRI[x];
                    break;
                  }
              }
            //--
            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]>mc.minprofit && 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]>mc.minprofit && 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)
                  {
                    mc.ModifySLTP(symbol,trlby);
                  }
              }
            //--
            mc.CheckOpenPMx(symbol);
            if(Close_by_Opps==No && (mc.xob[x]+mc.xos[x]>1))
              {
                mc.CheckProfitLoss(symbol);
                mc.Do_Alerts(symbol,"Close order due stop in loss.");
              }
            //--
            mc.CheckClose(symbol);
          }
        //--
        mc.psec=mc.ccur;
      }
    //--
    return;
//---
  } //-end ExpertActionTrade()
//---------//

同时,”Day Trading On/Off” 属性组允许交易者在周日至周六的特定日期进行交易。这允许交易者设置(Yes)或(No)选项来启用或禁用智能系统在特定日期进行交易。

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

"Day Trading On/Off" 执行如下:

bool MCEA::TradingToday(void)
  {
//---
    bool tradetoday=false;
    int trdday=ThisTime(dow);
    hariini="No";
    //--
    int ttd[];
    ArrayResize(ttd,7);
    ttd[0]=ttd0;
    ttd[1]=ttd1;
    ttd[2]=ttd2;
    ttd[3]=ttd3;
    ttd[4]=ttd4;
    ttd[5]=ttd5;
    ttd[6]=ttd6;
    //--
    if(ttd[trdday]==Yes) {tradetoday=true; hariini="Yes";}
   //--
   return(tradetoday);
//---
  } //-end TradingToday()
//---------//

注意:“Day Trading On/Off” 条件将显示在图表上的交易信息之中。

由 TradingDay() 函数执行

string MCEA::TradingDay(void)
  {
//---
   int trdday=ThisTime(dow);
   switch(trdday)
     {
        case 0: daytrade="Sunday";    break;
        case 1: daytrade="Monday";    break;
        case 2: daytrade="Tuesday";   break;
        case 3: daytrade="Wednesday"; break;
        case 4: daytrade="Thursday";  break;
        case 5: daytrade="Friday";    break;
        case 6: daytrade="Saturday";  break;
     }
   return(daytrade);
//---
  } //-end TradingDay()  
//---------//

交易者可以在智能系统的 “Trade at Specific Time” 属性组中选择按时区进行交易。

注意:如上所述,在新西兰时段交易到美国纽约时段交易的情况下,从交易开始到结束的时间由 EA 计算。
因此,在智能交易输入属性中,交易者只需设置自定义时段交易开始时间的小时和分钟,以及交易结束时间的小时和分钟。


ExpertActionTrade() 函数已扩展,调用专门的布尔值 Trade_session() 函数进行时区交易。

如果 Trade_session() 为 true,则 EA 工作流程将继续进行,直到完成;但如果为 false,则 EA 将执行任务“Close Trade and Save Profit due to Weak Signal if it is (Yes)”,以及 “Trailing Stop if it is (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()
//---------//

在特定时段交易的工作流程如下,首先 ExpertActionTrade() 函数调用 Trade_session() 函数,然后 Trade_session() 函数调用 Set_Time_Zone() 函数,最后 Set_Time_Zone() 函数调用 Time_Zone() 函数。

void MCEA::Set_Time_Zone(void)
  {
//---
    //-- Server Time==TimeCurrent()
    datetime TTS=TimeTradeServer();
    datetime GMT=TimeGMT();
    //--
    MqlDateTime svrtm,gmttm; 
    TimeToStruct(TTS,svrtm); 
    TimeToStruct(GMT,gmttm); 
    int svrhr=svrtm.hour;  // Server time hour
    int gmthr=gmttm.hour;  // GMT time hour
    int difhr=svrhr-gmthr; // Time difference Server time to GMT time
    //--
    int NZSGMT=12;  // New Zealand Session GMT/UTC+12
    int AUSGMT=10;  // Australia Sydney Session GMT/UTC+10
    int TOKGMT=9;   // Asia Tokyo Session GMT/UTC+9
    int EURGMT=0;   // Europe London Session GMT/UTC 0
    int USNGMT=-5;  // US New York Session GMT/UTC-5
    //--
    int NZSStm=8;   // New Zealand Session time start: 08:00 Local Time
    int NZSCtm=17;  // New Zealand Session time close: 17:00 Local Time 
    int AUSStm=7;   // Australia Sydney Session time start: 07:00 Local Time 
    int AUSCtm=17;  // Australia Sydney Session time close: 17:00 Local Time  
    int TOKStm=9;   // Asia Tokyo Session time start: 09:00 Local Time 
    int TOKCtm=18;  // Asia Tokyo Session time close: 18:00 Local Time  
    int EURStm=9;   // Europe London Session time start: 09:00 Local Time 
    int EURCtm=19;  // Europe London Session time close: 19:00 Local Time  
    int USNStm=8;   // US New York Session time start: 08:00 Local Time 
    int USNCtm=17;  // US New York Session time close: 17:00 Local Time  
    //--
    int nzo = (NZSStm+difhr-NZSGMT)<0 ? 24+(NZSStm+difhr-NZSGMT) : (NZSStm+difhr-NZSGMT);
    int nzc = (NZSCtm+difhr-NZSGMT)<0 ? 24+(NZSCtm+difhr-NZSGMT) : (NZSCtm+difhr-NZSGMT);
    //--
    int auo = (AUSStm+difhr-AUSGMT)<0 ? 24+(AUSStm+difhr-AUSGMT) : (AUSStm+difhr-AUSGMT);
    int auc = (AUSCtm+difhr-AUSGMT)<0 ? 24+(AUSCtm+difhr-AUSGMT) : (AUSCtm+difhr-AUSGMT);
    //--
    int tko = (TOKStm+difhr-TOKGMT)<0 ? 24+(TOKStm+difhr-TOKGMT) : (TOKStm+difhr-TOKGMT);
    int tkc = (TOKCtm+difhr-TOKGMT)<0 ? 24+(TOKCtm+difhr-TOKGMT) : (TOKCtm+difhr-TOKGMT);
    //--
    int euo = (EURStm+difhr-EURGMT)<0 ? 24+(EURStm+difhr-EURGMT) : (EURStm+difhr-EURGMT);
    int euc = (EURCtm+difhr-EURGMT)<0 ? 24+(EURCtm+difhr-EURGMT) : (EURCtm+difhr-EURGMT);
    //--
    int uso = (USNStm+difhr-USNGMT)<0 ? 24+(USNStm+difhr-USNGMT) : (USNStm+difhr-USNGMT);
    int usc = (USNCtm+difhr-USNGMT)<0 ? 24+(USNCtm+difhr-USNGMT) : (USNCtm+difhr-USNGMT);
    if(usc==0||usc==24) usc=23;
    //--
    //---Trading on Custom Session
    int _days00=ThisTime(day);
    int _days10=ThisTime(day);
    if(stsescuh>clsescuh) _days10=ThisTime(day)+1;
    tmopcu=ReqDate(_days00,stsescuh,stsescum); 
    tmclcu=ReqDate(_days10,clsescuh,clsescum); 
    //--
    //--Trading on New Zealand Session GMT/UTC+12
    int _days01=ThisTime(hour)<nzc ? ThisTime(day)-1 : ThisTime(day);
    int _days11=ThisTime(hour)<nzc ? ThisTime(day) : ThisTime(day)+1;
    tmop01=ReqDate(_days01,nzo,0);    // start: 08:00 Local Time == 20:00 GMT/UTC
    tmcl01=ReqDate(_days11,nzc-1,59); // close: 17:00 Local Time == 05:00 GMT/UTC
    //--
    //--Trading on Australia Sydney Session GMT/UTC+10
    int _days02=ThisTime(hour)<auc ? ThisTime(day)-1 : ThisTime(day);
    int _days12=ThisTime(hour)<auc ? ThisTime(day) : ThisTime(day)+1;
    tmop02=ReqDate(_days02,auo,0);    // start: 07:00 Local Time == 21:00 GMT/UTC
    tmcl02=ReqDate(_days12,auc-1,59); // close: 17:00 Local Time == 07:00 GMT/UTC
    //--
    //--Trading on Asia Tokyo Session GMT/UTC+9
    int _days03=ThisTime(hour)<tkc ? ThisTime(day) : ThisTime(day)+1;
    int _days13=ThisTime(hour)<tkc ? ThisTime(day) : ThisTime(day)+1;
    tmop03=ReqDate(_days03,tko,0);    // start: 09:00 Local Time == 00:00 GMT/UTC
    tmcl03=ReqDate(_days13,tkc-1,59); // close: 18:00 Local Time == 09:00 GMT/UTC
    //--
    //--Trading on Europe London Session GMT/UTC 00:00
    int _days04=ThisTime(hour)<euc ? ThisTime(day) : ThisTime(day)+1;
    int _days14=ThisTime(hour)<euc ? ThisTime(day) : ThisTime(day)+1;
    tmop04=ReqDate(_days04,euo,0);     // start: 09:00 Local Time == 09:00 GMT/UTC
    tmcl04=ReqDate(_days14,euc-1,59);  // close: 19:00 Local Time == 19:00 GMT/UTC
    //--
    //--Trading on US New York Session GMT/UTC-5
    int _days05=ThisTime(hour)<usc  ? ThisTime(day) : ThisTime(day)+1;
    int _days15=ThisTime(hour)<=usc ? ThisTime(day) : ThisTime(day)+1;
    tmop05=ReqDate(_days05,uso,0);  // start: 08:00 Local Time == 13:00 GMT/UTC
    tmcl05=ReqDate(_days15,usc,59); // close: 17:00 Local Time == 22:00 GMT/UTC
    //--
    //--Not Use Trading Time Zone
    if(trd_time_zone==No)
      {
        tmopno=ReqDate(ThisTime(day),0,15); 
        tmclno=ReqDate(ThisTime(day),23,59);
      }
    //--
    Time_Zone();
    //--
    return;
//---
  } //-end Set_Time_Zone()
//---------//
void MCEA::Time_Zone(void)
  {
//---
   //--
   tz_ses="";
   //--
   switch(session)
     {
       case Cus_Session:
         {
           SesCuOp=StringToTime(tmopcu);
           SesCuCl=StringToTime(tmclcu);
           zntm=SesCuOp;
           znop=SesCuOp;
           zncl=SesCuCl;
           tz_ses="Custom_Session";
           tz_opn=timehr(stsescuh,stsescum);
           tz_cls=timehr(clsescuh,clsescum);
           break;
         }
       case New_Zealand:
         {
           Ses01Op=StringToTime(tmop01);
           Ses01Cl=StringToTime(tmcl01);
           zntm=Ses01Op;
           znop=Ses01Op;
           zncl=Ses01Cl;
           tz_ses="New_Zealand/Oceania";
           tz_opn=timehr(ReqTime(Ses01Op,hour),ReqTime(Ses01Op,min));
           tz_cls=timehr(ReqTime(Ses01Cl,hour),ReqTime(Ses01Cl,min));
           break;
         }
       case Australia:
         {
           Ses02Op=StringToTime(tmop02);
           Ses02Cl=StringToTime(tmcl02);
           zntm=Ses02Op;
           znop=Ses02Op;
           zncl=Ses02Cl;
           tz_ses="Australia Sydney";
           tz_opn=timehr(ReqTime(Ses02Op,hour),ReqTime(Ses02Op,min));
           tz_cls=timehr(ReqTime(Ses02Cl,hour),ReqTime(Ses02Cl,min));
           break;
         }
       case Asia_Tokyo:
         {
           Ses03Op=StringToTime(tmop03);
           Ses03Cl=StringToTime(tmcl03);
           zntm=Ses03Op;
           znop=Ses03Op;
           zncl=Ses03Cl;
           tz_ses="Asia/Tokyo";
           tz_opn=timehr(ReqTime(Ses03Op,hour),ReqTime(Ses03Op,min));
           tz_cls=timehr(ReqTime(Ses03Cl,hour),ReqTime(Ses03Cl,min));
           break;
         }
       case Europe_London:
         {
           Ses04Op=StringToTime(tmop04);
           Ses04Cl=StringToTime(tmcl04);
           zntm=Ses04Op;
           znop=Ses04Op;
           zncl=Ses04Cl;
           tz_ses="Europe/London";
           tz_opn=timehr(ReqTime(Ses04Op,hour),ReqTime(Ses04Op,min));
           tz_cls=timehr(ReqTime(Ses04Cl,hour),ReqTime(Ses04Cl,min));
           break;
         }
       case US_New_York:
         {
           Ses05Op=StringToTime(tmop05);
           Ses05Cl=StringToTime(tmcl05);
           zntm=Ses05Op;
           znop=Ses05Op;
           zncl=Ses05Cl;
           tz_ses="US/New_York";
           tz_opn=timehr(ReqTime(Ses05Op,hour),ReqTime(Ses05Op,min));
           tz_cls=timehr(ReqTime(Ses05Cl,hour),ReqTime(Ses05Cl,min));
           break;
         }
     }
   //--
   if(trd_time_zone==No)
     {
       SesNoOp=StringToTime(tmopno);
       SesNoCl=StringToTime(tmclno);
       zntm=SesNoOp;
       znop=SesNoOp;
       zncl=SesNoCl;
       tz_ses="Not Use Time Zone";
       tz_opn=timehr(ReqTime(SesNoOp,hour),ReqTime(SesNoOp,min));
       tz_cls=timehr(ReqTime(SesNoCl,hour),ReqTime(SesNoCl,min));
     }
   //--
   return;
//---
  } //-end Time_Zone()
//---------//


3. 如何获取开仓的交易信号?

为了获得开仓信号,ExpertActionTrade() 函数调用 GetOpenPosition() 函数。

int MCEA::GetOpenPosition(const string symbol) // Signal Open Position 
  {
//---
    int ret=0;
    int rise=1,
        down=-1;
    //--
    int rsix=GetRSIxx(symbol);
    int par15=PARSAR15(symbol);
    //--
    if(rsix==rise && par15==rise) ret=rise;
    if(rsix==down && par15==down) ret=down;
    //--
    return(ret);
//---
  } //-end GetOpenPosition()
//---------//

而 GetOpenPosition() 函数会调用 2 个函数:

  1. GetRSIxx() 函数,该函数从 2 个RSI 的缓冲区取值,并遵算法计算信号。
  2. PARSAR15() 函数作为过滤器。

int MCEA::GetRSIxx(const string symbol) // Signal Open Position 
  {
//---
    int ret=0;
    int rise=1,
        down=-1;
    int bar=3;
    //--
    double rdif=rsidiff;
    double RSIFast[],
           RSISlow[];
    //--
    ArrayResize(RSIFast,bar,bar);
    ArrayResize(RSISlow,bar,bar);
    ArraySetAsSeries(RSIFast,true);
    ArraySetAsSeries(RSISlow,true);
    //--
    int x=PairsIdxArray(symbol);
    UpdatePrice(symbol,TFt);
    //--
    CopyBuffer(hRSIFast[x],0,0,bar,RSIFast);
    CopyBuffer(hRSISlow[x],0,0,bar,RSISlow);
    //--
    if(RSIFast[1]<=RSISlow[1] && RSIFast[0]>RSISlow[0]+rdif) ret=rise;
    if(RSIFast[1]>=RSISlow[1] && RSIFast[0]<RSISlow[0]-rdif) ret=down;
    //--
    return(ret);
//---
  } //-end GetRSIxx()
//---------//        
int MCEA::PARSAR15(const string symbol) // formula Parabolic SAR M5
  {
//---
   int ret=0;
   int rise=1,
       down=-1;
   int br=2;
//--
   double PSAR[];
   ArrayResize(PSAR,br,br);
   ArraySetAsSeries(PSAR,true);
   int xx=PairsIdxArray(symbol);
   CopyBuffer(hPar15[xx],0,0,br,PSAR);
//--
   RefreshPrice(symbol,TFT15,br);
   double HIG0=iHigh(symbol,TFT15,0);
   double LOW0=iLow(symbol,TFT15,0);
//--
   if(PSAR[0]<LOW0)
      ret=rise;
   if(PSAR[0]>HIG0)
      ret=down;
//--
   return(ret);
//---
  } //-end PARSAR15()
//---------//

在 GetRSIxx() 和 PARSAR15() 函数中,我们调用 1 个函数,即 PairsIdxArray() 函数。

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

PairsIdxArray() 函数获取所请求品种的名称,及其指标句柄。然后调用相应的指标句柄,从该交易品种和时间帧中获取 RSI 指标,及 PSAR 指标的缓冲区值。

在该智能系统中,我们将用到 2 个 RSI 指标。
它们具有不同的输入参数:

快速 RSI:

  • symbol = 根据请求的符号,
  • timeframe = 如智能系统时间帧中指定值。
  • ma_period = 10,根据快速 RSI 的输入周期
  • applied_price = PRICE_WEIGHTED,根据快速 RSI 的应用价格

慢速 RSI:

  • symbol = 根据请求的符号,
  • timeframe = 如智能系统时间帧中指定值。
  • ma_period = 30,根据慢速 RSI 的输入周期
  • applied_price = PRICE_WEIGHTED,根据慢速 RSI 的应用价格

    //-- Indicators handle for all symbol
    for(int x=0; x<arrsymbx; x++) 
      {
        hRSISlow[x]=iRSI(DIRI[x],TFt,rsislow,srsiapp);          //-- Handle for the Slow RSI indicator
        hRSIFast[x]=iRSI(DIRI[x],TFt,rsifast,frsiapp);          //-- Handle for the Fast RSI indicator
        hVIDyAv[x]=iVIDyA(DIRI[x],TFt,9,12,0,PRICE_WEIGHTED);   //-- Handle for the VIDYA indicator for Trailing Stop
        hPar05[x]=iSAR(DIRI[x],TFT05,SARstep,SARmaxi);          //-- Handle for the iSAR indicator for M5 Timeframe
        //--
      }

故此,要获取每个 RSI 指标的缓冲区值,我们将从指标句柄中复制每个缓冲区。

为了从快速 RSI 句柄复制缓冲区(缓冲区编号 0)到目标数组:

CopyBuffer(hRSIFast[x],0,0,bar,RSIFast);

为了从慢速 RSI 句柄复制缓冲区(缓冲区编号 0)到目标数组:

CopyBuffer(hRSISlow[x],0,0,bar,RSISlow);

在执行 GetRSIxx() 和 PARSAR05() 这两个函数后,GetOpenPosition() 函数将提供值:

  • 值为 0,信号未知。
  • 值为 1,是开立多头订单的信号。
  • 值为 -1,是开立空头订单的信号。

当 GetOpenPosition() 函数返回值 1 时,智能系统调用 OpenBuy() 函数来开立多头订单。

bool MCEA::OpenBuy(const string symbol) 
  {
//---
    ResetLastError();
    //--
    bool buyopen      = false;
    string ldComm     = GetCommentForOrder()+"_Buy";
    double ldLot      = MLots(symbol);
    ENUM_ORDER_TYPE type_req = ORDER_TYPE_BUY;
    //--
    MqlTradeRequest req={};
    MqlTradeResult  res={};
    MqlTradeCheckResult check={};
    //-- structure is set to zero
    ZeroMemory(req);
    ZeroMemory(res);
    ZeroMemory(check);
    //--
    CurrentSymbolSet(symbol);
    double SL=OrderSLSet(symbol,type_req,mc_symbol.Bid());
    double TP=OrderTPSet(symbol,type_req,mc_symbol.Ask());
    //--
    if(RefreshTick(symbol))
       buyopen=mc_trade.Buy(ldLot,symbol,mc_symbol.Ask(),SL,TP,ldComm);
    //--
    int error=GetLastError();
    if(buyopen||error==0)
      {
        string bsopen="Open BUY Order for "+symbol+" ~ Ticket= ["+(string)mc_trade.ResultOrder()+"] successfully..!";
        Do_Alerts(symbol,bsopen);
      }
    else
      {
        mc_trade.CheckResult(check);
        Do_Alerts(Symbol(),"Open BUY order for "+symbol+" FAILED!!. Return code= "+
                 (string)mc_trade.ResultRetcode()+". Code description: ["+mc_trade.ResultRetcodeDescription()+"]");
        return(false);   
      }
    //--
    return(buyopen);
    //--
//---
  } //-end OpenBuy
//---------//


同时,如果 GetOpenPosition() 函数返回值 -1,则智能系统将调用 OpenSell() 函数开立空头订单。

bool MCEA::OpenSell(const string symbol) 
  {
//---
    ResetLastError();
    //--
    bool selopen      = false;
    string sdComm     = GetCommentForOrder()+"_Sell";
    double sdLot      = MLots(symbol);
    ENUM_ORDER_TYPE type_req = ORDER_TYPE_SELL;
    //--
    MqlTradeRequest req={};
    MqlTradeResult  res={};
    MqlTradeCheckResult check={};
    //-- structure is set to zero
    ZeroMemory(req);
    ZeroMemory(res);
    ZeroMemory(check);
    //--
    CurrentSymbolSet(symbol);
    double SL=OrderSLSet(symbol,type_req,mc_symbol.Ask());
    double TP=OrderTPSet(symbol,type_req,mc_symbol.Bid());
    //--
    if(RefreshTick(symbol))
       selopen=mc_trade.Sell(sdLot,symbol,mc_symbol.Bid(),SL,TP,sdComm);
    //--
    int error=GetLastError();
    if(selopen||error==0)

      {
        string bsopen="Open SELL Order for "+symbol+" ~ Ticket= ["+(string)mc_trade.ResultOrder()+"] successfully..!";
        Do_Alerts(symbol,bsopen);
      }
    else
      {
        mc_trade.CheckResult(check);
        Do_Alerts(Symbol(),"Open SELL order for "+symbol+" FAILED!!. Return code= "+
                 (string)mc_trade.ResultRetcode()+". Code description: ["+mc_trade.ResultRetcodeDescription()+"]");
        return(false);   
      }
    //--
    return(selopen);
    //--
//---
  } //-end OpenSell
//---------//


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

在输入属性的 “Other Expert Advisor Parameters” 组中,交易者有机会选择是否在图表上显示交易信息(Yes)、或(No)。

如果选择该选项(Yes),则交易信息将通过调用 TradeInfo() 函数显示在加载 EA 的图表上。

作为 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()
//---------//
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 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      :: 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()  
//---------//

多币种智能系统 RSIxRSI_MCEA 界面类似于下图。

RSIxRSI_Look


如您所见,在智能系统名称 RSIxRSI_MCEA 下有按钮 “M”、“C” 和 “R”。

单击 M 按钮时,将显示一个手工单击按钮面板,如下所示。

Expert_manual_button_01


当显示手工点击按钮面板时,交易者可以手工管理订单:

1. Set SL/TP All Orders — 为所有订单设置止损/止盈
为所有订单设置止损/止盈解释如上,如果交易者输入参数使用订单止损(否)和/或使用订单止盈(否),但随后交易者想对所有订单使用止损或止盈,那么单击“为所有订单设置止损/止盈”按钮将修改所有订单,并应用止损和/或止盈。

void MCEA::SetSLTPOrders(void) 
  {
//---
   ResetLastError();
   MqlTradeRequest req={};
   MqlTradeResult  res={};
   MqlTradeCheckResult check={};
   //--
   double modbuysl=0;
   double modselsl=0;
   double modbuytp=0;
   double modseltp=0;
   string position_symbol;
   int totalorder=PositionsTotal();
   //--    
   for(int i=totalorder-1; i>=0; i--) 
     {
       string symbol=PositionGetSymbol(i);
       position_symbol=symbol;
       if(mc_position.Magic()==magicEA)
         {
           ENUM_POSITION_TYPE opstype = mc_position.PositionType();
           if(opstype==POSITION_TYPE_BUY) 
             {
               Pips(symbol);
               RefreshTick(symbol);
               double price    = mc_position.PriceCurrent();
               double pos_open = mc_position.PriceOpen();
               double pos_stop = mc_position.StopLoss();
               double pos_take = mc_position.TakeProfit();
               modbuysl=SetOrderSL(symbol,opstype,pos_open);
               if(price<modbuysl) modbuysl=mc_symbol.NormalizePrice(price-slip*pip);
               modbuytp=SetOrderTP(symbol,opstype,pos_open);
               if(price>modbuytp) modbuytp=mc_symbol.NormalizePrice(price+slip*pip);
               //--
               if(pos_stop==0.0 || pos_take==0.0)
                 {
                   if(!mc_trade.PositionModify(position_symbol,modbuysl,modbuytp))
                     {
                       mc_trade.CheckResult(check);
                       Do_Alerts(symbol,"Set SL and TP for "+EnumToString(opstype)+" on "+symbol+" FAILED!!. Return code= "+
                                (string)mc_trade.ResultRetcode()+". Code description: ["+mc_trade.ResultRetcodeDescription()+"]");
                     }
                 }
             }
           if(opstype==POSITION_TYPE_SELL) 
             {
               Pips(symbol);
               RefreshTick(symbol);
               double price    = mc_position.PriceCurrent();
               double pos_open = mc_position.PriceOpen();
               double pos_stop = mc_position.StopLoss();
               double pos_take = mc_position.TakeProfit();
               modselsl=SetOrderSL(symbol,opstype,pos_open);
               if(price>modselsl) modselsl=mc_symbol.NormalizePrice(price+slip*pip);
               modseltp=SetOrderTP(symbol,opstype,pos_open);
               if(price<modseltp) modseltp=mc_symbol.NormalizePrice(price-slip*pip);
               //--
               if(pos_stop==0.0 || pos_take==0.0)
                 {
                   if(!mc_trade.PositionModify(position_symbol,modselsl,modseltp))
                     {
                       mc_trade.CheckResult(check);
                       Do_Alerts(symbol,"Set SL and TP for "+EnumToString(opstype)+" on "+symbol+" FAILED!!. Return code= "+
                                (string)mc_trade.ResultRetcode()+". Code description: ["+mc_trade.ResultRetcodeDescription()+"]");
                     }
                 }
             }
         }
     }
    //--
    return;
//---
  } //-end SetSLTPOrders
//---------//

2. Close All Orders — 所有订单平仓
如果交易者希望所有订单平仓,只需单击“所有订单平仓”按钮即可把所有持单了结。

void MCEA::CloseAllOrders(void) //-- function: close all order
   {
//----
    ResetLastError();
    //--
    MqlTradeRequest req={};
    MqlTradeResult  res={};
    MqlTradeCheckResult check={};
    //--
    int total=PositionsTotal(); // number of open positions
    //--- iterate over all open positions
    for(int i=total-1; i>=0; i--)
      {
        //--- if the MagicNumber matches
        if(mc_position.Magic()==magicEA)
          { 
            //--
            string position_Symbol   = PositionGetSymbol(i);  // symbol of the position
            ulong  position_ticket   = PositionGetTicket(i);  // ticket of the the opposite position
            ENUM_POSITION_TYPE  type = mc_position.PositionType();
            RefreshTick(position_Symbol);
            bool closepos = mc_trade.PositionClose(position_Symbol,slip);
            //--- output information about the closure
            PrintFormat("Close #%I64d %s %s",position_ticket,position_Symbol,EnumToString(type));
            //---
          }
      }
   //---
   return;
//----
   } //-end CloseAllOrders()
//---------//

3. Close All Profits — 所有盈利单平仓如果交易者希望所有盈利单了结,只需单击“所有订单平仓”按钮即可把所有盈利单了结。

bool MCEA::ManualCloseAllProfit(void)
   {
//----
    ResetLastError();
    //--
    bool orclose=false;
    //--
    MqlTradeRequest req={};
    MqlTradeResult  res={};
    MqlTradeCheckResult check={};
    //--
    int ttlorder=PositionsTotal(); // number of open positions
    //--
    for(int x=0; x<arrsymbx; x++)
       {
         string symbol=DIRI[x];
         orclose=false;
         //--
         for(int i=ttlorder-1; i>=0; i--)
            {
              string position_Symbol   = PositionGetSymbol(i);
              ENUM_POSITION_TYPE  type = mc_position.PositionType();
              if((position_Symbol==symbol) && (mc_position.Magic()==magicEA))
                {
                  double pos_profit = mc_position.Profit();
                  double pos_swap   = mc_position.Swap();
                  double pos_comm   = mc_position.Commission();
                  double cur_profit = NormalizeDouble(pos_profit+pos_swap+pos_comm,2);
                  ulong  position_ticket = PositionGetTicket(i);
                  //---
                  if(type==POSITION_TYPE_BUY && cur_profit>0.02)
                    {
                      RefreshTick(position_Symbol);
                      orclose = mc_trade.PositionClose(position_Symbol,slip);
                      //--- output information about the closure
                      PrintFormat("Close #%I64d %s %s",position_ticket,position_Symbol,EnumToString(type));
                    }
                  if(type==POSITION_TYPE_SELL && cur_profit>0.02)
                    {
                      RefreshTick(position_Symbol);
                      orclose = mc_trade.PositionClose(position_Symbol,slip);
                      //--- output information about the closure
                      PrintFormat("Close #%I64d %s %s",position_ticket,position_Symbol,EnumToString(type));
                    }
                }
            }
       }
     //--
     return(orclose);
//----
   } //-end ManualCloseAllProfit()
//---------//

当点击 “C” 按钮时,会显示一个包含 30 个品种名称或交易对的面板按钮,交易者可以点击其中一个对名称、或品种名称。
单击其中一个货币对名称或交易品种名称,立即将图表品种替换为被点击的品种。

Expert_manual_button_02

void CreateSymbolPanel()
  {
//---    
    //--
    ResetLastError();
    DeletePanelButton();
    int sydis=83;
    int tsatu=int(mc.sall/2);
    //--
    CreateButtonTemplate(0,"Template",180,367,STYLE_SOLID,5,BORDER_RAISED,clrYellow,clrBurlyWood,clrWhite,CORNER_RIGHT_UPPER,187,45,true);
    CreateButtonTemplate(0,"TempCCS",167,25,STYLE_SOLID,5,BORDER_RAISED,clrYellow,clrBlue,clrWhite,CORNER_RIGHT_UPPER,181,50,true);
    CreateButtonClick(0,"X",14,14,"Arial Black",10,BORDER_FLAT,"X",clrWhite,clrWhite,clrRed,ANCHOR_CENTER,CORNER_RIGHT_UPPER,22,48,true,"Close Symbol Panel");
    //--
    string chsym="Change SYMBOL";
    int cspos=int(181/2)+int(StringLen(chsym)/2);
    CreateButtontLable(0,"CCS","Bodoni MT Black",chsym,11,clrWhite,ANCHOR_CENTER,CORNER_RIGHT_UPPER,cspos,62,true,"Change Chart Symbol");
    //--
    for(int i=0; i<tsatu; i++)
      CreateButtonClick(0,mc.AS30[i],80,17,"Bodoni MT Black",8,BORDER_RAISED,mc.AS30[i],clrYellow,clrBlue,clrWhite,ANCHOR_CENTER,CORNER_RIGHT_UPPER,180,sydis+(i*22),true,"Change to "+mc.AS30[i]);
    //--
    for(int i=tsatu; i<mc.sall; i++)
      CreateButtonClick(0,mc.AS30[i],80,17,"Bodoni MT Black",8,BORDER_RAISED,mc.AS30[i],clrYellow,clrBlue,clrWhite,ANCHOR_CENTER,CORNER_RIGHT_UPPER,94,sydis+((i-tsatu)*22),true,"Change to "+mc.AS30[i]);
    //--
    ChartRedraw(0);
    //--
    return;
//---
   } //-end CreateSymbolPanel()
//---------//

在这种情况下,当单击其中一个品种名称时,OnChartEvent() 函数将调用 ChangeChartSymbol() 函数。

   if(id==CHARTEVENT_OBJECT_CLICK) 
     {
       int lensymbol=StringLen(Symbol());
       int lensparam=StringLen(sparam);

       //--- if Symbol button is click
       if(lensparam==lensymbol)
         {
           int sx=mc.ValidatePairs(sparam);
           ChangeChartSymbol(mc.AS30[sx],CCS);
           mc.PanelExtra=false;
         }
       //--
     }
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()
//---------//


最后,单击 R 按钮将从图表中删除多币种智能系统 RSIxRSI_MCEA,如此交易者不必再手工删除智能系统。

   if(id==CHARTEVENT_OBJECT_CLICK) 
     {
       //--
       //--- 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);
         }
       //---
     }


策略测试器

MetaTrader 5 策略测试器的优势在于,它支持并允许我们测试基于多品种交易的策略,或测试所有可用品种和所有可用时间帧的自动交易。
因此,在 MetaTrader 5 策略测试器平台上,我们将测试 RSIxRSI_MCEA 多货币智能交易系统。

在第一次测试中,我们将 RSIxRSI_MCEA 放在 XAGUSD 对及 H4 时间帧上,自定义时间段为 2023.10.01 至 2024.01.05。
测试是采用两种不同的输入属性进行的,分别在全球策略 EA 参数组,和交易与订单管理参数组中指定。

1. RSIxRSI_MCEA 基于 XAGUSD 货币对和 H4 时间帧

ST_07_e1

ST_07_e2


第一次测试的结果如下图所示。

ST_07_e3

2. RSIxRSI_MCEA 基于 XAGUSD 货币对和 H124 时间帧

ST_08_e1

ST_08_e2

第二次测试的结果如下图所示。

ST_08_e3


结束语

利用 MQL5 进行外汇交易时,采用来自快速 RSI 穿越慢速 RSI、或 RSI 彼此交叉信号创建多货币智能交易系统的结论如下:

  1. 事实证明,在 MQL5 中创建多货币智能系统非常简单,与创建单一货币智能系统并无太大区别。
  2. 创建多币种智能交易系统将提高交易者的效率和有效性,从而降低打开众多品种图表进行交易的需求。
  3. 与单一货币智能系统相比,应用正确的交易策略将增加获利的可能性。这是因为一个货币对的损失能由其它货币对的盈利所弥补。
  4. 这个 RSIxRSI_MCEA 多币种智能系统只是一个学习和思路生成的示例。其在策略测试器当中的测试结果仍然不佳。因此,通过在不同的时间帧、或计算不同的指标周期来进行实验和测试,可以获得更好的策略,及盈利性更佳的结果。
  5. 以我的观点,这种 RSI 交叉策略应该进一步通过各种不同的实验研究,从时间帧、快速 RSI 周期、慢速 RSI 周期、两个 RSI 的差值开始。
  6. 根据我在策略测试器上的实验结果,在低于 H4 时间帧时,结果并不好,仅在 H4 及以上时间帧时,例如在时间帧 H8 和 H12 上,结果良好,开单交易量很少,这是与较短时间帧上大量开单交易相比,但仍然亏损。

我们希望本文和 MQL5 多币种智能交易系统程序能对交易者学习和开拓思路有所帮助。


感谢您的阅读。

本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/14051

附加的文件 |
RSIxRSI_MCEA.mq5 (112.24 KB)
交易策略 交易策略
各种交易策略的分类都是任意的,下面这种分类强调从交易的基本概念上分类。
数据分组处理方法:在MQL5中实现多层迭代算法。 数据分组处理方法:在MQL5中实现多层迭代算法。
在本文中,我们介绍如何在MQL5中实现分组数据处理方法中的多层迭代算法。
新手在交易中的10个基本错误 新手在交易中的10个基本错误
新手在交易中会犯的10个基本错误: 在市场刚开始时交易, 获利时不适当地仓促, 在损失的时候追加投资, 从最好的仓位开始平仓, 翻本心理, 最优越的仓位, 用永远买进的规则进行交易, 在第一天就平掉获利的仓位,当发出建一个相反的仓位警示时平仓, 犹豫。
DoEasy.服务功能(第 1 部分):价格形态 DoEasy.服务功能(第 1 部分):价格形态
在本文中,我们将开始开发使用时间序列数据搜索价格形态的方法。一种形态有一组参数,对任何类型的形态都是通用的。所有此类数据都将集中在基础抽象形态的对象类中。在本文中,我们将创建一个抽象形态类和一个 Pin Bar 形态类。