外汇EA编写教程:使用ex5库促进项目开发

简介

对于有经验的读者,不需要解释在库中隐藏函数和类的目的。那些积极寻找新想法的人可能想知道在中隐藏类/函数实现细节。ex5文件将使您能够与其他开发人员共享您的专有算法,建立公共项目并在网络上进行推广。

此外,尽管metaquotes团队不遗余力地引入直接继承ex5库类的可能性,但我们现在已经准备好实现它们了。

目录

1。函数
2的派生和导入。通过类隐藏实现
4初始化导出
3..ex5文件中的变量。继承公布
5。Ex5导出类库

A 60331。函数A 6033的派生和导入

这是构造类导出的基本方法。要将您的功能用于其他程序,请考虑三个重要事项:

  1. 要创建的文件的扩展名必须为。MQ5(不)。mqh)将在中编译。EX5文件。
  2. 此文件应包含属性库预处理器指令;
  3. 关键字“export”应放在所需派生函数的标题之后
Example 1. Let us create a function to be used in other programs

//--- library.mq5
#property library
int libfunc (int a, int b) export
{
  int c=a+b;
  Print("a+b="+string(с));
  return(с);
}

编译完文件后,就得到了库。ex5文件,然后libfunc可以在这里将其用于另一个程序。

导入函数的过程也非常简单。使用导入预处理器指令执行。

Example 2. We will use the export function libfunc() in our script

//--- uses.mq5
#import "library.ex5"
  int libfunc(int a, int b);
#import

void OnStart()
{
  libfunc(1, 2);
}

记住编译器会搜索。mql5/libraries文件夹中的ex5文件。所以,如果图书馆。ex5不在此文件夹下,必须指定相对路径名。

例如:

#import "../Include/MyLib/library.ex5" // the file is located in the MQL5/Include/MyLib folder
#import "../Experts/library.ex5" // the file is located in the MQL5/Experts/ folder

为了将来的使用,函数不仅可以导入到目标中。mq5文件,但也可以进入。MQH文件。

为了说明实际应用,我们使用了一些图形。

我们要创建一个要导出的库。这些功能显示图表上的图形对象,如按钮、编辑、标签和矩形标签,从图表中删除对象,并重置图表的颜色参数。

图如下:

类方法输出图

本文末尾提供了完整的graph.mq5文件。这里,我们只提供了一个用于绘图功能编辑的模板示例。

//+------------------------------------------------------------------+
//| SetEdit                                                          |
//+------------------------------------------------------------------+
void SetEdit(long achart,string name,int wnd,string text,color txtclr,color bgclr,color brdclr,
             int x,int y,int dx,int dy,int corn=0,int fontsize=8,string font="Tahoma",bool ro=false) export
  {
   ObjectCreate(achart,name,OBJ_EDIT,wnd,0,0);
   ObjectSetInteger(achart,name,OBJPROP_CORNER,corn);
   ObjectSetString(achart,name,OBJPROP_TEXT,text);
   ObjectSetInteger(achart,name,OBJPROP_COLOR,txtclr);
   ObjectSetInteger(achart,name,OBJPROP_BGCOLOR,bgclr);
   ObjectSetInteger(achart,name,OBJPROP_BORDER_COLOR,brdclr);
   ObjectSetInteger(achart,name,OBJPROP_FONTSIZE,fontsize);
   ObjectSetString(achart,name,OBJPROP_FONT,font);
   ObjectSetInteger(achart,name,OBJPROP_XDISTANCE,x);
   ObjectSetInteger(achart,name,OBJPROP_YDISTANCE,y);
   ObjectSetInteger(achart,name,OBJPROP_XSIZE,dx);
   ObjectSetInteger(achart,name,OBJPROP_YSIZE,dy);
   ObjectSetInteger(achart,name,OBJPROP_SELECTABLE,false);
   ObjectSetInteger(achart,name,OBJPROP_READONLY,ro);
   ObjectSetInteger(achart,name,OBJPROP_BORDER_TYPE,0);
   ObjectSetString(achart,name,OBJPROP_TOOLTIP,"");
  }

所需功能的导入和使用将在目标文件spiro.mq5:
中实现。

Example 3. Using imported functions

//--- Spiro.mq5 – the target file of the Expert Advisor

//--- importing some graphics functions
#import "Graph.ex5" 
  void SetLabel(long achart, string name, int wnd, string text, color clr, 
               int x, int y, int corn=0, int fontsize=8, string font="Tahoma");
  void SetEdit(long achart, string name, int wnd, string text, color txtclr, color bgclr, color brdclr, 
                 int x, int y, int dx, int dy, int corn=0, int fontsize=8, string font="Tahoma", bool ro=false);
  void SetButton(long achart, string name, int wnd, string text, color txtclr, color bgclr, 
                int x, int y, int dx, int dy, int corn=0, int fontsize=8, string font="Tahoma", bool state=false);
  void HideChart(long achart, color BackClr);
#import

//--- prefix for chart objects
string sID; 
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+

void OnInit()
{
  HideChart(0, clrWhite);
  sID="spiro.";
  DrawParam();
}
//+------------------------------------------------------------------+
//| DrawParam                                                        |
//+------------------------------------------------------------------+
void DrawParam()
{
  color bgclr=clrWhite, clr=clrBlack;
//--- bigger radius    
  SetLabel(0, sID+"stR.", 0, "R", clr, 10, 10+3);
  SetEdit(0, sID+"R.", 0, "100", clr, bgclr, clr, 40, 10, 50, 20);
//--- smaller radius   
  SetLabel(0, sID+"str.", 0, "r", clr, 10, 35+3);
  SetEdit(0, sID+"r.", 0, "30", clr, bgclr, clr, 40, 35, 50, 20);
//--- distance to the center
  SetLabel(0, sID+"stD.", 0, "D", clr, 10, 60+3);
  SetEdit(0, sID+"D.", 0, "40", clr, bgclr, clr, 40, 60, 50, 20);
//--- drawing accuracy
  SetLabel(0, sID+"stA.", 0, "Alfa", clr, 10, 85+3); 
  SetEdit(0, sID+"A.", 0, "0.04", clr, bgclr, clr, 40, 85, 50, 20);
//--- drawing accuracy
  SetLabel(0, sID+"stN.", 0, "Rotor", clr, 10, 110+3); 
  SetEdit(0, sID+"N.", 0, "10", clr, bgclr, clr, 40, 110, 50, 20);
//--- draw button
  SetButton(0, sID+"draw.", 0, "DRAW", bgclr, clr, 39, 135, 51, 20); 
}

运行EA后,这些对象将显示在图表
上方。

使用库对象的示例

如您所见,导出和导入函数的过程一点也不困难,但您必须阅读“帮助”的特定限制:导出和导入。

2。类隐藏实现的导出

由于mql5中的类仍然没有直接导出,因此我们必须使用一种有点花哨的方法。该方法基于多态性和虚函数。实际上,从ex5模块返回的不是类本身,而是创建的类对象。让我们称之为隐藏的实现对象。

该方法的本质是将所需的类划分为两个类,以便公开访问函数和变量的声明,并将实现细节隐藏在一个封闭的类中。EX5文件。

下面是一个简单的例子。有一个CSPIro类,我们希望在不公开其实现细节的情况下与其他开发人员共享。假设它包含变量、构造函数、析构函数和工作函数。

要导出此类,我们应该执行以下操作:

  • 创建cspiro类后代的副本。我们称之为ispiro(缩写c被i替换,因为它源自“interface”一词)
  • 将所有变量和虚拟函数保留在初始的cspiro类中。
  • 函数实现细节应该形成一个新的ispiro类。
  • 添加它将创建一个不公开ISPIRO实例的导出函数。
  • 小心!所有必需的函数都应冠以虚拟前缀

因此,我们有两个文件:

Example 4. Hiding of the class implementation in the ex5 module

//--- Spiro.mqh – public file, the so called header file

//+------------------------------------------------------------------+
//| Class CSpiro                                                     |
//| Spirograph draw class                                       |
//+------------------------------------------------------------------+
class CSpiro
  {
public:
   //--- prefix of the chart objects
   string            m_sID;
   //--- offset of the chart center
   int               m_x0,m_y0;
   //--- color of the line
   color             m_clr;
   //--- chart parameters
   double            m_R,m_r,m_D,m_dAlfa,m_nRotate;

public:
   //--- constructor
                     CSpiro() { };
   //--- destructor
                    ~CSpiro() { };
   virtual void Init(int ax0,int ay0,color aclr,string asID) { };
   virtual void SetData(double aR,double ar,double aD,double adAlpha,double anRotate) { };

public:
   virtual void DrawSpiro() { };
   virtual void SetPoint(int x,int y) { };
  };

注意:所有函数类都使用关键字virtual声明。

//--- ISpiro.mq5 – hidden implementation file

#include "Spiro.mqh"

//--- importing some functions
#import "../Experts/Spiro/Graph.ex5"
void SetPoint(long achart,string name,int awnd,int ax,int ay,color aclr);
void ObjectsDeleteAll2(long achart=0,int wnd=-1,int type=-1,string pref="",string excl="");
#import

CSpiro *iSpiro() export { return(new ISpiro); }
//+------------------------------------------------------------------+
//| Сlass ISpiro                                                     |
//| Spirograph draw class                                       |
//+------------------------------------------------------------------+
class ISpiro : public CSpiro
  {
public:
                     ISpiro() { m_x0=0; m_y0=0; };
                    ~ISpiro() { ObjectsDeleteAll(0,0,-1); };
   virtual void      Init(int ax0,int ay0,color aclr,string asID);
   virtual void      SetData(double aR,double ar,double aD,double adAlpha,double anRotate);

public:
   virtual void      DrawSpiro();
   virtual void      SetPoint(int x,int y);
  };
//+------------------------------------------------------------------+
//| Init                                                             |
//+------------------------------------------------------------------+
void ISpiro::Init(int ax0,int ay0,color aclr,string asID)
  {
   m_x0=ax0;
   m_y0=ay0;
   m_clr=aclr;
   m_sID=asID;
   m_R=0; 
   m_r=0; 
   m_D=0;
  }
//+------------------------------------------------------------------+
//| SetData                                                          |
//+------------------------------------------------------------------+
void ISpiro::SetData(double aR,double ar,double aD,double adAlpha,double anRotate)
  {
   m_R=aR; m_r=ar; m_D=aD; m_dAlfa=adAlpha; m_nRotate=anRotate;
  }
//+------------------------------------------------------------------+
//| DrawSpiro                                                        |
//+------------------------------------------------------------------+
void ISpiro::DrawSpiro()
  {
   if(m_r<=0) { Print("Error! r==0"); return; }
   if(m_D<=0) { Print("Error! D==0"); return; }
   if(m_dAlfa==0) { Print("Error! Alpha==0"); return; }
   ObjectsDeleteAll2(0,0,-1,m_sID+"pnt.");
   int n=0; double a=0;
   while(a<m_nRotate*2*3.1415926)
     {
      double x=(m_R-m_r)*MathCos(a)+m_D*MathCos((m_R-m_r)/m_r*a);
      double y=(m_R-m_r)*MathSin(a)-m_D*MathSin((m_R-m_r)/m_r*a);
      SetPoint(int(m_x0+x),int(m_y0+y));
      a+=m_dAlfa;
     }
   ChartRedraw(0);
  }
//+------------------------------------------------------------------+
//| SetPoint                                                         |
//+------------------------------------------------------------------+
void ISpiro::SetPoint(int x,int y)
  {
   Graph::SetPoint(0,m_sID+"pnt."+string(x)+"."+string(y),0,x,y,m_clr);
  }
//+------------------------------------------------------------------+

如您所见,隐藏类已在中实现。并包含预处理器命令属性库。因此,前条所列的所有规则也已得到遵守。

还要注意设置点函数的范围分辨率操作符。它在图形库和spiro类中声明。为了让编译器调用所需的函数,我们显式地指定了它的用法:操作并给出文件名。

  Graph::SetPoint(0, m_sID+"pnt."+string(x)+"."+string(y), 0, x, y, m_clr);

现在,我们可以合并头文件并将其实现导入到生成的EA中。

数字如下:

使用库类方法图解

Example 5. Using export objects

//--- Spiro.mq5 - the target file of the Expert Advisor

//--- importing some functions
#import "Graph.ex5" 
  void SetLabel(long achart, string name, int wnd, string text, color clr,
               int x, int y, int corn=0, int fontsize=8, string font="Tahoma");
  void SetEdit(long achart, string name, int wnd, string text, color txtclr, color bgclr, color brdclr, 
              int x, int y, int dx, int dy, int corn=0, int fontsize=8, string font="Tahoma", bool ro=false);
  void SetButton(long achart, string name, int wnd, string text, color txtclr, color bgclr, 
                int x, int y, int dx, int dy, int corn=0, int fontsize=8, string font="Tahoma", bool state=false);
  void HideChart(long achart, color BackClr);
#import

//--- including the chart class
#include <Spiro.mqh> 

//--- importing the object
#import "ISpiro.ex5"
  CSpiro *iSpiro();
#import

//--- object instance
CSpiro *spiro; 
//--- prefix for chart objects
string sID; 
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
void OnInit()
{
  HideChart(0, clrWhite);
  sID="spiro.";
  DrawParam();
//--- object instance created
  spiro=iSpiro(); 
//--- initializing the drawing
  spiro.Init(250, 200, clrBlack, sID);
//--- setting the calculation parameters
  spiro.SetData(100, 30, 40, 0.04, 10);
//--- drawing
  spiro.DrawSpiro(); 
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
  delete spiro; // deleting the object
}

因此,您将能够更改图表中的对象参数并绘制对象的图表。

图形对象参数

3..ex5文件
中变量的初始化

通常,isuperClass使用全局变量。在文件中包含变量的MQH。这些变量可以以类似的方式合并到其他文件中。

例如:

Example 6. Public include file

//--- globals.mqh

#include <Trade/Trade.mqh>
//--- instance of the trade function object
extern CTrade *_trade; 

_ trade对象的唯一实例在程序中初始化,但在隐藏的isuperClass类中使用。

为此,应将创建的指向该对象的指针从ISuperClass类传递给。EX5文件。

如果它接收来自的对象。EX5文件,最容易实现,如下图所示:

Example 7. Initialization of variables upon creation of the object

//--- ISuperClass.mq5 –hidden implementation file

#property library
CSuperClass *iSuperClass(CTrade *atrade) export
{
//--- saving the pointer
   _trade=atrade; 
//--- returning the object of the hidden implementation of ISuperClass of the open CSuperClass class
  return(new ISuperClass); 
}
//... the remaining code

因此,在接收到模块中的对象之后,所有需要的变量都被初始化。实际上,公共全局变量可能有多种类型。那些不想在任何时候更改isuperClass函数头的人最好创建一个特殊的类,该类聚集了所有使用它的全局变量和函数。

Example 8. Public include file

//--- globals.mqh
#include <Trade/Trade.mqh>

//--- trade "object"
extern CTrade *_trade; 
//--- name of the Expert Advisor of the system
extern string _eaname; 

//+------------------------------------------------------------------+
//| class __extern                                                   |
//+------------------------------------------------------------------+
class __extern // all extern parameters for passing between the ex5 modules are accumulated here
{
public:
//--- the list of all public global variables to be passed
//--- trade "object"
  CTrade *trade; 
//--- name of the Expert Advisor of the system
  string eaname; 
    
public:
  __extern() { };
  ~__extern() { };

//--- it is called when passing the parameters into the .ex5 file
  void Get() { trade=_trade; eaname=_eaname; };  // getting the variables

 //--- it is called in the .ex5 file
  void Set() { _trade=trade; _eaname=eaname; };  // setting the variables
                                                       
};
//--- getting the variables and pointer for passing the object into the .ex5 file
__extern *_GetExt() { _ext.Get(); return(GetPointer(_ext)); } 

//--- the only instance for operation
extern __extern _ext; 

ISuperClass.mq5 文件会如下实施:

Example 9.

//--- ISuperClass.mq5 –hidden implementation file

#property library
CSuperClass *iSuperClass(__extern *aext) export
{
//--- taking in all the parameters
  aext.Set();
//--- returning the object
  return(new ISuperClass); 
}
//--- ... the remaining code

函数调用现在被转换成一种简化的、可伸缩的(最重要的)形式。

Example 10. Using export objects in the presence of public global variables

//--- including global variables (usually located in SuperClass.mqh)
#include "globals.mqh"    

//--- including the public header class
#include "SuperClass.mqh" 
//--- getting the hidden implementation object
#import "ISuperClass.ex5"
  CSuperClass *iSuperClass();
#import

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
//--- creating the hidden implementation object providing for the passing of all parameters
  CSuperClass *sc=iSuperClass(_GetExt()); 
  //--- ... the remaining code
}

4。导出类
的继承

您必须清楚:这种导出对象的方式意味着直接简单继承是完全不可能的。隐藏的实现对象导出意味着对象本身是继承链中的最后一个链接,也是最后一个可用的链接。

通常,您可以通过编写一个额外的中间类来创建继承的“模拟”。当然,在这里,我们还需要多态性和虚拟性。

Example 11. Emulation of inheritance of hidden classes

//--- including the public header class
#include "SuperClass.mqh" 

//--- getting the hidden implementation object
#import "ISuperClass.ex5"
  CSuperClass *iSuperClass();
#import

class _CSuperClass
{
public:
//--- instance of the hidden implementation object
  CSuperClass *_base;
public:
//--- constructor
  _CSuperClass() {  _base=iSuperClass(_GetExt()); };
//--- destructor
  ~_CSuperClass() { delete _base; };
//--- further followed by all functions of the base CSuperClass class
//--- working function called from the hidden implementation object
  virtual int func(int a, int b) { _base.func(a,b); }; 
};

这里唯一的问题是访问CSuperClass的变量。正如您所看到的,它们不存在于后代的声明中,而是存在于基变量中。通常,如果有头类超类,它不会影响可用性。MQH。

当然,如果您主要关注的是专有功能,那么您不需要提前创建与它们相关联的isuperClass包装器。导出这些专有函数并允许外部开发人员创建自己的包装类就足够了,这些类随后很容易继承。

由此,为其他开发人员准备您的开发时,您要注意创建一整套的必需导出函数、.mqh 与 .ex5 文件以及相关类:

  1. 类独立函数的推导
  2. MQH头文件及其。Ex5实施
  3. 中变量的实现。EX5文件

发行
5。EX5文库

2011年11月,metaquotes开始提供对文件存储库的访问。详情请参阅声明。

此存储库允许您存储开发内容,更重要的是,它为其他开发人员提供对其的访问。此工具将允许您轻松发布文件的新版本,从而确保使用这些文件的开发人员能够快速访问这些文件。

此外,该公司的网站还为您提供了一个在市场上免费提供您自己的图书馆的机会。

总结

现在您知道了如何通过导出函数或类对象来创建ex5库,并且可以将您的知识应用到实践中。所有这些资源都允许您与其他开发人员更紧密地合作:致力于共同的项目,在“市场”中推广它们,或者提供对ex5库功能的访问。

本文由MetaQuotes Software Corp.翻译自俄语原文
,网址为https://www.mql5.com/ru/articles/362。

附加文件下载zip spio.zip(3.91 KB)

 

 


MyFxtop迈投(www.myfxtop.com)-靠谱的外汇跟单社区,免费跟随高手做交易!

 

免责声明:本文系转载自网络,如有侵犯,请联系我们立即删除,另:本文仅代表作者个人观点,与迈投财经(www.myfxtop.cn)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。

著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。

風險提示

MyFxtops邁投所列信息僅供參考,不構成投資建議,也不代表任何形式的推薦或者誘導行為。MyFxtops邁投非外匯經紀商,不接觸妳的任何資金。 MYFXTOPS不保證客戶盈利,不承擔任何責任。從事外彙和差價合約等金融產品的槓桿交易具有高風險,損失有可能超過本金,請量力而行,入市前需充分了解潛在的風險。過去的交易成績並不代表以後的交易成績。依據各地區法律法規,MyFxtops邁投不向中國大陸、美國、加拿大、朝鮮居民提供服務。

邁投公眾號

聯繫我們

客服QQ:981617007
Email: service@myfxtop.com

MyFxtops 邁投