
Promocione sus proyectos de desarrollo usando las librerías EX5
Introducción
Un lector avezado no necesita una explicación sobre la finalidad de ocultar las implementaciones de funciones y clases en librerías. Quienes busquen activamente nuevas ideas puede que quieran saber que ocultar los detalles de la implementación de las clases/funciones en un archivo .ex5 les permitirá compartir algoritmos propios con otros desarrolladores, iniciar proyectos y promocionarlos en la Web.
Y mientras el equipo de MetaQuotes no escatima esfuerzos para tener la posibilidad de heredar directamente las clases de las librerías ex5, vamos a implementarlas ahora.
Tabla de contenidos
1. Exportar e importar funciones
2. Exportar la implementación oculta de una clase
3. Inicialización de variables en un archivo .ex5
4. Herencia de clases de exportación
5. Publicación de librerías ex5
1. Exportar e importar funciones
Este es un método básico que subyace a la exportación de clases. Hay tres cosas clave que deben tenerse en cuenta para que nuestras funciones estén disponibles en otros programas:
- El archivo a crear debe tener la extensión .mq5 (no .mqh) para ser compilado a un archivo .ex5;
- El archivo debe contener la directiva del preprocesador de la librería #property.
- La palabra clave "exportar" debe ponerse después de los encabezados de las funciones exportadas correspondientes.
Ejemplo 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(с); }
Después de compilar este archivo, obtendremos el archivo library.ex5 del que libfunc puede usarse en otro programa.
El proceso de importar las funciones es también muy simple. Se realiza usando la directiva de preprocesador #import.
Ejemplo 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); }
Tenga en cuenta que el compilador buscará los archivos .ex5 en la carpeta MQL5\Libraries. Posteriormente, si el archivo ibrary.ex5 no está ubicado en esa carpeta, tendremos que especificar el nombre de la ruta respectiva.
P. ej.
#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
Para un uso en el futuro, las funciones pueden ser importadas no solo en el archivo de destino .mq5 sino también en los archivos .mqh.
Para ilustrar la aplicación práctica, vamos a usar algunos gráficos.
Vamos a crear una librería de funciones para exportar. Estas funciones mostrarán los objetos gráficos como botones, editar, etiqueta y etiqueta de rectángulo en un gráfico, borrarán los objetos del gráfico y restablecerán los parámetros de color del mismo.
Esto puede mostrarse esquemáticamente de la siguiente forma:
Puede descargar todo el archivo Graph.mq5 al final del artículo. Por tanto, solo daremos un ejemplo de plantilla de la función dibujo Edit.
//+------------------------------------------------------------------+ //| 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,""); }
La importación de las funciones necesarias y su uso se implementará en el archivo de destino Spiro.mq5:
Ejemplo 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); }
Después de la ejecución del asesor experto, los objetos aparecerán en el gráfico:
Como puede ver, el proceso de exportación e importación de funciones no es en absoluto difícil, pero debe asegurarse de que lee sobre algunas limitaciones en la ayuda: exportar, importar.
2. Exportar la implementación oculta de una clase
Como las clases en MQL5 no se pueden exportar directamente por ahora, tendremos que recurrir a algún método creativo. Este se basa en las funciones polymorphism y virtual. De hecho, no es la clase en sí la que es devuelta desde el módulo ex5 sino el objeto creado por la misma. Vamos a llamarlo objeto de la implementación oculto.
La esencia del método es dividir la clase necesaria en dos, de forma que la declaración de funciones y variables esté accesible al público y la información sobre su implementación esté oculta en un archivo .ex5 cerrado.
Esto puede mostrarse esquemáticamente de la siguiente forma: Tenemos la clase CSpiro que nos gustaría compartir con otros desarrolladores sin revelar la información sobre la implementación. Supongamos que contiene variables, un constructor, destructor y funciones.
Para exportar la clase debemos hacer lo siguiente:
- Creamos una copia de la clase CSpiro hija. Vamos a llamarla ISpiro (la primera letra C se sustituye por I, según deriva de la palabra "interfaz")
- Dejamos todas las variables y funciones dummy en la clase inicial CSpiro.
- La información sobre la implementación de la función formará una nueva clase ISpiro.
- La añadimos a la función de exportación que creará una instancia de la función ISpiro cerrada.
- ¡Cuidado! Todas las funciones necesarias deben tener el prefijo virtual.
Como resultado tenemos dos archivos:
Ejemplo 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) { }; };
//--- 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); } //+------------------------------------------------------------------+
Como puede ver, la clase oculta ha sido implementada en un archivo .mq5 y contiene la librería #property del comando del preprocesador. Por tanto, se han observado todas las reglas que se establecen en la sección anterior.
También observe el operador scope resolution para la función SetPoint. Se declara tanto en la librería Graph como en la clase CSpiro. Para que el compilador pueda llamar a la función necesaria, lo especificamos explícitamente usando la acción :: y dando el nombre del archivo.
Graph::SetPoint(0, m_sID+"pnt."+string(x)+"."+string(y), 0, x, y, m_clr);
Ahora podemos incluir el archivo cabecera e importar su implementación en nuestro asesor experto resultante.
Esto puede mostrarse esquemáticamente de la siguiente forma:
Ejemplo 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 }
Como resultado, podremos cambiar los parámetros del objeto en el gráfico y dibujar el gráfico del objeto
3. Inicialización de variables en un archivo .ex5
Suele ocurrir que ISuperClass utilice variables del archivo globals.mqh . Estas variables pueden incluirse de forma similar para su uso en otros archivos.
P. ej.
Ejemplo 6. Public include file //--- globals.mqh #include <Trade\Trade.mqh> //--- instance of the trade function object extern CTrade *_trade;
La única instancia del objeto _trade se inicializa en nuestro programa, aunque no obstante se usa en la clase oculta ISuperClass.
Para esta finalidad el puntero hacia el objeto que hayamos creado debe pasarse desde la clase ISuperClass al archivo .ex5.
Es más fácil hacerlo cuando el objeto se recibe desde el archivo .ex5, como se muestra a continuación:
Ejemplo 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
De esta forma, todas las variables se inicializan a la recepción del objeto en su módulo.
De hecho, puede haber un montón de variables globales públicas de distintos tipos. Aquellos que no deseen cambiar el encabezado de la funciónISuperClass todo el tiempo, deben crear una clase aggregating especial para que todas las variables y funciones trabajen con ella.
Ejemplo 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;El archivo ISuperClass.mq5 se implementará de la siguiente forma:
Ejemplo 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
La llamada a la función se transformará en otra forma simplificada y, lo que es más importante, ampliable.
Ejemplo 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. Herencia de clases de exportación
Ya debe haber comprendido que esta forma de exportar objetos implica que la herencia simple y directa está fuera de duda. La exportación del objeto de la implementación oculta sugiere que el propio objeto es el último enlace de la cadena de herencia y es además el que puede usarse en última instancia.
En el caso general podemos crear una "emulación" de la herencia escribiendo una clase intermedia adicional. Y aquí necesitaremos, por supuesto, el polimorfismo y la virtualidad.
Ejemplo 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); }; };
La única cuestión aquí es el acceso a las variables de CSuperClass. Como puede ver, no están presentes en la declaración de la hija y se ubican en la variable _base. Normalmente no afecta a la usabilidad siempre que haya una clase de encabezado SuperClass.mqh.
Naturalmente, si estamos centrados principalmente en funciones de conocimientos técnicos, tenemos que crear una envolvente de ISuperClass en relación a las mismas por adelantado. Será suficiente exportar estas funciones de conocimientos técnicos y dejar a los desarrolladores externos crear sus propias clases envolventes que serán luego fáciles de heredar.
- Exportación de las funciones independientes de la clase
- Archivos .mqh de encabezado y sus implementaciones .ex5
- Inicialización de variables en un archivo .ex5
5. Publicación de librerías ex5
En noviembre de 2011 MetaQuotes comenzó a proporcionar acceso al repositorio de archivos. Puede encontrar más información al respecto en el anuncio.
Este repositorio nos permite almacenar nuestros desarrollos y, lo que es más importante, proporcionar acceso para otros desarrolladores. Esta herramienta nos permitirá publicar fácilmente nuevas versiones de nuestros archivos para garantizar un acceso rápido a ellos a los desarrolladores que puedan usarlos.
Además, la página web de la empresa da la oportunidad a los usuarios de ofrecer sus propias librerías de funciones en el Mercado comercialmente y sin coste alguno.
Conclusión
Ya sabe cómo crear librerías ex5 exportando sus funciones u objetos de clases y puede poner en práctica sus conocimientos. Todos estos recursos permitirán establecer una cooperación con otros desarrolladores: para trabajar en proyectos comunes, promocionarlos en el Mercado o proporcionar acceso a las funciones de la librería ex5.
Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/362





- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso