English Русский Español Deutsch 日本語 Português
preview
如何利用 MQL5 创建简单的多币种智能交易系统(第 7 部分):依据动量振荡器指标的之字折线

如何利用 MQL5 创建简单的多币种智能交易系统(第 7 部分):依据动量振荡器指标的之字折线

MetaTrader 5示例 | 12 十二月 2024, 13:30
110 0
Roberto Jacobs
Roberto Jacobs

概述

多货币智能系统是一款自动交易系统,可从单个交易品种图表中开立、平仓、和管理多个品种对的订单。本文专注于交易 30 对、并采用之字折线指标的智能系统,该指标利用动量振荡器过滤或过滤彼此的信号。

如前几篇文章所示,多货币交易可以借助 MQL5 交易终端和策略测试器的强立功能、和设施。为了满足交易者寻求高效和有效自动交易的需求,我们来依靠 MQL5 提供的可靠强力功能、和设施。我们的目标是创建一个简单的多币种智能系统,可运用各种思路和策略。本文将专注于使用之字折线指标,其依据动量振荡器进行过滤、或者过滤彼此的信号。


计划和功能

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


为了确保本文中讨论的智能系统的顺利运行,我实现了一个自动处理品种名称带有前缀和/或后缀的函数。不过,重点要注意的是,该函数仅适工作于 MT5 中的外汇和金属品种对名称,不适用于特殊品种和指数。


1.1. 附加功能:

1.1.1. 单一货币智能系统

一些用户询问有关该多币种 EA 如何当作单一货币、或独立 EA。
为了解决这个问题,添加了一项功能,允许将该多币种 EA 当作单货币 EA。

在选择交易对模式(多种或单种)选项中,交易者可以在两种交易对条件之间进行选择:单一货币或多货币。

1. Single Pair (single-currency) — 单对(单币种)
2. Multi Pairs (multi-currency) — 多对(多币种)

设置智能系统输入参数,如下图所示

交易对选项


如果选择了'单对':
'SP' 或单对选项将智能系统限制为仅在其所放置的货币对上进行交易。举例,如果智能系统被放置在 EURUSD 对上,它只会在 EURUSD 对上进行交易。

如果选择了“多对”:
选项组“选择要交易的货币对”包括 10 对将要交易的货币选项。
其中一对称为“交易者愿望对”,它要求交易者在“智能系统输入”属性中手工输入要交易的货币对。不过,重点是要记住,输入的货币对名称必须已经在 30 对的列表当中。

“交易者的愿望对”选项可用于确保智能系统仅交易单一货币、或作为独立的 EA 工作。
智能系统将仅依据提供的期望货币对名称进行交易或工作。这确保了专注方式交易、或工作于单一货币对。

如果交易者仅输入 XAUUSD 对的名称,则智能系统仅在该货币对上进行交易。
智能系统将仅在 XAUUSD 对上进行交易,无论它在 30 个可用货币对中的位置如何。

必须如下图所示配置智能系统输入参数。

单独-twp


故此,在本文中,有两种方式来交易单一货币,或作为单独专用智能系统。

1. 坚持使用多货币对或 “MP” 选项,然后选择“交易者期望对”选项。不过,仅需输入一个货币对名称,例如 XAUUSD。
该选项将智能系统限制为仅据"交易者期望对“指定的货币对上进行交易。它不会交易任何其它货币对。

2. 在选择”交易对模式“中,选择 “SP” 或单一对。
如果智能系统应用于 EURUSD 对,它将专门在 EURUSD 对上进行交易。


1.1.2. Trade on Specific Time — 在特定时间交易

在”在特定时间交易”组中,为交易者提供了想要在该时段进行交易的选项。
也许很多交易者都想按照时区进行交易,所以要交易的货币对可与对应交易时段相应,所以在这个智能系统,我们仍然使用交易时段(时区)的选项。


2. 信号指标。

2.1. 之字折线(ZigZag)指标。

之字折线指标是一种衡量价格走势的方法,且无不必要噪音。它的运算是判定价格摇摆(高点和低点)之间的距离。随后,该指标计算回调。如果回调超过某个预期额度,则认为价格走势已完成。

众所周知,之字折线是最古老的技术指标之一,并将其运作方式从股票市场搬至货币交易。它令交易者能够把市场结构可视化。
当尝试估测价格走势时,之字折线指标可帮助交易者自动过滤掉次要的价格走势。利用之字折线指标有助于更清晰地理解市场结构。

当价格走势条件受到随机价格波动的影响而波动时,之字折线指标可用来帮助识别价格趋势,和价格趋势中的变化。


技术分析师言道:

  • 之字折线指标降低了随机价格波动的影响,用于识别价格趋势、及价格趋势的变化。
  • 该指标降低了噪音级别,强调底层趋势的更高点和更低点。
  • 之字折线指标在趋势强劲的市场中效果最佳。

之字折线指标限制。
与其它趋势跟踪指标类似,买入和卖出信号是通过查看过去的价格走势来判定的,也许无法准确预测未来的价格走势。举例,在生成之字折线指示线时,可能趋势已经走完大部分。

交易者应意识到,最近的之字折线也许不是永久的(译者按:即所谓的“未来函数”)。当价格改变方向时,指标开始绘制一条新指示线。
如果该指示线未达到指标的百分比设置,且证券价格逆转,则该指示将被删除,并替换为趋势原始方向的延长线。


之字折线参数设置:

之字折线指标有 3 个输入参数:

1. Depth - 深度默认值为 12。
Depth – 指它在图表柱线图序列中能看到多远。
为了获得定义的高点和低点,您需要确保有足够的 “深度”。
它是最小柱线数量,即区间内柱线的差价最大值或最小值唯一不二(例如:如果我们在蜡烛 x 处已有一个最大值,深度为 12,那么至少 x+12 根蜡烛以内不可绘制后续的最大值)。

2. Deviation - 默认值为 5。
Deviation - 是指将趋势线从正向变为负向所需的价格变化百分比。

3. Backstep - 默认值为 3。
Backstep - 摆动高点和低点之间的最小柱线数量


之字折线指标公式:

ZigZag (HL, %change=X, retrace=FALSE, LastExtreme=TRUE)

 如果 %change>=X,绘制之字折线 

其中:

HL = 价格序列或收盘价序列的(高点-低点) 

%change = 最小价格变化百分比

Retrace = 它是前一次移动的回撤变化,或从波峰到波谷的绝对变化?

Last Extreme = 如果极值价格在多个周期内相同,则极值价格是第一个观察值还是最后一个观察值? 


根据我的观察,对于之字折线指标,至少有 4 种信号算法可以使用。
在这个智能系统中,我创建了一个选项,以便交易者可以选择并尝试来自之字折线 指标的四种算法信号。


2.2. 动量振荡器(AO)。

动量震荡指标(AO)是交易者用来识别市场趋势和动量的动量指标。它由知名技术分析师比尔·威廉姆斯(Bill Williams)开发,因其简单性和可靠性而成为交易者的流行工具。

动量振荡器指标是一个市场动量指标,它将近期的市场走势与历史市场走势进行比较。
它在中心有一条零线,根据两条不同移动平均线的比较在其两侧绘制价格走势。

动量振荡器指标的计算方法是从金融产品中点 (H+L)/2 价格的 5-周期 SMA 中减去 34-周期简单移动平均线(SMA)。

中点价格被认为比开盘价或收盘价更准确地代表真实市场价格,因为它同时考虑了给定时期的最高价和最低价。
AO 在正值和负值之间振荡,正值表示看涨趋势,负值表示看跌趋势。

34-周期简单移动平均线(SMA)和 5-周期 SMA 的值在指标代码中永久设置,并且没有机会在指标输入参数属性中进行更改。

动量振荡器指标 = 5-周期 SMA(中位价,5-周期)– 34-周期 SMA(中位价,34-周期)

其中,中间价为:(时段周期的最高价 + 时段周期的最低价)/ 2。


对于 AO 指标,至少有 3 种信号算法可以使用。
因此,在这个智能系统中,我创建了一个选项,以便交易者可以选择并尝试来自该 AO 指标的三个算法信号。

下图所示,运用动量振荡器过滤、或彼此过滤信号的之字折线指标。

下面的信号插图是选项 2 之字折线信号,和选项 2 AO 信号

ZZ_AO_Indi_Signal_illustration

ZZ_AO_Indi_Signal_illustration_variation


3. 交易和订单管理

该多货币智能系统提供若干种方式管理交易:

3.1. 止损单。

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

  • 如果选中“使用订单止损(否)”选项,则所有订单在开单时都不带止损。

如果“由反向信号平单”设置为“是”,则不带止损开单将是安全的。但是,如果“由反向信号平单”设置为“否”,则对净值存在非常高的风险。因此,我添加了一个函数来启用检查净值和余额之间的百分比。在这种情况下,如果余额的净值百分比小于(100% - 每笔交易的净值风险百分比),则智能系统将运行 CheckLoss() 函数(运行虚拟止损的函数),并在亏损大于设置的止损值情况下平单。
            //--
            if(use_sl==No && CheckVSLTP==Yes)
              {
                if(!mc.CheckEquityBalance())
                  if(mc.CloseAllLoss())
                    mc.Do_Alerts(symbol,"Close order due stop in loss to secure equity.");
              }
            //--

bool MCEA::CheckEquityBalance(void)
  {
//---
   bool isgood=false;
   if((mc_account.Equity()/mc_account.Balance()*100) > (100.00-Risk)) isgood=true;
   //--
   return(isgood);
//---
  } //-end CheckEquityBalance()
//---------//

bool MCEA::CheckLoss(const string symbol,ENUM_POSITION_TYPE intype,double slc=0.0)
   {
//---
     Pips(symbol);
     bool inloss=false;
     double lossval=slc==0.0 ? (SLval*0.5) : slc;
     double posloss  = mc_symbol.NormalizePrice(slc*pip);
     int ttlorder=PositionsTotal(); // number of open positions
     //--
     for(int x=0; x<arrsymbx; x++)
       {
         string symbol=DIRI[x];
         //--
         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 price    = mc_position.PriceCurrent();
                  double pos_open = mc_position.PriceOpen();
                  double posloss  = mc_symbol.NormalizePrice(lossval*pip);
                  double pricegab = mc_symbol.NormalizePrice(fabs(price-pos_open));
                  //---
                  if(type==intype && pricegab>posloss) inloss=true;
                }
            }
       }
     //--
     return(inloss);
//----
   } //-end CheckLoss()
//---------//

bool MCEA::CloseAllLoss(void)
   {
//----
    ResetLastError();
    //--
    bool orclose=false;
    string isloss="due stop in loss.";
    //--
    MqlTradeRequest req={};
    MqlTradeResult  res={};
    MqlTradeCheckResult check={};
    //--
    int ttlorder=PositionsTotal(); // number of open positions
    //--
    for(int x=0; x<arrsymbx; x++)
       {
         string symbol=DIRI[x];
         Pips(symbol);
         double posloss=mc_symbol.NormalizePrice(SLval*pip);
         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 price    = mc_position.PriceCurrent();
                  double pos_open = mc_position.PriceOpen();
                  double posloss  = mc_symbol.NormalizePrice(SLval*pip);
                  double pricegab = mc_symbol.NormalizePrice(fabs(price-pos_open));
                  ulong  position_ticket = PositionGetTicket(i);
                  //---
                  if(type==POSITION_TYPE_BUY && pricegab>posloss)
                    {
                      RefreshTick(position_Symbol);
                      orclose = mc_trade.PositionClose(position_Symbol,slip);
                      //--- output information about the closure
                      PrintFormat("Close Buy %s %s %s",symbol,EnumToString(POSITION_TYPE_BUY),isloss);
                    }
                  if(type==POSITION_TYPE_SELL && pricegab>posloss)
                    {
                      RefreshTick(position_Symbol);
                      orclose = mc_trade.PositionClose(position_Symbol,slip);
                      //--- output information about the closure
                      PrintFormat("Close Sell %s %s %s",symbol,EnumToString(POSITION_TYPE_BUY),isloss);
                    }
                }
            }
       }
     //--
     return(orclose);
//----
   } //-end CloseAllLoss()
//---------//

  • 如果选项“使用订单止损(是)”:再次给出选项:“使用自动计算止损(是)或(否)”
  • 如果选项是“自动计算止损(是)”,则将由智能系统自动执行止损计算。
  • 如果选项“自动计算止损(否)”,则交易者必须以点数为单位输入止损值。
  • 如果选项“使用订单止损(否)”:则智能系统将检查每笔开单,信号条件是否仍然良好,订单是否可维持盈利;或信号疲软,需要平单以保障盈利;或信号条件已逆转方向,订单必须以亏损条件了结。

注意:特别是对于“因信号疲软并保障盈利而了结交易”,会给出一个选项,是否激活它。

在 ExpertActionTrade() 函数的一部分:

                //--
                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.");
                      }
                  }
                //--

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

int MCEA::GetCloseInWeakSignal(const string symbol,int exis) // Signal Indicator Position Close in profit
  {
//---
    int ret=0;
    int rise=1,
        down=-1;
    //--
    int AOdir=AOColorSignal(symbol);
    int ZZDir=ZigZagSignal(symbol);
    //--
    if(exis==down && (AOdir==rise||ZZDir==rise)) ret=rise;
    if(exis==rise && (AOdir==down||ZZDir==down)) ret=down;
    //--
    return(ret);
//---
  } //-end GetCloseInWeakSignal()
//---------//
  • 如果它没有被激活(否),即使信号已经疲软,订单仍将持有、或不会为了保障盈利而了结。
  • 如果激活(Yes),则之字折线指标和 AO 指标的条件为:

对于多头订单平仓:
当 AO 指标的颜色从绿色变为红色(默认颜色),或当之字折线指标达到高点极值,且价格改变方向时,多头订单将被平仓。

对于空头订单平仓:
当 AO 指标的颜色从红色变为绿色(默认颜色),或当之字折线指标达到低点极值位置,且价格改变方向时,空头订单将被平仓。

设置止损单的代码如下:

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


3.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.3. 尾随止损

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

  • 如果选项“使用尾随 SL是(否)”,则 EA 不会执行尾随止损和尾随止盈。
  • 如果选项“使用尾随止损(是)”:交易者可以在 3 个选项之间进行选择:

1. 按价格尾随
尾随止损将由 EA 按价格走势和输入属性中的值来执行。

2. 按指标尾随
尾随止损将由 EA 按 VIDYA 指标执行。
根据我的研究和实验,与抛物线 SAR、或移动平均线指标的几种变体相比,VIDYA 指标略好,非常适合尾随止损。
与抛物线 SAR 指标相比,VIDYA 指标更接近价格走势,而与 AMA、DEMA 和 MA 指标相比,VIDYA 指标离价格走势更远。
故此,在本文中,我决定基于 VIDYA 指标打造尾随止损功能。

3. 按前一根柱线的最高价或最低价尾随止损
对于买入订单,尾随止损的位置将会放置在前一根柱线的最低价(LOW[1])。
对于卖出订单,尾随止损位置将放置在前一根柱线的最高价(HIGH[1])。

尾随止损价格函数:

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 byprice:
          {
            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 byindi:
          {
            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;
          }
        case byHiLo:
          {
            UpdatePrice(xsymb,TFt,2);
            //--
            if(ptype==POSITION_TYPE_BUY  && (HIGH[0]>HIGH[1]))
               pval=LOW[1];
            if(ptype==POSITION_TYPE_SELL && (LOW[0]<LOW[1]))
               pval=HIGH[1];
            break;
          }
      }
    //--
    return(pval);
//---
  } //-end TSPrice()
//---------//


bool MCEA::ModifyOrdersSL(const string symbx,int TS_type)
  {
//---
   ResetLastError();
   MqlTradeRequest req={};
   MqlTradeResult  res={};
   MqlTradeCheckResult check={};
   //--
   int TRSP=TS_type;
   bool modist=false;
   int x=PairsIdxArray(symbx);
   Pips(symbx);
   //--
   int total=PositionsTotal();
   //--        
   for(int i=total-1; i>=0; i--) 
     {
       string symbol=PositionGetSymbol(i);
       if(symbol==symbx && mc_position.Magic()==magicEA)
         {
           ENUM_POSITION_TYPE opstype = mc_position.PositionType();
           if(opstype==POSITION_TYPE_BUY) 
             {
               RefreshTick(symbol);
               double price = mc_position.PriceCurrent();
               double vtrsb = mc_symbol.NormalizePrice(TSPrice(symbx,opstype,TRSP));
               double pos_open   = mc_position.PriceOpen();
               double pos_stop   = mc_position.StopLoss();
               double pos_tp     = mc_position.TakeProfit();
               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;
               bool modbuy = (price>modminsl && modbuysl>modstart && (pos_stop==0.0||modbuysl>pos_stop));
               //--
               if(modbuy && netp>minprofit)
                 {
                   modist=mc_trade.PositionModify(symbol,modbuysl,pos_tp);
                 }  
             }
           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_tp     = mc_position.TakeProfit();
               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;
               bool modsel = (price<modminsl && modselsl<modstart && (pos_stop==0.0||modselsl<pos_stop)); 
               //--
               if(modsel && netp>minprofit)
                 {
                   modist=mc_trade.PositionModify(symbol,modselsl,pos_tp);
                 }  
             }
         }
     }
    //--
    return(modist);
//---
  } //-end ModifyOrdersSL()
//---------//


3.4. 尾随止盈

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

  • 如果选项“使用尾随止盈是(否)”,则 EA 不会执行尾随止盈。
  • 如果选项“使用尾随止盈为(是)”,则以点数为单位输入尾随止盈值(默认值 25 点),智能交易系统将根据变量值 TPmin(最小尾随止盈值)执行尾随止盈。

bool MCEA::ModifyOrdersTP(const string symbx)
  {
//---
   ResetLastError();
   MqlTradeRequest req={};
   MqlTradeResult  res={};
   MqlTradeCheckResult check={};
   //--
   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 pos_open = mc_position.PriceOpen();
               double pos_stop = mc_position.StopLoss();
               double pos_tp   = mc_position.TakeProfit();
               double modbuytp = pos_tp==0.0 ? mc_symbol.NormalizePrice(pos_open+TPmin*pip) : pos_tp;
               double modpostp = mc_symbol.NormalizePrice(price+TPmin*pip);
               bool modtpb = (price>pos_open && modbuytp-price<TPmin*pip && pos_tp<modpostp);
               //--
               if(modtpb)
                 {
                   modist=mc_trade.PositionModify(symbol,pos_stop,modpostp);
                 }  
             }
           if(opstype==POSITION_TYPE_SELL) 
             {
               RefreshTick(symbol);
               double price    = mc_position.PriceCurrent();
               double pos_open = mc_position.PriceOpen();
               double pos_stop = mc_position.StopLoss();
               double pos_tp   = mc_position.TakeProfit();
               double modseltp = pos_tp==0.0 ? mc_symbol.NormalizePrice(pos_open-TPmin*pip) : pos_tp;
               double modpostp = mc_symbol.NormalizePrice(price-TPmin*pip);
               bool modtps = (price<pos_open && price-modseltp<TPmin*pip && pos_tp>modpostp);
               //--
               if(modtps)
                 {
                   modist=mc_trade.PositionModify(symbol,pos_stop,modpostp);
                 }  
             }
         }
     }
    //--
    return(modist);
//---
  } //-end ModifyOrdersTP()
//---------//


3.5. 由反向信号平仓

选项:“由反向信号平仓(是)或(否)”

  • 如果“由反向信号平仓(是)”:

故此,如果之前已开立了卖出订单,然后指标信号反转,那么卖出订单将被平仓,然后智能系统将开立一笔买入订单。反之亦然。
在 ExpertActionTrade() 函数的一部分:
if(Close_by_Opps==Yes && mc.xos[x]>0) mc.CloseSellPositions(symbol);
bool MCEA::CloseSellPositions(const string symbol)
  {
    //---
    ResetLastError();
    bool sellclose=false;
    int total=PositionsTotal(); // number of open positions
    ENUM_POSITION_TYPE closetype = POSITION_TYPE_SELL;
    ENUM_ORDER_TYPE     type_req = ORDER_TYPE_BUY;
    //--
    MqlTradeRequest req={};
    MqlTradeResult  res={};
    MqlTradeCheckResult check={};
    //--
    int x=PairsIdxArray(symbol);
    //--- iterate over all open positions
    for(int i=total-1; i>=0; i--)
      {
        if(mc_position.SelectByIndex(i))
          {
            //--- Parameters of the order
            string position_Symbol   = PositionGetSymbol(i);
            ulong  position_ticket   = PositionGetTicket(i);
            ENUM_POSITION_TYPE  type = mc_position.PositionType();
            //--- if the MagicNumber matches
            if((position_Symbol==symbol) && (mc_position.Magic()==magicEA))
              { 
                //--
                if(type==closetype)
                  {
                    RefreshTick(position_Symbol);
                    sellclose=mc_trade.PositionClose(position_Symbol,slip);
                    //--- output information about the closure
                    PrintFormat("Close Sell #%I64d %s %s",position_ticket,position_Symbol,EnumToString(type));
                  }
              }
          }
      }
   //---
   return(sellclose);
//----
   } //-end CloseSellPositions()
//---------//

在 ExpertActionTrade() 函数的一部分:

if(Close_by_Opps==Yes && mc.xob[x]>0) mc.CloseBuyPositions(symbol);

bool MCEA::CloseBuyPositions(const string symbol)
   {
 //---
    //--
    ResetLastError();
    bool buyclose=false;
    int total=PositionsTotal(); // number of open positions
    ENUM_POSITION_TYPE closetype = POSITION_TYPE_BUY;
    ENUM_ORDER_TYPE     type_req = ORDER_TYPE_SELL;
    //--
    MqlTradeRequest req={};
    MqlTradeResult  res={};
    MqlTradeCheckResult check={};
    //--
    int x=PairsIdxArray(symbol);
    //--- iterate over all open positions
    for(int i=total-1; i>=0; i--)
      {
        if(mc_position.SelectByIndex(i))
          {
            //--- Parameters of the order
            string position_Symbol   = PositionGetSymbol(i);
            ulong  position_ticket   = PositionGetTicket(i);
            ENUM_POSITION_TYPE  type = mc_position.PositionType();
            //--- if the MagicNumber matches
            if((position_Symbol==symbol) && (mc_position.Magic()==magicEA))
              { 
                //--
                if(type==closetype)
                  {
                    RefreshTick(position_Symbol);
                    buyclose=mc_trade.PositionClose(position_Symbol,slip);
                    //--- output information about the closure
                    PrintFormat("Close Buy #%I64d %s %s",position_ticket,position_Symbol,EnumToString(type));
                  }
              }
          }
      }
   //---
   return(buyclose);
//----
   } //-end CloseBuyPositions()
//---------//


如果”由反向信号平仓(否)“将出现问题:

1. 订单将是每对已交易总数的 2 倍。

2. 在一对中,会有处于亏损状态的订单,也有处于盈利状态的订单。

3. 由于亏损和盈利条件不平衡,净值将会消减。

为了克服这个问题,我创建了几个函数来检测亏损和盈利订单条件。

在 ExpertActionTrade() 函数的一部分:

            //--
            mc.CheckOpenPMx(symbol);
            if(Close_by_Opps==No && (mc.xob[x]+mc.xos[x]>1))
              {
                if(mc.CheckProfitLoss(symbol))
                   mc.Do_Alerts(symbol,"Close order due stop in loss.");
              }
            //--

bool MCEA::CheckProfitLoss(const string symbol)
   {
//----
     ResetLastError();
     //--
     bool closeinloss=false;
     string isloss="due stop in loss.";
     //--
     int xx=PairsIdxArray(symbol);
     //--
     bool BuyProfitSellLoss=(xob[xx]>0 && CheckProfit(symbol,POSITION_TYPE_BUY)) && (xos[xx]>0 && CheckLoss(symbol,POSITION_TYPE_SELL,0.0));
     bool SellProfitBuyLoss=(xos[xx]>0 && CheckProfit(symbol,POSITION_TYPE_SELL)) && (xob[xx]>0 && CheckLoss(symbol,POSITION_TYPE_BUY,0.0));
     //--
     if(BuyProfitSellLoss && !SellProfitBuyLoss)
       {
         if(CloseSellPositions(symbol))
           {
             PrintFormat("Close Sell %s %s %s",symbol,EnumToString(POSITION_TYPE_BUY),isloss);
             closeinloss=true;
           }
       }
     if(SellProfitBuyLoss && !BuyProfitSellLoss)
       {
         if(CloseBuyPositions(symbol))
           {
             PrintFormat("Close Buy %s %s %s",symbol,EnumToString(POSITION_TYPE_SELL),isloss);
             closeinloss=true;
           }
       }
     //--
     return(closeinloss);
//----
   } //-end CheckProfitLoss()
//---------//


CheckProfitLoss() 函数将调用另外 2 个函数,这些函数将按条件比较一对的订单:买入盈利和卖出亏损,或买入亏损和卖出盈利。

  • 如果买入盈利且卖出亏损,则卖出订单将被平仓。
  • 如果卖出亏损且卖出盈利,则买入订单将被平仓。

bool MCEA::CheckProfit(const string symbol,ENUM_POSITION_TYPE intype)
   {
//---
     Pips(symbol);
     double posprofit=mc_symbol.NormalizePrice((TPval*0.5)*pip);
     bool inprofit=false;
     //--
     int ttlorder=PositionsTotal(); // number of open positions
     //--
     for(int x=0; x<arrsymbx; x++)
       {
         string symbol=DIRI[x];
         //--
         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 price     = mc_position.PriceCurrent();
                  double pos_open  = mc_position.PriceOpen();
                  double posprofit = mc_symbol.NormalizePrice((TPval*0.5)*pip);
                  double pricegab  = mc_symbol.NormalizePrice(fabs(price-pos_open));
                  //---
                  if(type==intype && posprofit<pricegab) inprofit=true;
                }
            }
       }
     //--
     return(inprofit);
//----
   } //-end CheckProfit()
//---------//

bool MCEA::CheckLoss(const string symbol,ENUM_POSITION_TYPE intype,double slc=0.0)
   {
//---
     Pips(symbol);
     bool inloss=false;
     double lossval=slc==0.0 ? (SLval*0.5) : slc;
     double posloss  = mc_symbol.NormalizePrice(slc*pip);
     int ttlorder=PositionsTotal(); // number of open positions
     //--
     for(int x=0; x<arrsymbx; x++)
       {
         string symbol=DIRI[x];
         //--
         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 price    = mc_position.PriceCurrent();
                  double pos_open = mc_position.PriceOpen();
                  double posloss  = mc_symbol.NormalizePrice(lossval*pip);
                  double pricegab = mc_symbol.NormalizePrice(fabs(price-pos_open));
                  //---
                  if(type==intype && pricegab>posloss) inloss=true;
                }
            }
       }
     //--
     return(inloss);
//----
   } //-end CheckLoss()
//---------//


4. 手工订单管理。

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

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

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

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


所用时区的枚举

//--
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
    byHiLo   // Trailing Stop in HIGH or LOW bar
  };
//--


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

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


从之字折线指标中选择信号算法的枚举

//--
enum SignalZZ
 {
   SZZ1,  // ZigZagSignal 1
   SZZ2,  // ZigZagSignal 2
   SZZ3,  // ZigZagSignal 3
   SZZ4   // ZigZagSignal 4
 };
//--


从 AO 指标中选择信号算法的枚举

//--
enum SignalAO
 {
   SAO1,  // AOSignal 1
   SAO2,  // AOSignal 2
   SAO3   // AOSignal 3
 };
//--


智能系统输入属性

//---
input group               "=== Global Strategy EA Parameter ==="; // Global Strategy EA Parameter
input TFUSE               tfinuse = TFH4;             // Select Expert TimeFrame, default PERIOD_H4
//---
input group               "=== ZigZag Indicator Input Properties ===";  // ZigZag Indicator Input Properties
input int                 zzDepth = 12;               // Input ZigZag Depth, default 12
input int                 zzDevia = 5;                // Input ZigZag Deviation, default 5
input int                 zzBackS = 3;                // Input ZigZag Back Step, default 3
input SignalZZ              sigzz = SZZ2;             // Select ZigZag Signal to Use
input SignalAO              sigao = SAO2;             // Select AO Signal to Use
//---
input group               "=== Selected 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              TrailingSL = Yes;              // Use Trailing Stop Loss (Yes) or (No)
input TrType               trlby = byHiLo;           // 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 YN              TrailingTP = Yes;              // Use Trailing Take Profit (Yes) or (No)
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)
input YN              CheckVSLTP = Yes;              // Check Virtual SL/TP & Close Loss Trade (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 = 20240218;         // Expert ID (Magic Number)
//---

注意:如果智能系统 ID(魔幻数字)的输入属性留空,EA 就能够管理手工开立的订单。


在全局策略 EA 参数输入属性组中,交易者被引导选择智能系统时间帧来计算指标信号,默认为 PERIOD_H4。

在智能系统的“选择交易对”属性组中,交易者需要从提供的 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()
//---------//

注意:智能系统将验证每一对。如果交易者在输入货币对名称时出错(拼写错误),或者货币对验证失败,智能系统将收到警告,且智能系统将从图表中移除。


在智能系统输入属性组"按指定时间交易"中,交易者将在此处选择“按指定时间交易(是)或(否)"。

如果"按指定时间交易" 选项指定为“否,则智能系统会在 MT5 的 00:15 至 23:59 之间进行交易。

如果“是”,选择枚举选项:

  • 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(在美国纽约时段交易)

默认情况下,"在指定时段交易"设置为“是”,并设置为"在自定义时段交易"。

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

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


2. 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              GetIndiSignals(const string symbol);
    int              ZigZagSignal(const string symbol);
    int              AOSignal(const string symbol);
    int              AOColorSignal(const string symbol);
    int              PARSAR05(const string symbol);
    int              PARSAR15(const string symbol);
    int              LotDig(const string symbol);
    //--
    double           MLots(const string symbx);
    double           NonZeroDiv(double val1,double val2);
    double           OrderSLSet(const string xsymb,ENUM_ORDER_TYPE type,double atprice);
    double           OrderTPSet(const string xsymb,ENUM_ORDER_TYPE type,double atprice);
    double           SetOrderSL(const string xsymb,ENUM_POSITION_TYPE type,double atprice);
    double           SetOrderTP(const string xsymb,ENUM_POSITION_TYPE type,double atprice);
    double           TSPrice(const string xsymb,ENUM_POSITION_TYPE ptype,int TS_type);
    //--
    string           ReqDate(int d,int h,int m);
    string           TF2Str(ENUM_TIMEFRAMES period);
    string           timehr(int hr,int mn);
    string           TradingDay(void);
    string           AccountMode();
    string           GetCommentForOrder(void)             { return(expname); }
    //------------

    public:
    //---
    
    //-- ZigZag_AO_MCEA Config --
    string           DIRI[],
                     AS30[],
                     VSym[];
    string           SPC[];
    string           USD[];
    string           EUR[];
    string           GBP[];
    string           AUD[];
    string           NZD[];
    string           CAD[];
    string           CHF[];
    string           JPY[];             
    //--                 
    string           expname;
    string           indiname1;
    //--
    //--- Indicators Handle
    int              hZigZag[],
                     hAO[];
    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     ZigZag_AO_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             UpdatePrice(const string symbol,ENUM_TIMEFRAMES xtf,int bars);
    void             RefreshPrice(const string symbx,ENUM_TIMEFRAMES xtf,int bars);
    //--
    bool             CheckEquityBalance(void);
    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             ModifyOrdersSL(const string symbx,int TS_type);
    bool             ModifyOrdersTP(const string symbx);
    bool             CloseAllProfit(void);
    bool             CloseAllLoss(void);
    bool             ManualCloseAllProfit(void);
    bool             CheckProfitLoss(const string symbol);
    bool             CloseBuyPositions(const string symbol);
    bool             CloseSellPositions(const string symbol);
    bool             CheckProfit(const string symbol,ENUM_POSITION_TYPE intype);
    bool             CheckLoss(const string symbol,ENUM_POSITION_TYPE intype,double slc=0.0);
    //--
    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() 调用的,其为 ZigZag_AO_MCEA_Config()。

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


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

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

//+------------------------------------------------------------------+
//| Expert Configuration                                             |
//+------------------------------------------------------------------+
void MCEA::ZigZag_AO_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++) 
      {
        hZigZag[x] = iCustom(DIRI[x],TFt,indiname1,zzDepth,zzDevia,zzBackS);   //-- Handle for the ZigZag indicator
        hAO[x]     = iAO(DIRI[x],TFt);                                         //-- Handle for the Awesome_Oscillator 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
        //--
      }
    //--
    TesterHideIndicators(true);
    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 ZigZag_AO_MCEA_Config()
//---------//


3. 智能系统即刻报价函数和工作流程

在智能系统的即刻报价函数 OnTick() 中,我们将调用多币种智能系统的最重要函数之一,即 ExpertActionTrade() 函数。

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


EA 的整个交易过程都包含在这个函数当中。

这意味着 ExpertActionTrade() 函数将执行所有活动,并管理自动交易,从开单、平单、尾随止损或止盈、以及其它附加活动。

void MCEA::ExpertActionTrade(void)
  {
//---
    //--Check Trading Terminal
    ResetLastError();
    //--
    if(!MQLInfoInteger(MQL_TRADE_ALLOWED) && mc.checktml==0) //-- Check whether MT5 Algorithmic trading is Allow or Prohibit
      {
        mc.Do_Alerts(Symbol(),"Trading Expert at "+Symbol()+" are NOT Allowed by Setting.");
        mc.checktml=1;  //-- Variable checktml is given a value of 1, so that the alert is only done once.
        return;
      }
    //--
    if(!DisplayManualButton("M","C","R")) DisplayManualButton(); //-- Show the expert manual button panel
    //--
    if(trade_info_display==Yes) mc.TradeInfo(); //-- Displayed Trading Info on Chart
    //---
    //--
    int mcsec=mc.ThisTime(mc.sec); 
    //--
    if(fmod((double)mcsec,5.0)==0) mc.ccur=mcsec;
    //--
    if(mc.ccur!=mc.psec)
      {
        string symbol;
        //-- Here we start with the rotation of the name of all symbol or pairs to be traded
        for(int x=0; x<mc.arrsymbx && !IsStopped(); x++) 
          {
            //--
            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
                          mc.CloseAllProfit();
                        //--
                        if(mc.xos[x]>0 && use_sl==No && CheckVSLTP==Yes)
                          {
                            if(mc.CheckLoss(symbol,POSITION_TYPE_SELL,SLval)) 
                              if(mc.CloseSellPositions(symbol))
                                mc.Do_Alerts(symbol,"Check Profit Trade and Close order due stop in loss.");
                          }
                      }
                  }
                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
                          mc.CloseAllProfit();
                        //--
                        if(mc.xob[x]>0 && use_sl==No && CheckVSLTP==Yes)
                          {
                            if(mc.CheckLoss(symbol,POSITION_TYPE_BUY,SLval)) 
                              if(mc.CloseBuyPositions(symbol))
                                mc.Do_Alerts(symbol,"Check Profit Trade and Close order due stop in loss.");
                          }
                      }
                  }
              }
            //--
            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(TrailingSL==Yes) mc.ModifyOrdersSL(symbol,trlby); //-- Use Trailing Stop Loss (Yes)
                if(TrailingTP==Yes) mc.ModifyOrdersTP(symbol);       //-- Use Trailing Take Profit (Yes)
              }
            //--
            mc.CheckOpenPMx(symbol);
            if(Close_by_Opps==No && (mc.xob[x]+mc.xos[x]>1))
              {
                if(mc.CheckProfitLoss(symbol))
                   mc.Do_Alerts(symbol,"Close order due stop in loss.");
              }
            //--
            if(use_sl==No && CheckVSLTP==Yes)
              {
                if(!mc.CheckEquityBalance())
                  if(mc.CloseAllLoss())
                    mc.Do_Alerts(symbol,"Close order due stop in loss to secure equity.");
              }
            //--
            mc.CheckClose(symbol);
          }
        //--
        mc.psec=mc.ccur;
      }
    //--
    return;
//---
  } //-end ExpertActionTrade()
//---------//


同时,”交易日开/关”属性组允许交易者在周日至周六的特定日期进行交易。这允许交易者设置“是”或“否”选项来启用或禁用智能系统在特定日期进行交易。

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

"交易日开/关"执行如下:

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

注意:"交易日开/关"条件将显示在图表上的交易信息当中。

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

交易者可以在智能系统的“在指定时间交易”属性组中选择按时区进行交易。

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


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

如果 Trade_session() 为 true,则 EA 工作流程将继续进行,直到完成;但如果为 false,则 EA 将执行任务“由于疲软信号平仓并保障盈利(是)”,以及“尾随止损(是)”。

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


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

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

int MCEA::GetOpenPosition(const string symbol) // Signal Open Position 
  {
//---
    int ret=0;
    int rise=1,
        down=-1;
    //--
    int ZZAOSignal=GetIndiSignals(symbol);
    int dirmove=DirectionMove(symbol,TFt);
    int psar15=PARSAR15(symbol);
    //--
    if(ZZAOSignal==rise && dirmove==rise && psar15==rise) ret=rise;
    if(ZZAOSignal==down && dirmove==down && psar15==down) ret=down;
    //--
    return(ret);
//---
  } //-end GetOpenPosition()
//---------//

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

  1. GetIndiSignals(symbol)
  2. DirectionMove(symbol,TFt)
  3. PARSAR15(symbol)

4.1. GetIndiSignals(symbol) 函数将调用 2 个函数:

  1. ZigZagSignal(symbol)
  2. AOSignal(symbol)

4.1.1. 之字折线信号

在 ZigZagSignal() 函数中,我们使用并调用 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() 函数获取所请求品种的名称,及其指标句柄。然后调用相应的指标句柄,从该时间帧获取之字折线指标的缓冲区值。

    //-- Indicators handle for all symbol
    for(int x=0; x<arrsymbx; x++) 
      {
        hZigZag[x] = iCustom(DIRI[x],TFt,indiname1,zzDepth,zzDevia,zzBackS);   //-- Handle for the ZigZag indicator
        hAO[x]     = iAO(DIRI[x],TFt);                                         //-- Handle for the Awesome_Oscillator 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
        //--
      }
    //--


如此,为了获得之字折线指标的缓冲区值,我们将从之字折线指标句柄中复制每个缓冲区。

为了将之字折线缓冲区(缓冲区 0)从之字折线指标句柄复制到目标数组:

CopyBuffer(hZigZag[x],0,0,barcalc,ZZBuffer);

除此之外,它还将调用 UpdatePrice() 函数来获取最高价和最低价,其将用于获取之字折线缓冲区的最高和最低柱线位置。

void MCEA::UpdatePrice(const string symbol,ENUM_TIMEFRAMES xtf)
  {
//---
    //--
    ArrayFree(OPEN);
    ArrayFree(HIGH);
    ArrayFree(LOW);
    ArrayFree(CLOSE);
    ArrayFree(TIME);
    //--
    ArrayResize(OPEN,arper,arper);
    ArrayResize(HIGH,arper,arper);
    ArrayResize(LOW,arper,arper);
    ArrayResize(CLOSE,arper,arper);
    ArrayResize(TIME,arper,arper);
    //--
    ArraySetAsSeries(OPEN,true);
    ArraySetAsSeries(HIGH,true);
    ArraySetAsSeries(LOW,true);
    ArraySetAsSeries(CLOSE,true);
    ArraySetAsSeries(TIME,true);
    //--
    ArrayInitialize(OPEN,0.0);
    ArrayInitialize(HIGH,0.0);
    ArrayInitialize(LOW,0.0);
    ArrayInitialize(CLOSE,0.0);
    ArrayInitialize(TIME,0);    
    //--
    RefreshPrice(symbol,xtf,arper);
    //--
    int co=CopyOpen(symbol,xtf,0,arper,OPEN);
    int ch=CopyHigh(symbol,xtf,0,arper,HIGH);
    int cl=CopyLow(symbol,xtf,0,arper,LOW);
    int cc=CopyClose(symbol,xtf,0,arper,CLOSE);
    int ct=CopyTime(symbol,xtf,0,arper,TIME);
   //--
   return;
//---
  } //-end UpdatePrice()
//---------//

为了获得之字折线最高和最低柱线位置,我们进行迭代,并与最高价和最低价进行比较。

    //--
    for(int i=barcalc-1; i>=0; i--)
      {
        if(ZZBuffer[i]==HIGH[i]) ZH=i;
        if(ZZBuffer[i]==LOW[i])  ZL=i;
      }
    //--

在获得之字折线高点(ZH)和之字折线低点(ZL)的柱线位置后,它只取决于在属性输入中选择的信号之字折线指标选项。

完整的 ZigZagSignal() 函数如下:

int MCEA::ZigZagSignal(const string symbol) // ZigZag Signal for Open Position
  {
//---
    int ret=0;
    int rise=1,
        down=-1;
    int ZH=-1,
        ZL=-1;
    int barcalc=100;
    bool ZZrise=false;
    bool ZZdown=false;
    //--
    double ZZBuffer[];
    ArrayResize(ZZBuffer,barcalc,barcalc);
    ArraySetAsSeries(ZZBuffer,true);
    //--  
    int x=PairsIdxArray(symbol);
    UpdatePrice(symbol,TFt);
    //--    
    CopyBuffer(hZigZag[x],0,0,barcalc,ZZBuffer);
    //--
    for(int i=barcalc-1; i>=0; i--)
      {
        if(ZZBuffer[i]==HIGH[i]) ZH=i;
        if(ZZBuffer[i]==LOW[i])  ZL=i;
      }
    //--
    switch(sigzz)
      {
        case SZZ1:
          {
            ZZrise=((ZH==0 && HIGH[0]>HIGH[1])||(ZL<ZH && ZL>1));
            ZZdown=((ZL==0 && LOW[0]<LOW[1])||(ZH<ZL && ZH>1));
            //--
            break;
          }
        case SZZ2:
          {
            ZZrise=(ZL<ZH && ZL>1);
            ZZdown=(ZH<ZL && ZH>1);
            //--
            break;
          }
        case SZZ3:
          {
            ZZrise=((ZH==0 && HIGH[0]>HIGH[1])||(ZL<ZH && ZL>0));
            ZZdown=((ZL==0 && LOW[0]<LOW[1])||(ZH<ZL && ZH>0));
            //--
            break;
          }
        case SZZ4:
          {
            ZZrise=(ZL<ZH && ZL>0);
            ZZdown=(ZH<ZL && ZH>0);
            //--
            break;
          }
      };
    //--
    if(ZZrise) ret=rise;
    if(ZZdown) ret=down;
    //--
    return(ret);
//---
  } //-end ZigZagSignal()
//---------//


4.1.2. AO 信号

就像在 ZigZagSignal() 函数中一样,在 AOSignal() 函数中,我们也必须调用 PairsIdxArray() 函数,以便从 AO 指标获取缓冲区值。

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

为了将 AO 缓冲区(缓冲区 0)从 AO 指标句柄复制到目标数组:

CopyBuffer(hAO[x],0,0,barcalc,AOValue);

然后它只取决于在属性输入中选择的信号 AO 指标选项。

除此之外,为了完成来自 AO 指标的信号,我们还使用 AO 指标的颜色来验证来自缓冲区值的信号。

为此目的,我们创建了一个名为 AOColorSignal() 的函数来获取 AO 指标的颜色值

在该函数中,我们将从 AO 指标复制缓冲区 1(指标颜色索引缓冲区)。

CopyBuffer(hAO[x],1,0,barcalc,AOColor);
int MCEA::AOColorSignal(const string symbol)
  {
//---
    int ret=0;
    int rise=1,
        down=-1;
    int barcalc=9;
    //--
    double AOColor[];
    ArrayResize(AOColor,barcalc,barcalc);
    ArraySetAsSeries(AOColor,true);
    //--
    int x=PairsIdxArray(symbol);
    UpdatePrice(symbol,TFt,barcalc);
    //--
    CopyBuffer(hAO[x],1,0,barcalc,AOColor);
    //--
    bool AORise=((AOColor[1]==1.0 && AOColor[0]==0.0)||(AOColor[1]==0.0 && AOColor[0]==0.0));
    bool AODown=((AOColor[1]==0.0 && AOColor[0]==1.0)||(AOColor[1]==1.0 && AOColor[0]==1.0));
    //--
    if(AORise) ret=rise;
    if(AODown) ret=down;
    //--
    return(ret);
//---
  } //-end AOColorSignal()
//---------//

完整的 AOSignal() 函数如下:

int MCEA::AOSignal(const string symbol)
  {
//---
    int ret=0;
    int rise=1,
        down=-1;
    int barcalc=9;
    bool AORValue=false;
    bool AODValue=false;
    //--
    double AOValue[];
    ArrayResize(AOValue,barcalc,barcalc);
    ArraySetAsSeries(AOValue,true);
    //--
    int x=PairsIdxArray(symbol);
    UpdatePrice(symbol,TFt,barcalc);
    //--
    CopyBuffer(hAO[x],0,0,barcalc,AOValue);
    //--
    switch(sigao)
      {
        case SAO1:
          {
            AORValue=(AOValue[2]<=0.0 && AOValue[1]>0.0 && AOValue[0]>AOValue[1])||(AOValue[1]>AOValue[2] && AOValue[0]>AOValue[1]);
            AODValue=(AOValue[2]>=0.0 && AOValue[1]<0.0 && AOValue[0]<AOValue[1])||(AOValue[1]<AOValue[2] && AOValue[0]<AOValue[1]);
            //--
            break;
          }
        case SAO2:
          {
            AORValue=(AOValue[1]<=0.0 && AOValue[0]>0.0)||(AOValue[0]>0.0 && AOValue[0]>AOValue[1]);
            AODValue=(AOValue[1]>=0.0 && AOValue[0]<0.0)||(AOValue[0]<0.0 && AOValue[0]<AOValue[1]);
            //--
            break;
          }
        case SAO3:
          {
            AORValue=(AOValue[1]<=0.0 && AOValue[0]>0.0)||(AOValue[0]>AOValue[1]);
            AODValue=(AOValue[1]>=0.0 && AOValue[0]<0.0)||(AOValue[0]<AOValue[1]);
            //--
            break;
          }
      };
    //--
    bool AORise=(AOColorSignal(symbol)==rise);
    bool AODown=(AOColorSignal(symbol)==down);
    //--
    if(AORValue && AORise) ret=rise;
    if(AODValue && AODown) ret=down;
    //--
    return(ret);
//---
  } //-end AOSignal()
//---------//


GetIndiSignals() 函数将 ZigZagSignal() 函数和 AOSignal() 函数的返回值相加。

int MCEA::GetIndiSignals(const string symbol) // Get Signal for Open Position 
  {
//---
    int ret=0;
    int rise=1,
        down=-1;
    int sigrise=2;
    int sigdown=-2;
    //--
    int ZZSignal=ZigZagSignal(symbol);
    int AwSignal=AOSignal(symbol);
    //Print(symbol+" = ZZ="+string(ZZSignal)+" AO="+string(AwSignal)+" Signal="+string(ZZSignal+AwSignal));
    //--
    if(ZZSignal+AwSignal==sigrise) ret=rise;
    if(ZZSignal+AwSignal==sigdown) ret=down;
    //--
    return(ret);
//---
  } //-end GetIndiSignals()
//---------//        


GetIndiSignals() 函数将 ZigZagSignal() 函数和 AOSignal() 函数的返回值相加。

  • 若结果为 2,则为买入信号。
  • 若结果为 -2,则为卖出信号。

4.2. DirectionMove 函数。

DirectionMove() 函数对于获取当前柱线的收盘价位置很实用,无论是高于开盘价(上涨)、亦或低于开盘价(下跌)。

int MCEA::DirectionMove(const string symbol,const ENUM_TIMEFRAMES stf) // Bar Price Direction 
  {
//---
    int ret=0;
    int rise=1,
        down=-1;
    //--
    Pips(symbol);
    double difud=mc_symbol.NormalizePrice(1.5*pip);
    UpdatePrice(symbol,stf,2);
    //--
    if(CLOSE[0]>OPEN[0]+difud) ret=rise;
    if(CLOSE[0]<OPEN[0]-difud) ret=down;
    //--
    return(ret);
//---
  } //-end DirectionMove()
//---------//


4.3. PARSAR15() 函数。

PARSAR15() 函数可将之字折线指标和 AO 指标的移动与 M15 时间帧上的抛物线 SAR 指标(PSAR/iSAR) 对齐。

int MCEA::PARSAR15(const string symbol) // formula Parabolic SAR M15
  {
//---
   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);
   //--
   UpdatePrice(symbol,TFT15,br);
   //--
   if(PSAR[0]<LOW[0])
      ret=rise;
   if(PSAR[0]>HIGH[0])
      ret=down;
//--
   return(ret);
//---
  } //-end PARSAR15()
//---------//


在执行了 3 个主要信号函数和若干个支持函数之后,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
//---------//


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

在输入属性的“其它智能系统参数”组中,交易者有机会选择是否在图表上显示交易信息“是”、或“否”。

如果选项选择“是”,则交易信息将通过调用 TradeInfo() 函数显示在加载智能系统的图表上。

作为 TradeInfo() 函数的一部分,我们还添加了一个函数,根据交易时区条件描述时间。

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


然后多货币智能系统 ZigZag_AO_MCEA 界面类似于下图。

ZZ_AO_MCEA_Look


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

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

Expert_manual_button_01

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

5.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
//---------//


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


5.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 按钮将从图表中删除多货币智能交易系统 ZigZag_AO_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 策略测试器平台上,我们将测试 ZigZag_AO_MCEA 多货币智能交易系统。

在测试中,我们将 ZigZag_AO_MCEA 放在 XAUUSD 货币对和 H4 时间帧上,自定义时间段为 2023.10.01 至 2024.02.17。

ZZ_AO_ST_input

 结果如下图所示。

ZZ_AO_ST_result


ZZ_AO_ST_result_graph_01

ZZ_AO_ST_result_graph_02

ZZ_AO_ST_result_graph_03

ZZ_AO_ST_result_graph_04


结束语

依据来自之字折线指标的信号创建多货币智能系统,这些信号运用动量振荡器过滤,或过滤彼此的信号,从而利用 MQL5 进行外汇交易,结局如下:

  1. 事实证明,在 MQL5 中创建多货币智能系统非常简单,与创建单一货币智能系统没有太大区别,其中多货币智能系统也可以当作单一货币智能系统。
  2. 创建多币种智能交易系统将消除打开太多品种图表进行交易的需要,从而提高交易者的效率和有效性。
  3. 与使用单一货币的智能交易系统相比,应用正确的交易策略将增加获利的可能性。这是因为一个货币对的损失能由其它货币对的盈利所弥补。
  4. 这个 ZigZag_AO_MCEA 多币种智能系统只是一个学习和实现思路的示例。其在策略测试器当中的测试结果仍然不佳。因此,通过在不同的时间帧、或不同的指标周期计算上进行实验和测试,并选择不同的信号,可以获得更好的策略和更有利可图的结果。
  5. 在我看来,这个依据 AO 指标的之字折线策略应该通过各种不同的实验进一步研究,从时间帧开始,之字折线指标参数输入的区分值,也许您还可以为之子折线指标和 AO 指标添加其它算法信号。
  6. 根据我在策略测试器上的实验结果,在 H1 以下的时间帧上,大量开仓,结果并不好;与之相比,在 H1 及以上的时间帧上,少量开仓,结果略好,但仍亏损。

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

感谢您的阅读。

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

附加的文件 |
ZigZag_AO_MCEA.mq5 (123.74 KB)
可视化交易图表(第二部分):数据图形化展示 可视化交易图表(第二部分):数据图形化展示
接下来,我们将从头开始编写一个脚本,以简化交易订单截图的加载过程,便于分析交易入场点。所有关于单个交易的必要信息都将方便地显示在一个图表上,并且该图表具备绘制不同时间框架的能力。
为 Metatrader 5 开发 MQTT 客户端:TDD 方法 - 第 6 部分 为 Metatrader 5 开发 MQTT 客户端:TDD 方法 - 第 6 部分
本文是介绍我们针对 MQTT 5.0 协议的本地 MQL5 客户端的开发步骤的系列文章的第六部分。在本部分中,我们会讨论我们第一次重构中的主要变化,我们如何为我们的数据包构建类得出可行的蓝图,我们如何构建 PUBLISH 和 PUBACK 数据包,以及 PUBACK 原因代码背后的语义。
在MQL5中开发马丁格尔(Martingale)区域恢复策略 在MQL5中开发马丁格尔(Martingale)区域恢复策略
本文详细探讨了创建基于区域恢复交易算法的EA需要实施的步骤。这有助于自动化该系统,从而为算法交易者节省时间。
神经网络实践:最小二乘法 神经网络实践:最小二乘法
在本文中,我们将探讨一些想法,包括数学公式在外观上怎么会比用代码实现时更复杂。此外,我们还将考虑如何设置图表的象限,以及 MQL5 代码中可能出现的一个有趣问题。不过,说实话,我还是不太明白该如何解释。总之,我会告诉你如何用代码解决这个问题。