文章 "通用EA交易:与MetaTrader的标准信号模块集成 (第7部分)" - 页 3

 
Amy Liu:

感谢瓦西里的贡献。我学到了很多。我下载了所有代码,但在 Panel.mqh 文件中出现了编译错误:

At' - object pointer expected Panel.mqh 210 39

At' - 预期对象指针 Panel.mqh 228 37

能否请您检查一下?


嗨,艾米。我刚刚读完Vasiliy Sokolov 的文章。如果您仍有兴趣找到解决方案。请在此发布错误日志。我记得我遇到过这个错误,并意识到 StrategiesList 文件的声明中有一个".\Panel\Panel.mqh"。 Panel.mqh 并不存在。请尝试访问https://www.mql5.com/zh/articles/2411 并从那里下载 Panel 文件。我相信那里有 Panel.mqh 文件。

Vasiliy 的这个系列作为一个框架真的很不错。我也学到了很多东西,但当一个库出现问题时,如果作者不提供支持,如果你不是一个优秀的程序员,你可能就会被困住。这正是Alain Verleyen 在你们的其他讨论中提出的观点。但是,那些花时间在这里分享他们的知识和技能的人真是了不起。我永远心存感激。

Universal Expert Advisor: A Custom Trailing Stop (Part 6)
Universal Expert Advisor: A Custom Trailing Stop (Part 6)
  • 2016.06.16
  • Vasiliy Sokolov
  • www.mql5.com
The sixth part of the article about the universal Expert Advisor describes the use of the trailing stop feature. The article will guide you through how to create a custom trailing stop module using unified rules, as well as how to add it to the trading engine so that it would automatically manage positions.
 

这个引擎非常棒,谢谢你。这是我决定改用的第一个 OOP MQL5 引擎。

但不幸的是,Manager.OnTick() 运行速度非常慢。跟踪显示几乎 100%。在一分钟的时间范围内和使用 OHLC M1 时,测试速度非常慢。3 年来 - 约 50 秒。同时,Expert Advisor 本身不做任何测试,我已经注释掉了加载它的所有内容。也就是说,它只是搜索条形图。

我真的很想优化 Manager.OnTick() 中的代码

 
Edgar:

这个引擎非常棒,谢谢你。这是我决定改用的第一个 OOP MQL5 引擎。

但不幸的是,Manager.OnTick() 运行速度非常慢。跟踪显示几乎 100%。在一分钟的时间范围内和使用 OHLC M1 时,测试速度非常慢。3 年来 - 约 50 秒。同时,Expert Advisor 本身不做任何测试,我已经注释掉了加载它的所有内容。也就是说,它只是搜索条形图。

我真的很想优化 Manager.OnTick() 中的代码


这是启动其他一切的函数--当然,它将是 100% 的。看看里面都花了哪些时间,然后对其进行优化。您可以发布截图。

 
Edgar:

这个引擎非常棒,谢谢你。这是我决定改用的第一个 OOP MQL5 引擎。

但不幸的是,Manager.OnTick() 运行速度非常慢。跟踪显示几乎 100%。在一分钟的时间范围内和使用 OHLC M1 时,测试速度非常慢。3 年来 - 约 50 秒。同时,Expert Advisor 本身不做任何测试,我已经注释掉了加载它的所有内容。也就是说,它只是搜索条形图。

我真的想优化 Manager.OnTick() 中的代码

这里没有什么令人惊讶的。这个速度与策略测试器的空闲运行速度相当。OnTick 决定一个新的刻度线的出现和一个新的条形图的打开。这些操作不需要大量资源。

 

你好,瓦西里。

感谢您的所有文章。

就复杂性和软件架构而言,Universal Expert Advisor 确实令人印象深刻。

对于这个特殊版本,我想在这段代码中提出一个问题:

CAdapterMACD::CAdapterMACD(void)
{
   m_params.symbol = Symbol();
   m_params.period = Period();
   m_params.every_tick = false;
   m_params.signal_type = SIGNAL_MACD;
   m_params.magic = 1234;
   m_params.point = 1.0;
   m_params.usage_pattern = 2;
   CSignalMACD* macd = m_signal.CreateSignal(m_params);
   macd.PeriodFast(15);
   macd.PeriodSlow(32);
   macd.PeriodSignal(6);
}

请注意,在创建信号后,我们通过设置自己的 MACD 指标周期(15、32、6)继续对其进行配置。这很容易做到,因为 CreateSignal 方法已经返回了相应的对象。

实际上,MacD 参数(15、32 和 6)在这里不起作用,因为 CreateSignal() 方法会在更新参数之前初始化 MacD 信号。

在这种情况下,我建议将 CSignalAdapter::CreateSignal() 方法分为两部分,第一部分是创建信号并按原样返回,第二部分是在设置所有 "信号相关 "参数(本例中为 PeriodFast、PeriodSlow 和 PeriodSignal)后初始化信号:

CExpertSignal* CSignalAdapter::CreateSignal(MqlSignalParams& params)
{
   DeleteSignal();
   switch(params.signal_type)
   {
      case SIGNAL_AO:
         m_signal = new CSignalAO();
         break;
      case SIGNAL_AC:
         m_signal = new CSignalAC();
         break;
      case SIGNAL_ADAPTIVE_MA:
         m_signal = new CSignalAMA();
         break;
      case SIGNAL_CCI:
         m_signal = new CSignalCCI();
         break;
      case SIGNAL_DeMARKER:
         m_signal = new CSignalDeM();
         break;
      case SIGNAL_DOUBLE_EMA:
         m_signal = new CSignalDEMA();
         break;
      case SIGNAL_ENVELOPES:
         m_signal = new CSignalEnvelopes();
         break;
      case SIGNAL_FRAMA:
         m_signal = new CSignalFrAMA();
         break;
      case SIGNAL_MA:
         m_signal = new CSignalMA();
         break;
      case SIGNAL_MACD:
         m_signal = new CSignalMACD();
         break;
      case SIGNAL_PARABOLIC_SAR:
         m_signal = new CSignalSAR();
         break;
      case SIGNAL_RSI:
         m_signal = new CSignalRSI();
         break;
      case SIGNAL_RVI:
         m_signal = new CSignalRVI();
         break;
      case SIGNAL_STOCHASTIC:
         m_signal = new CSignalStoch();
         break;
      case SIGNAL_TRIPLE_EA:
         m_signal = new CSignalTriX();
         break;
      case SIGNAL_TRIPLE_EMA:
         m_signal = new CSignalTEMA();
         break;
      case SIGNAL_WILLIAMS_PER_RANGE:
         m_signal = new CSignalWPR();
         break;
   }
   if(CheckPointer(m_signal)!= POINTER_INVALID)
      m_params = params;
   
   return m_signal;
}

bool CSignalAdapter::Init()
{
   if(m_params.symbol == "") /* CreateSignal method should be called first in order to update m_params */
      return false;
   m_info.Name(m_params.symbol);
   if(!m_signal.Init(GetPointer(m_info), m_params.period, m_params.point))
      return false;
   if(!m_signal.InitIndicators(GetPointer(m_indicators)))
      return false;
   m_signal.EveryTick(m_params.every_tick);
   m_signal.Magic(m_params.magic);
   
   m_open.Create(m_params.symbol, m_params.period);
   m_high.Create(m_params.symbol, m_params.period);
   m_low.Create(m_params.symbol, m_params.period);
   m_close.Create(m_params.symbol, m_params.period);
   
   m_times.Create(m_params.symbol, m_params.period);
   m_spread.Create(m_params.symbol, m_params.period);
   m_tik_vol.Create(m_params.symbol, m_params.period);
   m_real_vol.Create(m_params.symbol, m_params.period);
   
   m_signal.SetPriceSeries(GetPointer(m_open), GetPointer(m_high), GetPointer(m_low), GetPointer(m_close));
   //m_signal.SetOtherSeries(GetPointer(m_spread), GetPointer(m_times), GetPointer(m_tik_vol), GetPointer(m_real_vol));
   int mask = 1;
   mask = mask << m_params.usage_pattern;
   m_signal.PatternsUsage(mask);
   return true;
}

当然,还需要调用新创建的 Init 方法:

CAdapterMACD::CAdapterMACD(void)
{
   m_params.symbol = Symbol();
   m_params.period = Period();
   m_params.every_tick = false;
   m_params.signal_type = SIGNAL_MACD;
   m_params.magic = 1234;
   m_params.point = 1.0;
   m_params.usage_pattern = 2;
   CSignalMACD* macd = m_signal.CreateSignal(m_params);
   macd.PeriodFast(15);
   macd.PeriodSlow(32);
   macd.PeriodSignal(6);
   m_signal.Init(); /* This call is going to create the CSignalMACD object with the custom parameters */
}


感谢您的出色工作,更感谢您的分享,瓦西里!


干杯

罗德里戈-哈勒

 

我再一次面对这样一个事实,那就是在实际做了一些事情之后,我发现实际上之前已经做了同样的事情(正如人们所说的那样,在我们之前已经发明了一切)。

有一点我想指出--在信号工作中,我从一开始就认为信号的加权平均值是买入和卖出的信号,这不符合典型形式的决策逻辑(决策树,这里已经提到过),我也是这么做的--信号的原生器中除了信号的实际列表外,还包含了 AND、ANDNOT、XOR 的信号槽。这些插槽的所有处理逻辑都是明确的,并且都在原生类中。也就是说,要构建一个策略,您只需将主信号添加到 Expert Advisor 中,并将信号添加到相应的逻辑槽中,原理与最初的相同,即每个逻辑槽最多可添加 64 个额外的过滤器。我认为这种解决方案最简单,也最容易实现。如果您对这个想法感兴趣,但有不明白的地方,请与我联系,我会告诉您更多。

 

如何在脚本中使用CSignalMACD 类

我试过在原处获取信号结果,但总是得到 0:

void OnStart()
{
   CSignalMACD       m_signal_macd;
   CSymbolInfo       m_info;
   CiOpen            m_open;
   CiHigh            m_high;
   CiLow             m_low;
   CiClose           m_close;
   CIndicators       m_indicators;

   m_signal_macd.Pattern_0(0);
   m_signal_macd.Pattern_1(0);
   m_signal_macd.Pattern_2(0);
   m_signal_macd.Pattern_3(100);
   m_signal_macd.Pattern_4(0);
   m_signal_macd.Pattern_5(0);
   m_info.Name(Symbol());                                  // 初始化代表策略交易符号的对象
   m_signal_macd.Init(GetPointer(m_info), Period(), 10);   // 根据交易符号和时间框架初始化信号模块
   m_signal_macd.InitIndicators(GetPointer(m_indicators)); // 根据指标空列表 m_indicators 在信号模块中创建所需的指标
   //m_signal_macd.EveryTick(true); // 测试模式
   m_signal_macd.Magic(42);                     // 神奇数字
   m_signal_macd.PatternsUsage(8);                         // 图案掩码
   m_open.Create(Symbol(), Period());                      // 初始化开放价格时间序列
   m_high.Create(Symbol(), Period());                      // 初始化高价时间序列
   m_low.Create(Symbol(), Period());                       // 初始化低价时间序列
   m_close.Create(Symbol(), Period());                     // 初始化收盘价时间序列
   m_signal_macd.SetPriceSeries(GetPointer(m_open),        // 通过时间序列对象初始化信号模块
                              GetPointer(m_high),
                              GetPointer(m_low),
                              GetPointer(m_close));
                              
   m_indicators.Refresh();
   m_signal_macd.SetDirection();
   int power_sell = m_signal_macd.ShortCondition();
   int power_buy = m_signal_macd.LongCondition();
   printf("PowerSell: " + (string)power_sell + " PowerBuy: " + (string)power_buy);
                                    
  }