下载MetaTrader 5

用 MQL5 绘制指标的喷发

20 十一月 2013, 06:24
Sergey Pavlov
0
854

简介

毫无疑问,许多交易人员和交易策略的开发人员会对下面这些问题感兴趣:

寻找这些问题的答案让我探索出一种市场研究的新方法:构造和分析指标喷发。为了让大家有更直观的印象,请参见下图:

图 1 DCMV 指标喷发。

图 2. 基于iMA轨道线的指标喷发。

图片展示了不同指标的喷发,但它们的构建原理是相同的。在每次价格跳动后,将出现越来越多的带不同颜色和各种形状的点。它们形成了众多的集群,形状包括星云、云团、轨迹、直线、弧线等。这些形状有助于发现影响市场价格变动的无形的跳跃力和驱动力。对这些喷发的研究和分析与手相学类似。

喷发及其属性

喷发是位于指标特定线的交叉点上的一组点。

喷发的属性尚未明确,仍然留待研究人员探索。这里列示的是已知属性:

  • 同一类型的点有集群倾向;
  • 喷发具有方向 - 从现在到未来或到过去;
  • 集群十分重要 - 密集的集群可吸引,或反过来排斥价格。

指标喷发的计算

我们将通过示例探讨喷发计算的基本原则。我们选取两个指标 - iBandsiMA - 并找到它们的交叉线。我们将使用它们来绘制喷发点。为此,我们需要使用图形对象。算法在“EA 交易”中实施,但它可在指标中完成。

初始指标如图 3 所示:

图 3. iBands 指标(绿色)和 iMA 指标(红色)

我们需要使用“EA 交易”来创建喷发点。最好是使用 MQL5 向导来创建“EA 交易”模板。

图 4. 使用 MQL5 向导来创建“EA 交易”模板。

//+------------------------------------------------------------------+
//|                                      Emission of Bands && MA.mq5 |
//|                                                 Copyright DC2008 |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "DC2008"
#property link      "http://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| EA交易初始化函数                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   
//---
   return(0);
  
}
//+------------------------------------------------------------------+
//| EA交易去初始化函数                                                |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  
}
//+------------------------------------------------------------------+
//| EA的tick函数                                                      |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   
  
}
//+------------------------------------------------------------------+

首先,我们需要一些辅助绘图。我们需要使用半直线延续指标线(图 5)。这样便能控制喷发点的计算和可视化的正确性。稍后,我们将从图表中删除这些线条。

图 5. 辅助绘图。使用半直线延续指标线。

因此,让我们将图形对象(水平线和趋势线)添加至我们的“EA 交易”代码中。

input bool     H_line=true;   // 启用绘制水平线的标识
input bool     I_line=true;   // 启用绘制指标线的标识
//---
string         name;
//---- 指标缓存
double      MA[];    // iMA指标数组 
double      BBH[];   // iBands指标数组   - UPPER_BAND 
double      BBL[];   // iBands指标数组- LOWER_BAND
double      BBM[];   // iBands指标数组- BASE_LINE
datetime    T[];     // 时间坐标数组
//---- 指标的句柄
int         MAHandle;   // iMA 指标 句柄
int         BBHandle;   // iBands 指标 句柄
//+------------------------------------------------------------------+
//| EA交易初始化函数                                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   MAHandle=iMA(Symbol(),0,21,0,MODE_EMA,PRICE_CLOSE);
   BBHandle=iBands(Symbol(),0,144,0,2,PRICE_CLOSE);
//---
   if(H_line)     // iBands 指标水平线
      {
         //--- iBands - UPPER_BAND
         name="Hi";
         ObjectCreate(0,name,OBJ_HLINE,0,0,0);           
         ObjectSetInteger(0,name,OBJPROP_COLOR,Red);
         ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_DOT);
         ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
         //--- iBands - LOWER_BAND
         name="Lo";
         ObjectCreate(0,name,OBJ_HLINE,0,0,0);           
         ObjectSetInteger(0,name,OBJPROP_COLOR,Blue);
         ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_DOT);
         ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
         //--- iBands - BASE_LINE
         name="MIDI";
         ObjectCreate(0,name,OBJ_HLINE,0,0,0);           
         ObjectSetInteger(0,name,OBJPROP_COLOR,DarkOrange);
         ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_DOT);
         ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
      
}
//---
   if(I_line)     // Indicator lines
      {
         //--- iMA
         name="MA";
         ObjectCreate(0,name,OBJ_TREND,0,0,0,0);           
         ObjectSetInteger(0,name,OBJPROP_COLOR,Red);
         ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_SOLID);
         ObjectSetInteger(0,name,OBJPROP_WIDTH,2);
         ObjectSetInteger(0,name,OBJPROP_RAY_RIGHT,1);
         ObjectSetInteger(0,name,OBJPROP_RAY_LEFT,1);
         //--- iBands - UPPER_BAND
         name="BH";
         ObjectCreate(0,name,OBJ_TREND,0,0,0,0);           
         ObjectSetInteger(0,name,OBJPROP_COLOR,MediumSeaGreen);
         ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_SOLID);
         ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
         ObjectSetInteger(0,name,OBJPROP_RAY_RIGHT,1);
         ObjectSetInteger(0,name,OBJPROP_RAY_LEFT,1);
         //--- iBands - LOWER_BAND
         name="BL";
         ObjectCreate(0,name,OBJ_TREND,0,0,0,0);           
         ObjectSetInteger(0,name,OBJPROP_COLOR,MediumSeaGreen);
         ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_SOLID);
         ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
         ObjectSetInteger(0,name,OBJPROP_RAY_RIGHT,1);
         ObjectSetInteger(0,name,OBJPROP_RAY_LEFT,1);
         //--- iBands - BASE_LINE
         name="BM";
         ObjectCreate(0,name,OBJ_TREND,0,0,0,0);           
         ObjectSetInteger(0,name,OBJPROP_COLOR,MediumSeaGreen);
         ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_SOLID);
         ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
         ObjectSetInteger(0,name,OBJPROP_RAY_RIGHT,1);
         ObjectSetInteger(0,name,OBJPROP_RAY_LEFT,1);
      
}
   return(0);
  
}
//+------------------------------------------------------------------+
//| EA交易去初始化函数                                                |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  
}
//+------------------------------------------------------------------+
//| EA的tick函数                                                      |
//+------------------------------------------------------------------+
void OnTick()
  {
   //--- 用当前值填充数组
   CopyBuffer(MAHandle,0,0,2,MA);
   ArraySetAsSeries(MA,true);  
   CopyBuffer(BBHandle,0,0,2,BBM);
   ArraySetAsSeries(BBM,true);  
   CopyBuffer(BBHandle,1,0,2,BBH);
   ArraySetAsSeries(BBH,true);  
   CopyBuffer(BBHandle,2,0,2,BBL);
   ArraySetAsSeries(BBL,true);
   CopyTime(Symbol(),0,0,10,T);
   ArraySetAsSeries(T,true);
     
   //--- iBands指标(修正的)水平线指标(修正的)水平线
   if(H_line)
      {
      name="Hi";
      ObjectSetDouble(0,name,OBJPROP_PRICE,BBH[0]);
      name="Lo";
      ObjectSetDouble(0,name,OBJPROP_PRICE,BBL[0]);
      name="MIDI";
      ObjectSetDouble(0,name,OBJPROP_PRICE,BBM[0]);
      
}
   //--- 指标线(修正的)
   if(I_line)
      {
      name="MA";  //--- iMA
      ObjectSetInteger(0,name,OBJPROP_TIME,T[1]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,MA[1]);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,T[0]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,MA[0]);
      name="BH";  //--- iBands - UPPER_BAND
      ObjectSetInteger(0,name,OBJPROP_TIME,T[1]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,BBH[1]);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,T[0]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,BBH[0]);
      name="BL";  //--- iBands - LOWER_BAND
      ObjectSetInteger(0,name,OBJPROP_TIME,T[1]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,BBL[1]);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,T[0]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,BBL[0]);
      name="BM";  //--- iBands - BASE_LINE
      ObjectSetInteger(0,name,OBJPROP_TIME,T[1]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,BBM[1]);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,T[0]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,BBM[0]);
      
}
  
}
//+------------------------------------------------------------------+
由于喷发向过去和未来延续,趋势线属性应如下所示:
  • OBJPROP_RAY_LEFT = 1,(半直线向左);
  • OBJPROP_RAY_RIGHT = 1,(半直线向右)。

如此一来,带附加线的图表将呈图 6 所示效果。

准备阶段到此结束,现在我们来进行喷发。我们将会在以下线的交叉处创建第一系列的点:

  • 位于 "MA" (iMA) 线和 "BH" (iBands = UPPER_BAND) 线之间;
  • 位于 "MA" (iMA) 线和 "BL" (iBands = LOWER_BAND) 线之间;
  • 位于 "MA" (iMA) 线和 "BM" (iBands = BASE_BAND) 线之间。

图 6. 辅助绘图。使用直线延续指标线。

现在,到了计算交叉点坐标和绘制喷发点的时候了。我们来创建函数:

void Draw_Point(
                string   P_name,     // 对象名称(OBJ_ARROW)
                double   P_y1,       // 柱形[1]第一行的Y轴坐标
                double   P_y0,       // 柱形[0]第一行的Y轴坐标
                double   P_yy1,      // 柱形[1]第二行的Y轴坐标 
                double   P_yy0,      // 柱形[0]第二行的Y轴坐标
                char     P_code1,    // 柱形[0]右侧的图表
                char     P_code2,    // 柱形[0]左侧的图表
                color    P_color1,   // 柱形[0]右侧的点的颜色
                color    P_color2    // 柱形[0]左侧的点的颜色
                )
  {
   double   P,X;
   datetime P_time;
   if(MathAbs((P_yy0-P_yy1)-(P_y0-P_y1))>0)
     {
      P=P_y1+(P_y0-P_y1)*(P_y1-P_yy1)/((P_yy0-P_yy1)-(P_y0-P_y1));
      X=(P_y1-P_yy1)/((P_yy0-P_yy1)-(P_y0-P_y1));
      if(X>draw_period)
        {
         P_time=T[0]+(int)(X*PeriodSeconds());
         ObjectCreate(0,P_name,OBJ_ARROW,0,0,0);
         ObjectSetDouble(0,P_name,OBJPROP_PRICE,P);
         ObjectSetInteger(0,P_name,OBJPROP_TIME,P_time);
         ObjectSetInteger(0,P_name,OBJPROP_WIDTH,0);
         ObjectSetInteger(0,P_name,OBJPROP_ARROWCODE,P_code1);
         ObjectSetInteger(0,P_name,OBJPROP_COLOR,P_color1);
         if(X<0)
           {
            ObjectSetInteger(0,P_name,OBJPROP_ARROWCODE,P_code2);
            ObjectSetInteger(0,P_name,OBJPROP_COLOR,P_color2);
           
}
        
}
     
}
  
}

并将下面的代码行添加至函数 OnTick

//+------------------------------------------------------------------+
   int GTC=GetTickCount();                                             
//+------------------------------------------------------------------+
   name="H"+(string)GTC;
   Draw_Point(name,BBH[1],BBH[0],MA[1],MA[0],170,178,Red,Red);
   name="L"+(string)GTC;
   Draw_Point(name,BBL[1],BBL[0],MA[1],MA[0],170,178,Blue,Blue);
   name="M"+(string)GTC;
   Draw_Point(name,BBM[1],BBM[0],MA[1],MA[0],170,178,Green,Green);
//---
   ChartRedraw(0);

现在,我们来运行“EA 交易”并查看结果(图 7)。

很好,但还有其他一些交叉情形,这是我们没有考虑到的。例如,iBands 指标有三条线彼此相交,可对全局做出补充。

图 7. iMA 和 iBands 指标的喷发(3 个交叉点)。

现在,让我们尝试将另一系列的点添加至计算出的喷发,交叉点位于下面列出的线之间:
  • 位于线 "BH" (iBands = UPPER_BAND) 和线 "BL" (iBands = LOWER_BAND) 之间;
  • 位于线 "BH" (iBands = UPPER_BAND) 和线 "BM" (iBands = BASE_BAND) 之间;
  • 位于线 "BL" (iBands = LOWER_BAND) 和线 "BM" (iBands = BASE_BAND) 之间。

由于这些交叉点,我们将获得 3 个点,但它们将具有相同的坐标。因此,仅使用一个位于线 "BH" 和线 "BL" 之间的交叉点即已足够。

让我们将这些代码行添加至我们的“EA 交易”,然后查看结果(图 8)。

   name="B"+(string)GTC;
   Draw_Point(name,BBH[1],BBH[0],BBL[1],BBL[0],170,178,Magenta,Magenta);

图 8. iMA 和 iBands 指标的喷发(4 个交叉点)。

因此,我们获得了喷发,但总有一种我们错过了某些重要事情的感觉。然而,我们到底错过了什么?

为什么我们仅使用了这些输入参数?如果我们更改输入参数,我们会得到什么结果?无论如何,它们在喷发中的角色是什么?

的确,我们获得的喷发对应于一个单一的频率,由指标的输入参数所导致。要计算完整的多频率频谱,需要为其他频率执行相同的计算。作为示例,以下是我的可能的喷发频率版本:

//---- 指标的句柄
int         MAHandle[5];   // iMA 指标数组
int         BBHandle[7];   // iBands 指标句柄数组
//+------------------------------------------------------------------+
//| EA交易初始化函数                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   MAHandle[0]=iMA(NULL,0,21,0,MODE_EMA,PRICE_CLOSE);
   MAHandle[1]=iMA(NULL,0,34,0,MODE_EMA,PRICE_CLOSE);
   MAHandle[2]=iMA(NULL,0,55,0,MODE_EMA,PRICE_CLOSE);
   MAHandle[3]=iMA(NULL,0,89,0,MODE_EMA,PRICE_CLOSE);
   MAHandle[4]=iMA(NULL,0,144,0,MODE_EMA,PRICE_CLOSE);
//---
   BBHandle[0]=iBands(NULL,0,55,0,2,PRICE_CLOSE);
   BBHandle[1]=iBands(NULL,0,89,0,2,PRICE_CLOSE);
   BBHandle[2]=iBands(NULL,0,144,0,2,PRICE_CLOSE);
   BBHandle[3]=iBands(NULL,0,233,0,2,PRICE_CLOSE);
   BBHandle[4]=iBands(NULL,0,377,0,2,PRICE_CLOSE);
   BBHandle[5]=iBands(NULL,0,610,0,2,PRICE_CLOSE);
   BBHandle[6]=iBands(NULL,0,987,0,2,PRICE_CLOSE);
//---
   return(0);
  
}

为将所有可能的组合考虑在内,我们需要将以下代码添加至“EA 交易”:

//+------------------------------------------------------------------+
   CopyTime(NULL,0,0,10,T);
   ArraySetAsSeries(T,true);
   int GTC=GetTickCount();
//+------------------------------------------------------------------+
   int iMax=ArraySize(BBHandle)-1;
   int jMax=ArraySize(MAHandle)-1;
   for(int i=0; i<iMax; i++)
     {
      for(int j=0; j<jMax; j++)
        {
         //--- 用当前值填充数组
         CopyBuffer(MAHandle[j],0,0,2,MA);
         ArraySetAsSeries(MA,true);
         CopyBuffer(BBHandle[i],0,0,2,BBM);
         ArraySetAsSeries(BBM,true);
         CopyBuffer(BBHandle[i],1,0,2,BBH);
         ArraySetAsSeries(BBH,true);
         CopyBuffer(BBHandle[i],2,0,2,BBL);
         ArraySetAsSeries(BBL,true);

         name="H"+(string)GTC+(string)i+(string)j;
         Draw_Point(name,BBH[1],BBH[0],MA[1],MA[0],250,158,Aqua,Aqua);
         name="L"+(string)GTC+(string)i+(string)j;
         Draw_Point(name,BBL[1],BBL[0],MA[1],MA[0],250,158,Blue,Blue);
         name="M"+(string)GTC+(string)i+(string)j;
         Draw_Point(name,BBM[1],BBM[0],MA[1],MA[0],250,158,Green,Green);
         name="B"+(string)GTC+(string)i+(string)j;
         Draw_Point(name,BBH[1],BBH[0],BBL[1],BBL[0],250,158,Magenta,Magenta);
        
}
     
}
//---
   ChartRedraw(0);

喷发频谱中包含的频率越多,图表上的图形就越好,但也不能滥用 - 它是消耗计算机资源最简单的方式,并会使图表上的图形变得一团糟。频率的数量可凭经验判定。为了获得更好的图形感知,我们必须特别注意绘制风格。

图 9. 多频率喷射频谱。

论喷射的绘制风格

MQL5 语言为喷射的绘制提供了各种网页颜色Windings 字符。在此,我想分享我对绘制风格的一些看法:  
  1. 每个人对图形图像都有自己的感知,因此您需要花费一些时间来自定义喷射。
  2. 我们无法从图 9 的“混沌”中识别任何规律或模式。它是糟糕绘制的一个示例。
  3. 尝试在彩虹频谱中使用相邻色。
  4. 区分过去(来自 [0] 柱的左侧)和未来(来自 [0] 柱的右侧)的字符码。
  5. 将点的颜色和形状成功结合能够使喷发转变为杰作,这不仅有助于交易,同时还能悦观者目。
作为示例,以下是我的喷发绘制风格版本(见图 10-17):
         name="H"+(string)GTC+(string)i+(string)j;
         Draw_Point(name,BBH[1],BBH[0],MA[1],MA[0],250,158,Aqua,Aqua);
         name="L"+(string)GTC+(string)i+(string)j;
         Draw_Point(name,BBL[1],BBL[0],MA[1],MA[0],250,158,Blue,Blue);
         name="M"+(string)GTC+(string)i+(string)j;
         Draw_Point(name,BBM[1],BBM[0],MA[1],MA[0],250,158,Magenta,Magenta);
         name="B"+(string)GTC+(string)i+(string)j;
         Draw_Point(name,BBH[1],BBH[0],BBL[1],BBL[0],250,158,DarkOrchid,DarkOrchid);

iMA 和 iBands 喷发图库

以下是本文所述及的喷发图像。

 

图 10. 

 

11

12.

13.

14.

 

15.

16.

 

17.

喷发分析

喷发分析是一项独立的任务。最有价值的是实时观察它的动态,这是理解众多效果和模式的最佳方式。

注意价格的修正 - 看上去喷发似乎“知道”目标价格。此外,您可以查看支撑、阻力和均衡价位。

总结

  1. 指标的喷发可能会引起正在探索市场研究及分析的新方法的交易人员和交易系统开发人员的兴趣。
  2. 作为一篇介绍性文章,本文并未提供现成的解决方案。然而,文中给出的喷发计算技术可应用至其他指标或指标的组合。
  3. 在文章的成文过程中,我碰到的问题要多过答案。以下是部分摘录:如何优化喷发绘制的算法;喷发频谱特性在喷发结构中处于什么角色;如何在自动交易中使用喷发?

本文译自 MetaQuotes Software Corp. 撰写的俄文原文
原文地址: https://www.mql5.com/ru/articles/26

如何交换数据:10 分钟为 MQL5 创建 DLL 如何交换数据:10 分钟为 MQL5 创建 DLL

现在很多开发人员不知道如何编写简单的 DLL,而这是不同系统绑定的特殊特性。我将通过多个示例,展示在 10 分钟内创建简单 DLL 的整个过程,并讨论我们绑定实施的一些技术细节。我将给出 Visual Studio 中的 DLL 创建的分步过程,以及交换不同变量类型的示例(数字、数组、字符串等)。此外,我还将说明在自定义 DLL 中如何使您的客户端免于崩溃。

价格直方图(市场概况)及其在 MQL5 中的实施 价格直方图(市场概况)及其在 MQL5 中的实施

“市场概况”由真正才华横溢的思想家 Peter Steidlmayer 所提出。他建议使用有关“水平”和“垂直”市场动态信息的替代表示法,从而给出一套完全不同的模型。他认为存在市场深层次的摆动或称之为平衡和失衡周期的基本模式。在本文中,我将会探讨价格直方图(市场概况的一种简化模型)以及它在 MQL5 中的实施。

使用 WCF 服务将报价从 MetaTrader 5 导出至 .NET 应用程序的方法 使用 WCF 服务将报价从 MetaTrader 5 导出至 .NET 应用程序的方法

想要从 MetaTrader 5 导出报价到您自己的应用程序?MQL5-DLL 组合可给出这样的解决方案!本文介绍将报价从 MetaTrader 5 导出至以 .NET 编写的应用程序的方法。对我而言,使用该平台实施报价的导出要更为有趣、合理和容易。遗憾的是版本 5 仍然不支持 .NET,因此和以往一样,我们将使用 .NET 支持的 win32 dll 作为中间层。

指标间的数据交换:易如反掌! 指标间的数据交换:易如反掌!

我们希望创建这样一个环境,即能够提供对附加于图表的指标的数据访问,并具有以下属性:没有数据复制;只需稍加修改我们需要使用的可用方法的代码;MQL 代码优先(当然,我们必须使用 DLL,但我们将只使用一些 C++ 代码字符串)。本文介绍了为 MetaTrader 终端开发程序环境的简易方法,这将提供从其他 MQL 程序访问指标缓冲区的方法。