English Русский 中文 Español Deutsch Português 한국어 Français Italiano Türkçe
EX5 ライブラリ使用による開発プロジェクトの促進

EX5 ライブラリ使用による開発プロジェクトの促進

MetaTrader 5 | 30 11月 2015, 08:38
1 344 0
---
---

はじめに

教養ある読者の方にはライブラリに関数やクラスの実装を非表示にする目的を説明するまでもないでしょう。新しい考えを積極積に探している方はex5 ファイルにクラス/関数の実装詳細を隠すことでノウハウアルゴリズムを他の開発者と共有し、共通のプロジェクトを設定し、ウェブ上でそれらを進めていくことができるようになるということを知りたいを思うものです。

そして MetaQuotes チームが ex5 ライブラリクラスの直接継承機能を実現することに全力を傾ける一方で、われわれはそれをいますぐ実装していこうとしているのです。

コンテンツ一覧

1. 関数のエクスポートとインポート
2. クラスの非表示実装のエクスポート
3. .ex5 ファイルにおける変数初期化
4. Export クラスの継承
5. ex5 ライブラリの発行


1. 関数のエクスポートとインポート

これはクラスのエクスポートの背後にある基本メソッドです。他のプログラムでご自身の関数を使用可能にするために考慮すべき主要な事柄が3項目あります。

  1. 作成されるファイルを .ex5にコンパイルするため、 .mq5 ( .mqhではない)の拡張子を持つ必要があります。
  2. ファイルには#property ライブラリのプロセッサ命令が含まれます。
  3. キーワード『エクスポート』は必要なエクスポート関数のヘッダーの後につける必要があります。
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 のクラスはまだ直接エクスポートできないため、なにかすてきなメソッドに再ソートする必要があります。それは関数 polymorphismvirtualを基にしています。実際、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 ファイルから受け取られるときに簡単に行われます。

 オブジェクト作成時の変数初期化

//--- 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 ファイルとクラスの設定全体に気を配る必要があります。
  1. クラス自立関数のエクスポート
  2. ヘッダー .mqh ファイルとその .ex5 実装
  3. .ex5 における変数初期化


5. ex5 ライブラリの発行

2011年11月、MetaQuotes はファイルリポジトリへのアクセスを提供し始めました。発表でその件に関しての情報を見ることができます。

このリポジトリ によってみなさんの開発したものを格納することができ、またより重要なことは他の開発者がそこにアクセスできることです。このツールでご自身の新しいバージョンのファイルを簡単に発行できるようになり、他の開発者がそれらファイルを使用するためにそこに早くアクセスできることを保証します。

それ以上に企業ウェブサイトでは商業的にまたは無料Marketにおいてご自身の関数ライブラリを提供することができます。


おわりに

これで関数エクスポートを伴う ex5 ライブラリとクラスオブジェクトの作成方法を理解し、その知識を実践に応用できるようになりました。こういったリソースにより他の開発者と緊密な協力関係を築くことができます。共通のプロジェクトで作業する、マーケットでそのようなプロジェクトを ex5 ライブラリ関数にアクセスできるようにする、などです。


MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/362

添付されたファイル |
spiro.zip (3.91 KB)
合成バー - 値の視覚情報を表示する新次元 合成バー - 値の視覚情報を表示する新次元
バーや日本製のローソク足を使って値情報を表示する古典的な方法の主な欠点は、それらが期間にたよっている、ということです。これらの方法がつくられた頃では大変良いものであったかもしれませんが、マーケットの値動きが、ときに急な動きをする今日では、このやり方でチャートに表示された値は新たな値動きに素早く反応するのには役立ちません。ここで紹介するプライスチャート表示方法はこの欠点がなく非常に分かり易いレイアウトで表示されます。
指数平滑化を利用した時系列予測(続編) 指数平滑化を利用した時系列予測(続編)
本稿はすでに作成済みのインディケータをグレードアップを模索し、 またブート処理と変位値を利用して予測信頼区間を推定するための手法を簡単に取り上げます。その結果、予測精度を推定するために用いる予測インディケータおよびスクリプトを手にすることになります。
ランダムサンドボックス ランダムサンドボックス
本稿は、インタラクティブな"サンドボックス"について書かれています。エクセルファイルが、ランダム化したエキスパートアドバイザーのバックテストデータをシュミレートします。読者の皆さんは、これを使えば、初期状態のMetaTraderが提供するEAパフォーマンスのメトリックスを探求する手助けとなり、より多くのことを理解できるようになります。本稿の文書はこの経験則を通じユーザーの皆さんに理解してもらえるように書かれています。
ポイントおよびグラフチャート化インディケータ ポイントおよびグラフチャート化インディケータ
現在マーケットの状況に関する情報を提供するチャートは数多くあります。「ポイント」や「グラフ」チャートのようにそれらの多くは遠い過去の遺産です。本稿は実時間のインディケータを用いて「ポイントとグラフ」チャート例について述べます。