
EX5 ライブラリ使用による開発プロジェクトの促進
はじめに
教養ある読者の方にはライブラリに関数やクラスの実装を非表示にする目的を説明するまでもないでしょう。新しい考えを積極積に探している方はex5 ファイルにクラス/関数の実装詳細を隠すことでノウハウアルゴリズムを他の開発者と共有し、共通のプロジェクトを設定し、ウェブ上でそれらを進めていくことができるようになるということを知りたいを思うものです。
そして MetaQuotes チームが ex5 ライブラリクラスの直接継承機能を実現することに全力を傾ける一方で、われわれはそれをいますぐ実装していこうとしているのです。
コンテンツ一覧
1. 関数のエクスポートとインポート
2. クラスの非表示実装のエクスポート
3. .ex5 ファイルにおける変数初期化
4. Export クラスの継承
5. ex5 ライブラリの発行
1. 関数のエクスポートとインポート
これはクラスのエクスポートの背後にある基本メソッドです。他のプログラムでご自身の関数を使用可能にするために考慮すべき主要な事柄が3項目あります。
- 作成されるファイルを .ex5にコンパイルするため、 .mq5 ( .mqhではない)の拡張子を持つ必要があります。
- ファイルには#property ライブラリのプロセッサ命令が含まれます。
- キーワード『エクスポート』は必要なエクスポート関数のヘッダーの後につける必要があります。
例1 他のプログラムで使用するための関数を作成します。 //--- library.mq5 #property library int libfunc (int a, int b) export { int c=a+b; Print("a+b="+string(с)); return(с); }
このファイルをコンパイルした後、libfuncが別のプログラムで使用可能となる元の library.ex5ファイルを取得します。
関数インポート手順はとてもシンプルです。それは#import プロセッサ命令を使用して実行されます。
例2 われわれのスクリプトではエクスポート関数 libfunc() を使用します。 //--- uses.mq5 #import "library.ex5" int libfunc(int a, int b); #import void OnStart() { libfunc(1, 2); }
コンパイラはMQL5\Libraries フォルダ内に.ex5ファイルを検索することを忘れないでください。よってそのフォルダにlibrary.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 ファイルは本稿末尾にあります。ここでは関数 Editを描くテンプレート例を1例だけ挙げます。
//+------------------------------------------------------------------+ //| 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に実装されます。
例3 インポートされた関数の使用 //--- 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); }
Expert Advisorの実行に続いてオブジェクトがチャートに表示されます。
ご覧のように、関数のエクスポートとインポートはまったく難しいものではありませんが、ヘルプ:エクスポート、 インポートで一定の制約について一読することを忘れないでください。
2. クラスの非表示実装のエクスポート
MQL5 のクラスはまだ直接エクスポートできないため、なにかすてきなメソッドに再ソートする必要があります。それは関数 polymorphismとvirtualを基にしています。実際、ex5 モジュールから返されるのはクラスそのものではなく、作成されたオブジェクです。 それを非表示実装オブジェクトと呼びましょう。
そのメソッドの基本は関数および変数の宣言がパブリックアクセスに対してオープンとなり、それらの実装詳細が閉じられた.ex5ファイルで非表示となるように要求されるクラスを二分することです。
これは以下のように簡単に例示することができます。そこには実装の詳細を公開することなく他の開発者と共有するCSpiro クラスがあります。それに変数、コンストラクタ、デストラクタ、ワーキング関数が含まれているとします。
クラスをエクスポートするには以下の手順に従います。
- CSpiroクラスから派生するクラスのクローンを作成します。それをISpiro(最初の文字 C を Iと置き換えます。その I は, 「interface:インターフェース」から来ています)と呼ぶことにします。)
- 変数およびダミー関数はすべて最初の CSpiroクラスに残します。
- 関数実装詳細は新しいISpiro クラスからきます。
- 閉じられたISpiroのインスタンスを作成するエクスポート関数にそれを追加します。
- 注意!要求される関数はすべてvirtualの接頭辞を持つ必要があります。
結果、ファイルを2件取得します。
例4 ex5 モジュールへのクラス実装非表示 //--- 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); } //+------------------------------------------------------------------+
ご覧のように非表示クラスは.mq5ファイルに実装され、そこにはプリプロセッサ命令#property ライブラリが含まれます。よって前項で表されたすべてのルールが見つかります。
また、SetPoint関数のための スコープ解決演算子にも注意します。それはGraph ライブラリおよび CSpiroクラスの両方で宣言されます。コンパイラが要求される関数を呼ぶために、:: アクションを用いてそれを明確に指定し、ファイル名をつける必要があります。
Graph::SetPoint(0, m_sID+"pnt."+string(x)+"."+string(y), 0, x, y, m_clr);
これでヘッダファイルをインクルードし、その実装を結果としてもたらされた Expert Advisorにインポートすることができます。
これは概略的に以下のように示されます。
例5 エクスポートオブジェクトの使用 //--- 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 がインクルードファイルglobals.mqhからの変数を使用するというのはよくあることです。こういった変数は同じ方法でみなさんご自身の別ファイルでも使用するべくインクルードすることができます。
たとえば以下です:
例6 パブリックインクルードファイル //--- globals.mqh #include <Trade\Trade.mqh> //--- instance of the trade function object extern CTrade *_trade;
_trade オブジェクトのただひとつのインスタンスがご自身のプログラムで初期化され、そのうえ非表示 ISuperClassクラスで使用されます。
このために、作成したオブジェクトに対するポインターISuperClass クラスから .ex5 ファイルに渡される必要があります。
それは以下のようにオブジェクトが .ex5 ファイルから受け取られるときに簡単に行われます。
例7 オブジェクト作成時の変数初期化 //--- 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 関数のヘッダーファイルを変更するのを好まない方は連動するグローバル関数や関数を統合する特別なクラスを作成するのが良いでしょう。
例8 パブリックなインクルードファイル //--- 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ファイルは以下のように実装されます。
例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
関数呼び出しは今シンプルな形に、そしてもっとも重要なのは、拡張可能な形式に変換されます。
例10 パブリックなグローバル変数にてのエクスポートオブジェクト使用 //--- 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. エクスポートクラスの継承
すでにオブジェクトをエクスポートするこの方法は直接のシンプルな継承は問題外であることを意味していることがわかります。非表示実装オブジェクトのエクスポートはオブジェクトそのものは継承連鎖の最終リンクであり、最終的に使用可能であることを示唆しています。
一般的には別個に中間クラスを書くことで継承の『エミュレーション』が作成可能です。そしてもちろんここで多様性と実質的にそうであることが必要です。
例11 非表示クラス継承のエミュレーション //--- 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の変数へのアクセスです。ご覧のようにそれらは派生クラスの宣言にはなく、変数 _base内にセットされています。これは通常ヘッダークラスSuperClass.mqhがあるという利便性には影響しません。
当然、ノウハウ関数に主に注目するとそれにしたがってあらかじめISuperClassのラッパーを作成する必要はありません。そういったノウハウ関数をエクスポートし、外部の開発者に自身のラッパークラスを作成してもらうのです。その方が継承もしやすくなります。
- クラス自立関数のエクスポート
- ヘッダー .mqh ファイルとその .ex5 実装
- .ex5 における変数初期化
5. ex5 ライブラリの発行
2011年11月、MetaQuotes はファイルリポジトリへのアクセスを提供し始めました。発表でその件に関しての情報を見ることができます。
このリポジトリ によってみなさんの開発したものを格納することができ、またより重要なことは他の開発者がそこにアクセスできることです。このツールでご自身の新しいバージョンのファイルを簡単に発行できるようになり、他の開発者がそれらファイルを使用するためにそこに早くアクセスできることを保証します。
それ以上に企業ウェブサイトでは商業的にまたは無料Marketにおいてご自身の関数ライブラリを提供することができます。
おわりに
これで関数エクスポートを伴う ex5 ライブラリとクラスオブジェクトの作成方法を理解し、その知識を実践に応用できるようになりました。こういったリソースにより他の開発者と緊密な協力関係を築くことができます。共通のプロジェクトで作業する、マーケットでそのようなプロジェクトを ex5 ライブラリ関数にアクセスできるようにする、などです。
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/362





- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索