求助:请教如何获取多个周期多根MACD的值

 

大家好 本人想在EA中获取1分钟到1小时多个周期前5-10根K线对应的MACD的值

尝试了将MACD指标封装成类 不知是语法错了还是思路错了 发现指标的计算似乎必须直接写在OnCalculate()事件中 否则会出现这句语句array out of range的报错 将MACD的计算代码直接放在mq5文件的OnCalculate()事件中不会报错

for(int i=limit;i<rates_total && !IsStopped();i++)

      ExtMacdBuffer[i]=ExtFastMaBuffer[i]-ExtSlowMaBuffer[i];

其次我该如何编写能够得到多个周期的MACD的值 有没有较好的思路或方案 万分谢谢


下面是目前尝试的代码 红色字体是报错对应的代码 错误为array out of range

文件 MACD.mqh


#include <MovingAverages.mqh>

// 属性

#property indicator_buffers 4

// 参数

int InpFastEMA=12;                              // Fast EMA period

int InpSlowEMA=26;                              // Slow EMA period

int InpSignalSMA=9;                             // Signal SMA period

ENUM_APPLIED_PRICE InpAppliedPrice=PRICE_CLOSE; // Applied price

// 指标缓存

double ExtMacdBuffer[];

double ExtSignalBuffer[];

double ExtFastMaBuffer[];

double ExtSlowMaBuffer[];

// MA处理

int ExtFastMaHandle;

int ExtSlowMaHandle;


// MACD

class MACD

   {

   public:

   void Init(void);

   int Calculate(const int rates_total,

                 const int prev_calculated);

   };

   

// 初始化

void MACD::Init(void)

   {

   //--- indicator buffers mapping

   SetIndexBuffer(0,ExtMacdBuffer,INDICATOR_DATA);

   SetIndexBuffer(1,ExtSignalBuffer,INDICATOR_DATA);

   SetIndexBuffer(2,ExtFastMaBuffer,INDICATOR_CALCULATIONS);

   SetIndexBuffer(3,ExtSlowMaBuffer,INDICATOR_CALCULATIONS);

   //--- get MA handles

   ExtFastMaHandle=iMA(NULL,0,InpFastEMA,0,MODE_EMA,InpAppliedPrice);

   ExtSlowMaHandle=iMA(NULL,0,InpSlowEMA,0,MODE_EMA,InpAppliedPrice);

   }


// 计算MACD

int MACD::Calculate (const int rates_total,

               const int prev_calculated)

   {

   //--- check for data

   if(rates_total<InpSignalSMA)

      return(0);

//--- not all data may be calculated

   int calculated=BarsCalculated(ExtFastMaHandle);

   if(calculated<rates_total)

     {

      Print("Not all data of ExtFastMaHandle is calculated (",calculated,"bars ). Error",GetLastError());

      return(0);

     }

   calculated=BarsCalculated(ExtSlowMaHandle);

   if(calculated<rates_total)

     {

      Print("Not all data of ExtSlowMaHandle is calculated (",calculated,"bars ). Error",GetLastError());

      return(0);

     }

//--- we can copy not all data

   int to_copy;

   if(prev_calculated>rates_total || prev_calculated<0) to_copy=rates_total;

   else

     {

      to_copy=rates_total-prev_calculated;

      if(prev_calculated>0) to_copy++;

     }

//--- get Fast EMA buffer

   if(IsStopped()) return(0); //Checking for stop flag

   if(CopyBuffer(ExtFastMaHandle,0,0,to_copy,ExtFastMaBuffer)<=0)

     {

      Print("Getting fast EMA is failed! Error",GetLastError());

      return(0);

     }

//--- get SlowSMA buffer

   if(IsStopped()) return(0); //Checking for stop flag

   if(CopyBuffer(ExtSlowMaHandle,0,0,to_copy,ExtSlowMaBuffer)<=0)

     {

      Print("Getting slow SMA is failed! Error",GetLastError());

      return(0);

     }

//---

   int limit;

   if(prev_calculated==0)

      limit=0;

   else limit=prev_calculated-1;

//--- calculate MACD

   for(int i=limit;i<rates_total && !IsStopped();i++)

      {

      ExtMacdBuffer[i]=ExtFastMaBuffer[i]-ExtSlowMaBuffer[i];

      if(i == rates_total-1)

         {

         Print("OnTick  MACD:  ", DoubleToString(ExtMacdBuffer[i]), "    Time:  ", TimeToString(TimeTradeServer(), TIME_SECONDS));//TIME_SECONDS去掉会怎样

         }

      }

//--- OnCalculate done. Return new prev_calculated.

   return(rates_total);

   }



文件 main.mq5

// 引入文件

#include <MACD.mqh>

MACD myMACD;

int OnInit()

  {

myMACD.Init();

return(INIT_SUCCEEDED);

  }

void OnDeinit(const int reason)

  {

  }

void OnTick()

  {

//---

  }

void OnTimer()

  {

//---

  }

int OnCalculate(const int rates_total,

                const int prev_calculated,

                const int begin,

                const double &price[])

  {

  myMACD.Calculate(rates_total, prev_calculated );

  }




 

自己的想法是取足够多的Close价格 如在OnTick事件中取iClose(NULL, PERIOD_M1, 0)

取到自己想要的不同周期足够多的Close价格再计算成MACD 这个思路似乎可以规避掉OnCalculate事件的限制

 

你把指标和EA的架构搞混了。

OnCalculate()是指标的主函数,OnTick()是EA的主函数,不要搞混了。

如果你希望在自己的类中实现MACD算法,那么则用CoryRates()拷贝适量的数据,然后编写MACD算法,这种做法稍微复杂。

简单做法是在EA的OnInit()中创建要指标句柄,然后在EA的OnTick()中用CopyBuffer()来拷贝相应的指标数据,这种情况下指标的实时计算是由系统负责,你不用管,比较省事。

 
//+------------------------------------------------------------------+
//|                                                 test_MACD_EA.mq5 |
//|                                           Copyright 2019,fxMeter |
//|                            https://www.mql5.com/en/users/fxmeter |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019,fxMeter"
#property link      "https://www.mql5.com/en/users/fxmeter"
#property version   "1.00"

input ENUM_TIMEFRAMES tf1 = PERIOD_M5;
input ENUM_TIMEFRAMES tf2 = PERIOD_H1;

int handle1,handle2;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
    handle1 = CreateMacdHandle(tf1);
    handle2 = CreateMacdHandle(tf2);    
    if(handle1==INVALID_HANDLE || handle2==INVALID_HANDLE)
    {
      printf("Error creating MACD indicator");
      return(INIT_FAILED);
    }
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
      if(handle1!=INVALID_HANDLE)IndicatorRelease(handle1);
      if(handle2!=INVALID_HANDLE)IndicatorRelease(handle2);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
      double macd[];
      ArraySetAsSeries(macd,true);
      
      //---拷贝handle1的数据,即tf1的MACD数据,5个
      int index = 0; //buffer index, 0 - MAIN_LINE, 1 - SIGNAL_LINE.      
      if(CopyBuffer(handle1,index,0,5,macd)!=5)return;
      //...
      Comment(macd[0]);
      
      //---拷贝handle2的数据,即tf2的MACD数据,5个
      if(CopyBuffer(handle2,index,0,5,macd)!=5)return;
      //...  
  }
//+------------------------------------------------------------------+

int CreateMacdHandle(ENUM_TIMEFRAMES tf)
{
  int handle =-1;
  handle =iMACD(NULL,tf,12,26,9,PRICE_CLOSE);
  return(handle);
}
 
Ziheng Zhuang:
非常感谢 这样简单多了 还有个问题要麻烦问一下 我如果想创建一些自定义周期 比如15秒的周期(MT5里没有)或者年线周期并取MACD 那MACD的值就要用你说的第一种方法自己计算而不能用iMACD()了是吗 然后15秒周期和年线数据应该用什么方法去创建 是怎样的创建思路 我自己的思路是 小于1分钟的周期用EventSetTimer(1)计时 在OnTimer()事件里取秒级数据 组成自己的Buffer 大于月的数据用1月的数据去拼 得到年线 这样可以吗 有更好的方法吗 谢谢
 

1. 秒级别的timeframe数据你只能自己收集tick数据,参考CopyTick()...从而构造秒级别的数据。 别指望在OnTimer()收集秒的数据,因为这个timer事件并不会精确的以秒来调用。

2.年级别的timeframe数据你可以通过日线数据构造。

这两种数据你只能自己算MACD值,因为秒,年,这种非标准timeframe,无法调用iMACD()。

iMACD()之类的函数只接受标准timeframe。

另外,对于非标准timeframe,MT5不支持创建custom symbol,因而无法构成bar chart,因此也无法调用iMACD()。

MT5的API函数以及图表周期只支持标准timeframe。

 
Ziheng Zhuang:

1. 秒级别的timeframe数据你只能自己收集tick数据,参考CopyTick()...从而构造秒级别的数据。 别指望在OnTimer()收集秒的数据,因为这个timer事件并不会精确的以秒来调用。

2.年级别的timeframe数据你可以通过日线数据构造。

这两种数据你只能自己算MACD值,因为秒,年,这种非标准timeframe,无法调用iMACD()。

iMACD()之类的函数只接受标准timeframe。

另外,对于非标准timeframe,MT5不支持创建custom symbol,因而无法构成bar chart,因此也无法调用iMACD()。

MT5的API函数以及图表周期只支持标准timeframe。

感谢你的帮助 有机会请你吃个饭 我在写自己的EA 所以刚接触MQL5 虽然有一些C++的基础 但对MQL5底层的东西不了解 如何学习 似乎资料也很少 书籍也很少 看官网吗 后续还会有不少问题会请教你 有空的时候帮我看看 谢谢了
 
Ziheng Zhuang:

1. 秒级别的timeframe数据你只能自己收集tick数据,参考CopyTick()...从而构造秒级别的数据。 别指望在OnTimer()收集秒的数据,因为这个timer事件并不会精确的以秒来调用。

2.年级别的timeframe数据你可以通过日线数据构造。

这两种数据你只能自己算MACD值,因为秒,年,这种非标准timeframe,无法调用iMACD()。

iMACD()之类的函数只接受标准timeframe。

另外,对于非标准timeframe,MT5不支持创建custom symbol,因而无法构成bar chart,因此也无法调用iMACD()。

MT5的API函数以及图表周期只支持标准timeframe。

这边有一个语法上的问题 我写了个简单的例子 定义了一个结构体 在类中定义了这个结构体的数组做为私有成员 现在要通过函数返回这个结构体数组该怎么写函数返回类型和return 另外假设这个结构体数组要作为函数参数传递 该怎么写 谢谢 我试过以前学习的时候用的方法 都报错

聊两句 我是专业操盘的 10年了 我看到你的介绍 你也是操盘的吧 很早就用MQL写EA了 很厉害 MT5平台上模拟交易和回测对于源代码来说安全吗 网上说有可能泄露的 我大学是学计算机的 网络和编程这两条路都走过 所以知道确实有这个可能性的


struct sample
   {
   int i;
   double j;
   }
   
class Test
   {
   private:
   sample instance[20];
   public:
   sample getInstance(void);
   void setInstance(sample instance[]);
   };
   
sample Test::getInstance(void)
   {
   
   }
   
void setInstance(sample instance[])
   {
   
   }
 

1. 函数并不能返回一个数组,函数的返回值类型是基本类型或者构造类型(类,结构体),或者构造类型的指针。    

    在MQL5中,构造类型作为参数时必须传入引用,数组作为参数时也是如此,目的是为了免去拷贝构造的开销。

    要达到返回一个数组的效果,传入该类型数组的引用。

2.  MT5平台上模拟交易和回测对于源代码来说安全吗 ?  当然是安全的。

 
#property copyright "Copyright 2019,fxMeter"
#property link      "https://www.mql5.com/en/users/fxmeter"
#property version   "1.00"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
struct Sample
  {
   int               a;
   double            b;
                     Sample(){a=0;b=0;}
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void InitSample(Sample &sam,int a,double b)
  {
   sam.a = a;
   sam.b = b;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class Test
  {
private:
   Sample            m_instance;
   Sample            m_data[20];
public:
   void              SetInstance(Sample &instance);
   Sample            GetInstance(void);
   void              SetInstance(Sample &data[]){for(int i=0;i<20;i++)m_data[i]=data[i];}
   void              GetInstance(Sample &data[]){for(int i=0;i<20;i++)data[i]=m_data[i];}

  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
Sample Test::GetInstance(void)
  {  
   return this.m_instance;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Test::SetInstance(Sample &instance)
  {
   this.m_instance=instance;
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   Test test;
   Sample sam;
   InitSample(sam,10,20);
   test.SetInstance(sam);
   Sample sam2;
   sam2=test.GetInstance();
   Print("same2.a=",sam2.a);
   Print("same2.b=",sam2.b);

   Sample data[20];
   for(int i=0;i<20;i++)
     {
      InitSample(data[i],i,i*i);
     }

   for(int i=0;i<20;i++)
     {
      printf("i:%d, data.a=%d;data.b=%.2f",i,data[i].a,data[i].b);
     }

   Sample data2[20];
   test.SetInstance(data);
   test.GetInstance(data2);

   printf("======================================");
   for(int i=0;i<20;i++)
     {
      printf("i:%d, data.i=%d;data.j=%.2f",i,data2[i].a,data2[i].b);
     }

  }
//+------------------------------------------------------------------+
 
Ziheng Zhuang:

谢谢了 很详细 辛苦了 还有一点不明白 函数能返回结构体数组吗 函数定义时它的返回类型及函数的return语句该怎么写

非常感谢你的帮助 有机会请你吃个饭 认识一下 我在写自己的EA 所以刚接触MQL5 虽然有一些C++的基础 但对MQL5深层的东西不了解 很多想做的事情不知道怎么实现 该如何学习 关于MQL似乎资料很少 书籍也很少 看官网吗 通过什么方式学习呢 后续还会有不少问题会请教你 有空的时候帮我看看 谢谢了

原因: