クロスプラットフォームEA:序章
目次
イントロダクション
メタトレーダーでクロスプラットフォームのEAを作成する理由には、次があります
- 使用している取引プラットフォームのバージョンに関係なく、他人のEAを共有することが可能になります。
- MQL4とMQL5の違いを理解しておきましょう。
- コーディングの時間を節約します。
- MT4は古いソフトウェアになりつつあり、MT5に移行しつつあります。
- しかし、すでにMT5ユーザーでも、何らかの理由で、MT4でEAをテストしたいことがあります。
- また、MT4のユーザーでも、ロボットを最適化するために、MQL5クラウドサービスを使用したい場合があります。
EA、インジケーターやスクリプトを開発する場合、開発者は通常、次のような対策をします。
- 1言語を使用してソフトウェアを開発(MQL4またはMQL5)
- 開発したソフトウェアを徹底的にテスト
- 他の言語と同じソフトウェアを再実装
これには、いくつかの欠点があります。
- ソフトウェアは、両方のバージョンが共有する部品や関数を含め、再実装する必要があります
- デバッグとメンテナンスが困難な場合があります。
- 生産性が低下します。
MQL4、MQL5:独立した、並列実装はほぼ倍の量のコードが必要です。デバッグとメンテナンスがより一層大変になります。バージョンを更新する必要がある場合、同じ更新内容を、他のバージョンにも同様に導入する必要があるかもしれません。そして、MQL4とMQL5間の違いに起因して、同じソフトウェアの2つのバージョンはいくつかの点で発散しなければなりません。コードのずれは、しばしば明確に並列実装を使って配置されていないので、潜在的に多くの問題をもたらします。
Hello WorldのEAサンプル
ハローワールドEA:MQL5のシンプルなEAから始めましょう。次のソースコードに示すように、一般的に書きます:
(HelloWorld.mq5)
#include <Object.mqh> //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CHelloWorld : public CObject { public: CHelloWorld(void); ~CHelloWorld(void); virtual void Greeting(void); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorld::CHelloWorld(void) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorld::~CHelloWorld(void) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorld::Greeting(void) { Print("Hello World!"); } CHelloWorld hello; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- hello.Greeting(); ExpertRemove(); }
MQL4では、同じようなルールで記述します。:
HelloWorld.mq4
#include <Object.mqh> //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CHelloWorld : public CObject { public: CHelloWorld(void); ~CHelloWorld(void); virtual void Greeting(void); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorld::CHelloWorld(void) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorld::~CHelloWorld(void) { } CHelloWorld hello; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- hello.Greeting(); ExpertRemove(); }
ソースとヘッダ・ファイル
先に示した2つのソースファイルが同じであることに注意してください。クロスプラットフォームの互換性のある単一のソースファイルを持つことは不可能です。これは、ソースファイルがコンパイルされているかどうかによるものです:
- MQ4ソースファイルをコンパイル、EX4ファイルの生成
- MQ5ソースファイルをコンパイルすると、EX5ファイルになります。
両方のプラットフォーム上で動作する単一のソースファイルを持つことができない場合があります。しかし、次の図に示されているように、単一のヘッダファイルを参照するために、両方のソースファイルを有することが可能です。
ヘッダー・ファイルをリンクする:理想的には、2つのソースファイルは、ソースコードの単一の行を持ち、ヘッダファイルを持っています。次のようにHello WorldのEAのヘッダファイルを書き換えることができます。
HelloWorld_SingleHeader.mqh
#include <Object.mqh> //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CHelloWorld : public CObject { public: CHelloWorld(void); ~CHelloWorld(void); virtual void Greeting(void); virtual void Greeting(const string str1,const string str2); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorld::CHelloWorld(void) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorld::~CHelloWorld(void) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorld::Greeting(void) { Print("Hello World!"); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorld::Greeting(const string str1,const string str2) { string str=NULL; Print(StringConcatenate(str,str1,str2)); } CHelloWorld hello; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- hello.Greeting("Hello ","World!"); ExpertRemove(); } //+------------------------------------------------------------------+
MQL4とMQL5ソースファイルは、それぞれ上記のヘッダファイルを参照し、#includeディレクティブがあるコード行を含みます:
HelloWorld_SingleHeader.mq4 及び HelloWorld_SingleHeader.mq5
#include <HelloWorld_SingleHeader.mqh>
このアプローチは利点がいくつかあります。まず、50%まで(少なくともこの例では)2つのプラットフォームに書かれたソースコードの量を減らすことができます。第2の利点は、このセットアップは、別々のものではなく、単に1つのインプリメンテーション上で動作することを可能にするということです。上で動作する唯一のソースがあるので、MQL4のバージョンに加えられた変更は、MQL5のバージョンに適用されます。
一つのソースファイルを変更する場合、他のプラットフォームのソースファイルに個別に変更を適用する必要があります。EAはこの例のように書かれていません。はるかに複雑です。EAが複雑になるにつれて、2つの別々のバージョンを維持することがますますハードになるでしょう。。
条件付きコンパイル
MQL4とMQL5には共通点が多く、また、多くの点で異なっています。これらの違いには、文字列の連結関数があります。MQL4では、関数は、次のように定義されます。
string StringConcatenate( void argument1, // シンプルタイプの第1パラメータ void argument2, // シンプルタイプの第2パラメータ ... // シンプルタイプの次のパラメータ );
MQL5では、関数が若干異なります。
int StringConcatenate( string& string_var, // string から form void argument1 // シンプルタイプの第1パラメータ void argument2 //任意の単純型の2番目のパラメータ ... // シンプルタイプの次のパラメータ );
Greeting() メソッドをオーバーロードすることによって、Hello Worldアプリケーションでこの関数を使用することができます。新しいメソッドは、その連結結果端末に表示される2つの文字列引数、およびを受け入れます。、次のようなヘッダファイルを更新します。
(HelloWorld_SingleHeader.mqh)
#include <Object.mqh> //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CHelloWorld : public CObject { public: CHelloWorld(void); ~CHelloWorld(void); virtual void Greeting(void); virtual void Greeting(const string str1,const string str2); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorld::CHelloWorld(void) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorld::~CHelloWorld(void) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorld::Greeting(void) { Print("Hello World!"); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorld::Greeting(const string str1,const string str2) { string str=NULL; Print(StringConcatenate(str,str1,str2)); } CHelloWorld hello; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- hello.Greeting("Hello ","World!"); ExpertRemove(); } //+------------------------------------------------------------------+
MT4に、この更新されたバージョンを使用すると、端末に表示次のような結果を見ることになります。
Hello World!
MT5では、本来意図されたものとは異なる結果を見るでしょう:
12
MQL4では、関数は、連結テキストを表す文字列を返します。一方、MQL5に、連結された文字列のサイズを表す整数値を返します。コードの大部分をやり直すことなく、アプリケーションが2つのプラットフォームで同じ挙動を示すようにするために、単に使用することができます条件付きコンパイル、次のコードに示すように:
CHelloWorld::Greeting(const string str1,const string str2) { #ifdef __MQL5__ string str=NULL; StringConcatenate(str,str1,str2); Print(str); #else Print(StringConcatenate(str1,str2)); #endif }
これはプリプロセッサディレクティブであることに注意してください。実行時間の追加コンパイル時にオーバーヘッドではなく、あるかもしれません。MQL4では、コンパイラは次のように上記のコードを解釈します:
CHelloWorld::Greeting(const string str1,const string str2) { Print(StringConcatenate(str1,str2)); }
次のように一方、MQL5コンパイラはコードが表示されます。
CHelloWorld::Greeting(const string str1,const string str2) { string str=NULL; StringConcatenate(str,str1,str2); Print(str); }
スプリット実装
この時点で、すでにクロスプラットフォームの互換性のEAを作成するために存在するどのような種類のコードの理解することができます:
- Compatible
- 共有関数
- 計算
- 互換性がありません
- 異なる動作を関数
- 1で利用可能な関数はなく、他に
- 実行の異なるモード
MQL4とMQL5の間で、同じように動作する関数のセットが存在します。Print()関数は、1つの例です。それは関係なく、専門家アドバイザーが使用するプラットフォームのバージョンと同じように動作しません。互換性のあるソースコードは、純粋な計算の形で見ることができます。1+1の結果は、MQL4とMQL5の両方で同じだけでなく、任意の実世界のプログラミング言語になります。どちらの場合も、分割実装はほとんど必要ありません。
ソースコードの特定の部分がコンパイルされませんいずれか、または1つのプラットフォームで異なって実行される例では、分割の実装が必要になります。文字列連結関数は、互換性のないコードの最初の場合の例です。同じ名前を持つにもかかわらず、MQL4とMQL5で動作が異なります。他の言語では直接対応するものがないいくつかの関数もあります。例では、少なくともこの記事の執筆時点までに、MQL4には同等のを持っていない、注文のCalcマージン関数、です。第三の場合は、実装は、別の開発者と異なる場合がありどこそれがここにあるように、おそらくクロスプラットフォーム開発のために取り扱いが最も困難です。この場合、2つのプラットフォーム間の共通点は、必要に応じてコード長、その後スプリット実装を軽減するために必要とされるかもしれない見つけます。
今、単に条件付きコンパイルに頼ることは悪い考えかもしれません。コードが長くなるにつれて、これらのステートメントの多くを持つことはコードの保守対デバッグが非常に困難になります。(1)ベースの実装、(2)MQL4固有の実装、および(3)MQL5固有の実装:オブジェクト指向プログラミングでは、3つの部分に実装を分割する必要があるかもしれません。
基底クラスの実装では、両方のバージョンで共有されているコードが含まれます。非互換性が生じた場合には、1は基本実装から外れ、あるいは空の基本実装を残して、両方の言語に別々の実装を適用することができます。
Hello WorldのEAのために、MQL4とMQL5の両方で共有されているコードが含まれているためにそれを使用し、それをこのようなCHelloWorldBaseなどの名前を付け、および、基本クラスを宣言します。これは、この記事の最初に定義された初期グリーティング()メソッドが含まれています。
HelloWorld_SingleHeader.mqh
#include <Object.mqh> //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CHelloWorldBase : public CObject { public: CHelloWorldBase(void); ~CHelloWorldBase(void); virtual void Greeting(void); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorldBase::CHelloWorldBase(void) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorldBase::~CHelloWorldBase(void) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorldBase::Greeting(void) { Print("Hello World!"); } //+------------------------------------------------------------------+
、その後、基本クラスから継承し、同じ所望の結果を達成するために、異なる実装を紹介するプラットフォームや言語固有のクラスのオブジェクトを行います。
HelloWorld_SingleHeader_MQL4.mqh
#include "HelloWorld_SingleHeader.mqh" //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CHelloWorld : public CHelloWorldBase { public: CHelloWorld(void); ~CHelloWorld(void); virtual void Greeting(const string str1,const string str2); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorld::CHelloWorld(void) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorld::~CHelloWorld(void) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorld::Greeting(const string str1,const string str2) { Print(StringConcatenate(str1,str2)); } //+------------------------------------------------------------------+
HelloWorld_SingleHeader_MQL5.mqh
#include "HelloWorld_SingleHeader.mqh" //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CHelloWorld : public CHelloWorldBase { public: CHelloWorld(void); ~CHelloWorld(void); virtual void Greeting(const string str1,const string str2); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorld::CHelloWorld(void) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorld::~CHelloWorld(void) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorld::Greeting(const string str1,const string str2) { string str=NULL; StringConcatenate(str,str1,str2); Print(str); } //+------------------------------------------------------------------+
、それらは通常、メインソースファイル内にある、発見された場所に戻ってイベント関数を移動します。
HelloWorld_SingleHeader.mq5
#include <HelloWorld_SingleHeader_MQL5.mqh> CHelloWorld hello; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- hello.Greeting("Hello ","World!"); ExpertRemove(); } //+------------------------------------------------------------------+
HelloWorld_SingleHeader.mq4
#include <HelloWorld_SingleHeader_MQL4.mqh> CHelloWorld hello; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- hello.Greeting("Hello ","World!"); ExpertRemove(); } //+------------------------------------------------------------------+
この特定の例では、ベースクラス、および条件付きコンパイル命令内の二つの下位クラスを含む、単一のヘッダを使用することがより実用的です。しかし、ほとんどの場合、ファイルを分離するためのクラスを移動すると、関連するソースコードが長い場合は特に必要です。
ファイルのインクルード
開発者は、単に実際のクラス定義を含むヘッダ・ファイルは、プログラムで使用することを参照することは自然です。たとえば、HelloWorldのEAのMQL5の実装では、二つのバージョン(HelloWorld_SingleHeader.mq4とHelloWorld_SingleHeader.mq5)は、含まれ、特定のヘッダファイルを除いて、実質的に同じであることがわかります。
#include <HelloWorld_SingleHeader_MQL4.mqh>
#include <HelloWorld_SingleHeader_MQL5.mqh>
別のアプローチは、基本実装を含むヘッダファイルを参照することです。そして、そのヘッダファイルの最後に、ヘッダファイル、適用可能な子孫を含む使用されているコンパイラの種類に応じて参照するために、条件付きコンパイルディレクティブを使用することができます。#include <Object.mqh> //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CHelloWorldBase : public CObject { public: CHelloWorldBase(void); ~CHelloWorldBase(void); virtual void Greeting(void); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorldBase::CHelloWorldBase(void) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorldBase::~CHelloWorldBase(void) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorldBase::Greeting(void) { Print("Hello World!"); } //+------------------------------------------------------------------+ #ifdef __MQL5__ #include "HelloWorld_SingleHeader_MQL5.mqh" #else #include "HelloWorld_SingleHeader_MQL4.mqh" #endif //+------------------------------------------------------------------+
それから、むしろ言語固有のヘッダファイルよりも、メインのソース・ファイルにこのヘッダー・ファイルを参照します。
#include <HelloWorld_SingleHeader.mqh> CHelloWorld hello; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- hello.Greeting("Hello ","World!"); ExpertRemove(); } //+------------------------------------------------------------------+
この後、言語固有の実装を含むヘッダファイルの書式#includeディレクティブを削除(取り消し線テキストは、コードが削除され表示されます):
#include "HelloWorld_SingleHeader.mqh" //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CHelloWorld : public CHelloWorldBase { public: CHelloWorld(void); ~CHelloWorld(void); virtual void Greeting(const string str1,const string str2); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorld::CHelloWorld(void) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorld::~CHelloWorld(void) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorld::Greeting(const string str1,const string str2) { Print(StringConcatenate(str1,str2)); } //+------------------------------------------------------------------+ #include "HelloWorld_SingleHeader.mqh" //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CHelloWorld : public CHelloWorldBase { public: CHelloWorld(void); ~CHelloWorld(void); virtual void Greeting(const string str1,const string str2); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorld::CHelloWorld(void) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorld::~CHelloWorld(void) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorld::Greeting(const string str1,const string str2) { string str=NULL; StringConcatenate(str,str1,str2); Print(str); } //+------------------------------------------------------------------+
このアプローチは、推奨されると、いくつかの利点を有しています。まず、それはMQL4とMQL5メインソースファイルの両方に対して同じ含まディレクティブを保持します。また、所与のプロセッサディレクティブを含めるには、(例えばはMQL4/またはMQL5を/含む)に含まれ、どのパスするためにどの特定のヘッダファイルを考えるの精神的オーバーヘッドを節約できます。第3の利点は、それが基本ヘッダファイルにベース介在物を保持することです。一つは言語固有のヘッダファイルのインクルードディレクティブを使用する場合、それはそのバージョンのみ(MQL4またはMQL5)専用に使用されるでしょう。
分割ディレクトリとファイル
OOPにEAを開発する場合1は、単一のクラス定義の下にあるすべてのものをコーディングするために、それは確かにそうです。この一証明はMQL5標準ライブラリの取引戦略クラスです。コードの行が増加するように、様々なヘッダファイルの中でコードを分割することがより実用的であり得ます。この資料では、以下のディレクトリ形式をお勧めします。
|-Include
|-Base
|-MQL4
|-MQL5
3つのディレクトリは、当該フォルダ内のデータフォルダ内の右インクルードディレクトリ内に置かれた、またはサブディレクトリにすることができます。
コード例では、以下のディレクトリ構造を採用します:
|-Include
|-MQLx-Intro
|-Base
HelloWorldBase.mqh
|-MQL4
HelloWorld.mqh
|-MQL5
HelloWorld.mqh
このようなディレクトリ構造を使用すると、コードをより良い組織を与えます。また、ファイルは、以前に回避しようとしていた衝突を命名の問題を排除するでしょう。
当社のヘッダファイル用のディレクトリの場所の変更に、その2つの子孫の新しい場所を持つクラスのために主なヘッダー・ファイルを更新する必要があります。
#include <Object.mqh> //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CHelloWorldBase : public CObject { public: CHelloWorldBase(void); ~CHelloWorldBase(void); virtual void Greeting(void); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorldBase::CHelloWorldBase(void) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorldBase::~CHelloWorldBase(void) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CHelloWorldBase::Greeting(void) { Print("Hello World!"); } //+------------------------------------------------------------------+ #ifdef __MQL5__ #include "..\MQL5\HelloWorld.mqh" #else #include "..\MQL4\HelloWorld.mqh" #endif //+------------------------------------------------------------------+
また、当社は、基本クラスの更新された場所で主なソースファイルを更新します。両方のバージョンの場合は、ソースファイルは既にこの段階で同じになります。
HelloWorld_Sample.mq4 及び HelloWorld_Sample.mq5
#include <MQLx-Intro\Base\HelloWorldBase.mqh> CHelloWorld hello; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- hello.Greeting("Hello ","World!"); ExpertRemove(); } //+------------------------------------------------------------------+
継承
さよなら世界という名前のクラスのように、先に定義されたHelloWorldクラスを拡張したいと仮定しましょう。このクラスは、というメッセージを作成するために、CHelloWorldのGreeting() メソッドを使用します"さよなら世界を!」。(推奨)、それを行うための1つの方法は、CHelloWorldBaseある先祖の基底クラスを、参照することです。そして、CHelloWorldBaseと同様に、正しい子孫を参照し、このファイルの最後にプリプロセッサの条件付きコンパイル・ディレクティブが含まれています。継承階層は次のようになり
しかし、ヘッダファイルが少し異なるものになります:
クラスを下図に示します。最初のGreeting関数は、CHelloWorld基本クラスであり、このメソッドは、他のすべての下位クラスにまたがって使用(継承)されます。同じことがまた、新しいメソッドCGoodByeWorldについても同様です。「こんにちは」、「さようなら」と言うのではなく、CHelloWorldBaseメソッドを拡張することも可能です。
基本クラスのヘッダーファイルが含まれています。このファイルを参照すると、自動的に他の必要なヘッダファイルが含まれているため、単一のクラス階層が関与しています。このケースでは、GoodByeWorldBase.mqhと、基本クラスのヘッダーファイルが含まれています。ベース・ヘッダ・ファイルなので、プラットフォーム固有のヘッダファイルを参照する#includeを使用しないことに注意してください。
ディレクトリ構造が完了した時点で、新しいヘッダーファイルが含まれていることになり、更新されます。
|-Include
|-MQLx-Intro
|-Base
HelloWorldBase.mqh
GoodByeWorldBase.mqh
|-MQL4
HelloWorld.mqh
GoodByeWorld.mqh
|-MQL5
HelloWorld.mqh
GoodByeWorld.mqh
以下はCGoodByeWorldBaseクラスです:
#include "HelloWorldBase.mqh" //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CGoodByeWorldBase : public CHelloWorld { public: CGoodByeWorldBase(void); ~CGoodByeWorldBase(void); virtual void GoodBye(void); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CGoodByeWorldBase::CGoodByeWorldBase(void) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CGoodByeWorldBase::~CGoodByeWorldBase(void) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CGoodByeWorldBase::GoodBye(void) { Greeting("Goodbye ","World!"); } //+------------------------------------------------------------------+ #ifdef __MQL5__ #include "..\MQL5\GoodByeWorld.mqh" #else #include "..\MQL4\GoodByeWorld.mqh" #endif //+------------------------------------------------------------------+
ファイルに「HelloWorldのBase.mqh」を含めても、CGoodByeWorld基本クラスはHelloWorldのCHelloWorldBaseから継承することに注意してください。最終的にはMQLコンパイラのバージョンによって異なるCHelloWorldのバージョンが使用されています。CHelloWorldBaseはまた別で動作します。Goodbye()メソッドはGreeting()メソッドを使用しているので、この例では、CGoodByeWorldBaseはCHelloWorldのプラットフォームの実装から直接継承する必要があります。
GoodBye()メソッドは、2つのバージョン間で共有することができるので、ベースの実装内で維持するのに理想的です。このクラスオブジェクトには、他の付加的なメソッドは存在しないので、子や孫は、新しいクラスメソッドを欠くことになります。次のようにして子クラスを実装できます。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CGoodByeWorld : public CGoodByeWorldBase { }; //+------------------------------------------------------------------+
メインソースファイルはCGoodByeWorldに基づいてオブジェクトをインスタンス化し、OnTickのハンドラ内GoodBye()メソッドを呼び出して、同様に更新されるように、時間が必要になります。
HelloWorld_Sample.mq4 及び HelloWorld_Sample.mq5
#include <MQLx-Intro\Base\GoodByeWorldBase.mqh> CGoodByeWorld hello; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- hello.Greeting("Hello ","World!"); hello.GoodBye(); ExpertRemove(); } //+------------------------------------------------------------------+
EAを実行すると、端末に次のような結果が出力されます:
Hello World!
Goodbye World!
ExpertRemove() function called
制限事項
ほとんどの場合、このアプローチは、より迅速かつ効率的なクロスプラットフォームのEAを開発できます。しかし、この記事で適用することが困難な可能性のある制約を知る必要があります。
1。メタトレーダー4の制限
2。2つのプラットフォーム間で大きく異なる規則
MT4は古い取引プラットフォームで、MT5で利用可能な特定の関数を欠いています。一つのプラットフォームに欠けている関数が必要な場合には、もう一方のバージョン専用のカスタムソリューションを開発する必要があります。これは主にMT4に対応している必要があるMT5ネイティブEAの問題です。MT4は、ほとんどの関数として、少なくとも簡単な回避策を持っています。
2つのプラットフォームは、いくつかの操作が異なります。これは、トレード操作に特に当てはまります。この場合、開発者はどちらかを選択する必要があります。例えば、MT4の表記法を使用し、同じ動作を実現するために、MT5にそれらを変換することができます。または正反対は、MT4にMT5取引に慣習的なアプローチを適用する必要があります。
結論
この記事では、クロスプラットフォームEAを開発することができるメソッドを実証しています。このメソッドは、両方の取引プラットフォームで共有される実装が含まれている基本クラスを提案しました。二つの言語が互いに外れる場合は、この基本クラスから継承するクラスとして導入することができます。同様のメソッドが、クラス内にさらに定義される必要があるクラスに対して繰り返されます。このメソッドは、より少ない時間でクロスプラットフォームアプリケーションの開発に役立ち、独立した並列実装を実現する必要性を回避することによって、簡単にコードの保守を行うことができます。
MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/2569
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索