English Русский 中文 Español Deutsch Português
クロスプラットフォームEA:MQL5標準ライブラリからコンポーネントの再利用

クロスプラットフォームEA:MQL5標準ライブラリからコンポーネントの再利用

MetaTrader 5統合 | 20 9月 2016, 13:29
1 511 0
Enrico Lambino
Enrico Lambino

目次


イントロダクション

クロスプラットフォームのEA開発に有用なMQL5標準ライブラリコンポーネントが存在します。しかし、MQL4コンパイラと互換性のないMQL4クロスプラットフォームでは使用できなくなります。この場合、少なくとも2つの選択肢があります。

  • 両方のバージョンでサポートされるコンポーネントを保ち、スクラッチから書き直します。
  • クラスをコピーし、ヘッダファイルをを変更します。

この記事では、2番目オプションを検討します。このメソッドを使用すると、MQL4側でかなり緩い実装になるでしょう。しかし、その主な欠点として、多くコードを書き直す必要ないことです。また、最初からすべてを書き換えるよりも、MQL5クラスの最新バージョンにアップデートするでしょう。


フォルダ構成

使用するほとんどクラスとは異なり、MQL5標準ライブラリから再利用するクラスオブジェクトは、MQL4データフォルダincludeフォルダ内のどこかにコピーする必要あります。そのため、バージョンに関係なく、使用することできるでしょう。メソッドは変更になる場合あります。しかし、最も簡単なメソッドは、特定ヘッダファイルをリンクし、ヘッダファイルを作ることです。これは通常、カスタムメイドのクラスオブジェクト上で行われます。

  1. MQL5バージョンについて、メインヘッダファイルは、使用するヘッダファイルの元ファイルにリンクする必要あります。

  2. MQL4バージョンについて、メインヘッダファイルは、使用するMQL5ヘッダーファイル(修正)にリンクする必要あります。

このメソッドは、ベースディレクトリ内に「Lib」フォルダを作成します。基本ヘッダファイルが配置されるでしょう。同様のフォルダ(クロスプラットフォームベッド)のクロスプラットフォームディレクトリMQL4フォルダ下に作成されます。MQL5クラスが配置されます。

|-Include

|-MQLx-Reuse

|-Base

|-Lib

<Main Header Files>

|-MQL4

|-Lib

<MQL5ヘッダファイルコピー>

|-MQL5

もともとMQL5データフォルダ内のように、メインヘッダファイルはヘッダファイルに直接リンクすることになるで、MQL5フォルダは「Lib」フォルダを持っていません。例えば、クロスプラットフォームのEAには、 CSymbolInfoを再利用する必要あるとします。特定クラスは、トレードクラス下で、MQL5標準ライブラリの一部です。以下を使用してアクセスすることできます。#include

#include <Trade\SymbolInfo.mqh>

現在の設定でこれを使用するため、次のコードで、ベースlibフォルダ下にメインヘッダファイルを作成する必要があります。

(/Base/Lib/SymbolInfo.mqh)

#ifdef __MQL5__
   #include <Trade\SymbolInfo.mqh>
#else
   #include "..\..\MQL4\Lib\SymbolInfo.mqh"
#endif

MQL4バージョンは、「Lib」フォルダ内のヘッダファイルにディレクティブを呼び出します。しかし、それがカスタムディレクトリ(「MQL-リユース」)内「MQL4」フォルダ「リブ」フォルダになります。

先に述べたように、MQL5バージョンはベースフォルダにポジションするメインヘッダファイルにあるため、「リブ」フォルダを必要としません。クラス内にある<Trade\SymbolInfo.mqh>フォルダを含めます。

これは推奨のアプローチであり、決して強制的なものではありません。再利用またはMQL5から借用されたヘッダファイルに、別フォルダを持っている場合、便利です。


CSymbolInfo

コンパイル・エラーを生成するクラスヘッダーファイルでCSymbolInfoをコンパイルし、MQL4コンパイラを使用します。エラーは SymbolInfoDouble SymbolInfoIntegerで、MQL4との非互換性によって引き起こされます。これらの関数の呼び出し大部分は、Refresh() メソッド内で見ることできます。クラス内のCSymbolInfoコードを以下に示します。

bool CSymbolInfo::Refresh(void)
  {
   long tmp=0;
//---
   if(!SymbolInfoDouble(m_name,SYMBOL_POINT,m_point))
      return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_TRADE_TICK_VALUE,m_tick_value))
      return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_TRADE_TICK_VALUE_PROFIT,m_tick_value_profit))
      return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_TRADE_TICK_VALUE_LOSS,m_tick_value_loss))
      return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_TRADE_TICK_SIZE,m_tick_size))
      return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_TRADE_CONTRACT_SIZE,m_contract_size))
      return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_VOLUME_MIN,m_lots_min))
      return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_VOLUME_MAX,m_lots_max))
      return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_VOLUME_STEP,m_lots_step))
      return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_VOLUME_LIMIT,m_lots_limit))
      return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_SWAP_LONG,m_swap_long))
      return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_SWAP_SHORT,m_swap_short))
      return(false);
   if(!SymbolInfoInteger(m_name,SYMBOL_DIGITS,tmp))
      return(false);
   m_digits=(int)tmp;
   if(!SymbolInfoInteger(m_name,SYMBOL_ORDER_MODE,tmp))
      return(false);
   m_order_mode=(int)tmp;
   if(!SymbolInfoInteger(m_name,SYMBOL_TRADE_EXEMODE,tmp))
      return(false);
   m_trade_execution=(ENUM_SYMBOL_TRADE_EXECUTION)tmp;
   if(!SymbolInfoInteger(m_name,SYMBOL_TRADE_CALC_MODE,tmp))
      return(false);
   m_trade_calcmode=(ENUM_SYMBOL_CALC_MODE)tmp;
   if(!SymbolInfoInteger(m_name,SYMBOL_TRADE_MODE,tmp))
      return(false);
   m_trade_mode=(ENUM_SYMBOL_TRADE_MODE)tmp;
   if(!SymbolInfoInteger(m_name,SYMBOL_SWAP_MODE,tmp))
      return(false);
   m_swap_mode=(ENUM_SYMBOL_SWAP_MODE)tmp;
   if(!SymbolInfoInteger(m_name,SYMBOL_SWAP_ROLLOVER3DAYS,tmp))
      return(false);
   m_swap3=(ENUM_DAY_OF_WEEK)tmp;
   if(!SymbolInfoDouble(m_name,SYMBOL_MARGIN_INITIAL,m_margin_initial))
      return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_MARGIN_MAINTENANCE,m_margin_maintenance))
      return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_MARGIN_LONG,m_margin_long))
      return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_MARGIN_SHORT,m_margin_short))
      return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_MARGIN_LIMIT,m_margin_limit))
      return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_MARGIN_STOP,m_margin_stop))
      return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_MARGIN_STOPLIMIT,m_margin_stoplimit))
      return(false);
   if(!SymbolInfoInteger(m_name,SYMBOL_EXPIRATION_MODE,tmp))
      return(false);
   m_trade_time_flags=(int)tmp;
   if(!SymbolInfoInteger(m_name,SYMBOL_FILLING_MODE,tmp))
      return(false);
   m_trade_fill_flags=(int)tmp;
//--- succeed
   return(true);
  }


最初記事で説明したのと同様に、理想的には、MQL4とMQL5バージョン間のコードに類似点がある共通ヘッダーファイルを使用します。単一ファイルに共有できるように、3つの別々ファイルにCSymbolInfoを書き換えることで、他2つのクラスファイルにコード化されます。しかし、この記事では、簡単(かつ迅速)なアプローチを扱います:CSymbolInfoでMQL5シンボルをコピーし、MQL4と互換性ない行をコメントにします。結果ファイル構造は、以下ようになります。

ファイル構造内シンボル

こようなSYMBOL_TRADE_TICK_VALUE_PROFIT や SYMBOL_TRADE_TICK_VALUE_LOSSなど、一部のプロパティ識別子はMQL4でサポートされていません。これらが今後サポートされるという確信はありません。しかし、実際にサポートされるまではコメントで置くことはまだ良いです。また、新しい開発は、これらの関数の回避策が必要です。

次のコードで、falseを返すために最新情報に更新メソッド呼び出しを引き起こす可能性あるコメントと同じ関数を示しています。

bool CSymbolInfo::Refresh(void)
  {
   long tmp=0;
//---
   if(!SymbolInfoDouble(m_name,SYMBOL_POINT,m_point))
      return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_TRADE_TICK_VALUE,m_tick_value))
      return(false);
//if(!SymbolInfoDouble(m_name,SYMBOL_TRADE_TICK_VALUE_PROFIT,m_tick_value_profit))
//return(false);
//if(!SymbolInfoDouble(m_name,SYMBOL_TRADE_TICK_VALUE_LOSS,m_tick_value_loss))
//return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_TRADE_TICK_SIZE,m_tick_size))
      return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_TRADE_CONTRACT_SIZE,m_contract_size))
      return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_VOLUME_MIN,m_lots_min))
      return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_VOLUME_MAX,m_lots_max))
      return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_VOLUME_STEP,m_lots_step))
      return(false);
//if(!SymbolInfoDouble(m_name,SYMBOL_VOLUME_LIMIT,m_lots_limit))
//return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_SWAP_LONG,m_swap_long))
      return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_SWAP_SHORT,m_swap_short))
      return(false);
   if(!SymbolInfoInteger(m_name,SYMBOL_DIGITS,tmp))
      return(false);
   m_digits=(int)tmp;
//if(!SymbolInfoInteger(m_name,SYMBOL_ORDER_MODE,tmp))
//return(false);
//m_order_mode=(int)tmp;
   if(!SymbolInfoInteger(m_name,SYMBOL_TRADE_EXEMODE,tmp))
      return(false);
   m_trade_execution=(ENUM_SYMBOL_TRADE_EXECUTION)tmp;
   if(!SymbolInfoInteger(m_name,SYMBOL_TRADE_CALC_MODE,tmp))
      return(false);
   m_trade_calcmode=(ENUM_SYMBOL_CALC_MODE)tmp;
   if(!SymbolInfoInteger(m_name,SYMBOL_TRADE_MODE,tmp))
      return(false);
   m_trade_mode=(ENUM_SYMBOL_TRADE_MODE)tmp;
   if(!SymbolInfoInteger(m_name,SYMBOL_SWAP_MODE,tmp))
      return(false);
   m_swap_mode=(ENUM_SYMBOL_SWAP_MODE)tmp;
   if(!SymbolInfoInteger(m_name,SYMBOL_SWAP_ROLLOVER3DAYS,tmp))
      return(false);
   m_swap3=(ENUM_DAY_OF_WEEK)tmp;
   if(!SymbolInfoDouble(m_name,SYMBOL_MARGIN_INITIAL,m_margin_initial))
      return(false);
   if(!SymbolInfoDouble(m_name,SYMBOL_MARGIN_MAINTENANCE,m_margin_maintenance))
      return(false);
//if(!SymbolInfoDouble(m_name,SYMBOL_MARGIN_LONG,m_margin_long))
//return(false);
//if(!SymbolInfoDouble(m_name,SYMBOL_MARGIN_SHORT,m_margin_short))
//return(false);
//if(!SymbolInfoDouble(m_name,SYMBOL_MARGIN_LIMIT,m_margin_limit))
//return(false);
//if(!SymbolInfoDouble(m_name,SYMBOL_MARGIN_STOP,m_margin_stop))
//return(false);
//if(!SymbolInfoDouble(m_name,SYMBOL_MARGIN_STOPLIMIT,m_margin_stoplimit))
//return(false);
//if(!SymbolInfoInteger(m_name,SYMBOL_EXPIRATION_MODE,tmp))
//return(false);
//m_trade_time_flags=(int)tmp;
//if(!SymbolInfoInteger(m_name,SYMBOL_FILLING_MODE,tmp))
//return(false);
//m_trade_fill_flags=(int)tmp;
//--- succeed
   return(true);
  }

MQL5ではなくMQL4で利用可能な組み込み列挙あります。ヘッダ・ファイルはMQL4コンパイラを使用してコンパイルされるため、ENUM_SYMBOL_CALC_MODE と ENUM_SYMBOL_SWAP_MODEが必要とされるでしょう。これら列挙を含めるには、クラスヘッダファイルを宣言する必要あります:

enum ENUM_SYMBOL_CALC_MODE
  {
   SYMBOL_CALC_MODE_FOREX,
   SYMBOL_CALC_MODE_FUTURES,
   SYMBOL_CALC_MODE_CFD,
   SYMBOL_CALC_MODE_CFDINDEX,
   SYMBOL_CALC_MODE_CFDLEVERAGE,
   SYMBOL_CALC_MODE_EXCH_STOCKS,
   SYMBOL_CALC_MODE_EXCH_FUTURES,
   SYMBOL_CALC_MODE_EXCH_FUTURES_FORTS
  };
enum ENUM_SYMBOL_SWAP_MODE
  {
   SYMBOL_SWAP_MODE_DISABLED,
   SYMBOL_SWAP_MODE_POINTS,
   SYMBOL_SWAP_MODE_CURRENCY_SYMBOL,
   SYMBOL_SWAP_MODE_CURRENCY_MARGIN,
   SYMBOL_SWAP_MODE_CURRENCY_DEPOSIT,
   SYMBOL_SWAP_MODE_INTEREST_CURRENT,
   SYMBOL_SWAP_MODE_INTEREST_OPEN,
   SYMBOL_SWAP_MODE_REOPEN_CURRENT,
   SYMBOL_SWAP_MODE_REOPEN_BID
  };

MQL4でサポートされていない関数がコメントアウトされたことに注意してください。これまでに行われた変更は、MQL4コンパイラを使用してヘッダーファイルコンパイルを行うために必要な最小限の手順です。特定のメソッドや関数が両方バージョンでサポートされているかどうかがわからない場合、言語マニュアルを参照してください。

各バージョンは、CSymbolInfoの独自のコピーを持っているで、基本ヘッダファイルにクラス定義は含まれていません。それだけで使用されているコンパイラバージョンに基づいて、インクルードするヘッダファイルの場所を指します。

#ifdef __MQL5__
   #include <Trade\SymbolInfo.mqh>
#else
   #include "..\..\MQL4\Lib\SymbolInfo.mqh"
#endif

MQL5ヘッダファイルは、MQL5標準ライブラリ内のCSymbolInfoを指します。一方、MQL4ヘッダファイルは、Lib下にヘッダファイルでMQL5のシンボルが変更されたコピーであり、ヘッダファイルでCSymbolInfoを指すようになります。


CSymbolManager

複数通貨に対応するために、CSymbolInfoのインスタンスコレクションが必要になります。これは、CSymbolManagerの目的です。このクラスは、いくつか追加メソッドと共に、シンボル情報のオブジェクトのさまざまなインスタンスを格納できるようにするためにCArrayObjを拡張します。この事例ではCSymbolInfoは、次図に示します。

シンボルマネージャファイル構造

このクラスは、最高オブジェクトの特定タイプ(CSymbolInfo)を格納するために使用され、CArrayObjのように振る舞います。CSymbolInfo と CArrayObjに基づいており、CArrayObjはMQL4とMQL5両方で利用可能なので、2つバージョンに空クラスファイルを参照することできます。最後に、前述したCSymbolInfoクラスファイルと同じファイル構造を持っています。

シンボルマネージャファイル構造


シンボルを追加

CSymbolnfoインスタンスはCArrayObjAddメソッドに追加されます。しかし、CArrayObjとは異なり、追加されるインスタンスは一意である必要あります。つまり、同じシンボル名を共有しない二つの要素があってはならないです。

bool CSymbolManagerBase::Add(CSymbolInfo *node)
  {
   if(Search(node.Name())==-1)
      return CArrayObj::Add(node);       
   return false;
  }

派生クラスは、カスタム検索方式を使用します。実際に CObjectメソッド(CSymbolInfoは明示的な比較でない)のCSymbolInfo比較メソッドを利用することになるで、CArrayObj検索メソッドを使用することはありません。Compareメソッドを使用すると、すでに独立したコピーを持っているため、より複雑でもよいCSymbolInfoを拡張するために必要となるでしょう。新しい検索メソッドは、シンボル名を持つオブジェクトを比較します。

int CSymbolManagerBase::Search(string symbol=NULL)
  {
   if(symbol==NULL)
      symbol= Symbol();
   for(int i=0;i<Total();i++)
     {
      CSymbolInfo *item=At(i);
      if(StringCompare(item.Name(),symbol)==0)
         return i;
     }
   return -1;
  }
多通貨EAについては、主要なシンボルが存在するかもしれません。現在のシンボルである可能性も、別である可能性もあります。これは、頻繁にアクセスされるシンボルです。このクラスでは、初期化中の一次符号を設定できます。何も選択されていない場合、最初CSymbolInfoのインスタンスは、プライマリシンボルとして扱われます。
void CSymbolManagerBase::SetPrimary(string symbol=NULL)
  {
   if(symbol==NULL)
      symbol= Symbol();
   m_symbol_primary=Get(symbol);
  }

CSymbolInfo *CSymbolManagerBase::GetPrimary(void)
  {
   if (!CheckPointer(m_symbol_primary) && Total()>0)
      SetPrimary(0);
   return m_symbol_primary;
  }

これに可能なアプローチです。上記コードは、最も簡単です。

シンボルのリフレッシュ

シンボルマネージャですべてのシンボルをリフレッシュするには、格納されているすべてオブジェクトに反復処理し、RefreshRatesメソッドを1つずつ呼び出します。シンボルが膨大なため、呼び出しに最も実用的なメソッドではないかもしれないことに注意してください。むしろ、この場合、CSymbolInfoインスタンスでは、RefreshRates関数を呼び出す方が良いかもしれません。次コードは、RefreshRatesメソッドを示しています。

bool CSymbolManagerBase::RefreshRates(void)
  {
   for(int i=0;i<Total();i++)
     {
      CSymbolInfo *symbol=At(i);
      if(!CheckPointer(symbol))
         continue;
      if(!symbol.RefreshRates())
         return false;
     }
   return true;
  }

なお、CSymbolInfoにおけるRefresh RefreshRates メソッドは異なっています。後者は最後に処理されたティックにシンボル情報を更新され、初期化時に使用されます。

以下は、CSymbolManagerクラスの基本コードです:

(SymbolManagerBase.mqh)

#include <Arrays\ArrayObj.mqh>
#include "..\Lib\SymbolInfo.mqh"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CSymbolManagerBase : public CArrayObj
  {
protected:
   CSymbolInfo      *m_symbol_primary;
   CObject          *m_container;
public:
                     CSymbolManagerBase(void);
                    ~CSymbolManagerBase(void);
   virtual bool      Add(CSymbolInfo*);
   virtual void      Deinit(void);
   CSymbolInfo      *Get(string);
   virtual bool      RefreshRates(void);
   virtual int       Search(string);
   virtual CObject *GetContainer(void);
   virtual void      SetContainer(CObject*);
   virtual void      SetPrimary(string);
   virtual void      SetPrimary(const int);
   virtual CSymbolInfo *GetPrimary(void);
   virtual string    GetPrimaryName(void);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CSymbolManagerBase::CSymbolManagerBase(void)
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CSymbolManagerBase::~CSymbolManagerBase(void)
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CObject *CSymbolManagerBase::GetContainer(void)
  {
   return m_container;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CSymbolManagerBase::SetContainer(CObject *container)
  {
   m_container=container;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CSymbolManagerBase::Deinit(void)
  {
   Shutdown();
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CSymbolManagerBase::Add(CSymbolInfo *node)
  {
   if(Search(node.Name())==-1)
      return CArrayObj::Add(node);       
   return false;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CSymbolInfo *CSymbolManagerBase::Get(string symbol=NULL)
  {
   if(symbol==NULL)
      symbol= Symbol();
   for(int i=0;i<Total();i++)
     {
      CSymbolInfo *item=At(i);
      if(!CheckPointer(item))
         continue;
      if(StringCompare(item.Name(),symbol)==0)
         return item;
     }
   return NULL;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CSymbolManagerBase::RefreshRates(void)
  {
   for(int i=0;i<Total();i++)
     {
      CSymbolInfo *symbol=At(i);
      if(!CheckPointer(symbol))
         continue;
      if(!symbol.RefreshRates())
         return false;
     }
   return true;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int CSymbolManagerBase::Search(string symbol=NULL)
  {
   if(symbol==NULL)
      symbol= Symbol();
   for(int i=0;i<Total();i++)
     {
      CSymbolInfo *item=At(i);
      if(StringCompare(item.Name(),symbol)==0)
         return i;
     }
   return -1;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CSymbolManagerBase::SetPrimary(string symbol=NULL)
  {
   if(symbol==NULL)
      symbol= Symbol();
   m_symbol_primary=Get(symbol);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CSymbolManagerBase::SetPrimary(const int idx)
  {
   m_symbol_primary=At(idx);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CSymbolInfo *CSymbolManagerBase::GetPrimary(void)
  {
   if (!CheckPointer(m_symbol_primary) && Total()>0)
      SetPrimary(0);
   return m_symbol_primary;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string CSymbolManagerBase::GetPrimaryName(void)
  {
   if(CheckPointer(m_symbol_primary))
      return m_symbol_primary.Name();
   return NULL;
  }
//+------------------------------------------------------------------+
#ifdef __MQL5__
#include "..\..\MQL5\Symbol\SymbolManager.mqh"
#else
#include "..\..\MQL4\Symbol\SymbolManager.mqh"
#endif
//+------------------------------------------------------------------+

メソッドのすべては、クロスプラットフォーム互換性があります。このように、プラットフォームの固有クラスと同じになると、追加メソッドが含まれていないでしょう。

(SymbolManager.mqh, MQL4 and MQL5)

class CSymbolManager : public CSymbolManagerBase
  {
public:
                     CSymbolManager(void);
                    ~CSymbolManager(void);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CSymbolManager::CSymbolManager(void)
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CSymbolManager::~CSymbolManager(void)
  {
  }
//+------------------------------------------------------------------+


CAccountInfo

CSymbolInfo内で行われたものと同様に、サポートされていない関数のほとんどはコメントにする必要あります。サポートされていない関数は、 OrderCalcMargin OrderCalcProfitで、MQL4には直接対応がありません。したがって、CSymbolInfoクラスでしたように、2つのプラットフォームにクラスを別々にコピーし、MQL4コンパイラを使用してコンパイルします。ファイル構造は、これまで説明してきた他のクラスようになります。

CAccountInfoファイル構造

修正されたクラスは以下通りです。

//+------------------------------------------------------------------+
//|                                                  AccountInfo.mqh |
//|                   Copyright 2009-2016, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include <Object.mqh>
//+------------------------------------------------------------------+
//| Class CAccountInfo.                                              |
//| Appointment: Class for access to account info.                   |
//|              Derives from class CObject.                         |
//+------------------------------------------------------------------+
class CAccountInfo : public CObject
  {
public:
                     CAccountInfo(void);
                    ~CAccountInfo(void);
   //---整数アカウントプロパティに高速アクセス
   long              Login(void) const;
   ENUM_ACCOUNT_TRADE_MODE TradeMode(void) const;
   string            TradeModeDescription(void) const;
   long              Leverage(void) const;
   ENUM_ACCOUNT_STOPOUT_MODE StopoutMode(void) const;
   string            StopoutModeDescription(void) const;
   //ENUM_ACCOUNT_MARGIN_MODE MarginMode(void) const;
   //string            MarginModeDescription(void) const;
   bool              TradeAllowed(void) const;
   bool              TradeExpert(void) const;
   int               LimitOrders(void) const;
   //---doubleアカウントプロパティに高速アクセス
   double            Balance(void) const;
   double            Credit(void) const;
   double            Profit(void) const;
   double            Equity(void) const;
   double            Margin(void) const;
   double            FreeMargin(void) const;
   double            MarginLevel(void) const;
   double            MarginCall(void) const;
   double            MarginStopOut(void) const;
   //---文字列アカウントプロパティに高速アクセス
   string            Name(void) const;
   string            Server(void) const;
   string            Currency(void) const;
   string            Company(void) const;
   //---APIMQL5にアクセス
   long              InfoInteger(const ENUM_ACCOUNT_INFO_INTEGER prop_id) const;
   double            InfoDouble(const ENUM_ACCOUNT_INFO_DOUBLE prop_id) const;
   string            InfoString(const ENUM_ACCOUNT_INFO_STRING prop_id) const;
   //--- checks
   //double            OrderProfitCheck(const string symbol,const ENUM_ORDER_TYPE trade_operation,
                                      //const double volume,const double price_open,const double price_close) const;
   //double            MarginCheck(const string symbol,const ENUM_ORDER_TYPE trade_operation,
                                 //const double volume,const double price) const;
   //double            FreeMarginCheck(const string symbol,const ENUM_ORDER_TYPE trade_operation,
                                     //const double volume,const double price) const;
   //double            MaxLotCheck(const string symbol,const ENUM_ORDER_TYPE trade_operation,
                                 //const double price,const double percent=100) const;
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CAccountInfo::CAccountInfo(void)
  {
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CAccountInfo::~CAccountInfo(void)
  {
  }
//+------------------------------------------------------------------+
//| Get the property value "ACCOUNT_LOGIN"                           |
//+------------------------------------------------------------------+
long CAccountInfo::Login(void) const
  {
   return(AccountInfoInteger(ACCOUNT_LOGIN));
  }
//+------------------------------------------------------------------+
//| Get the property value "ACCOUNT_TRADE_MODE"                      |
//+------------------------------------------------------------------+
ENUM_ACCOUNT_TRADE_MODE CAccountInfo::TradeMode(void) const
  {
   return((ENUM_ACCOUNT_TRADE_MODE)AccountInfoInteger(ACCOUNT_TRADE_MODE));
  }
//+------------------------------------------------------------------+
//| Get the property value "ACCOUNT_TRADE_MODE" as string            |
//+------------------------------------------------------------------+
string CAccountInfo::TradeModeDescription(void) const
  {
   string str;
//---
   switch(TradeMode())
     {
      case ACCOUNT_TRADE_MODE_DEMO   : str="Demo trading account";    break;
      case ACCOUNT_TRADE_MODE_CONTEST: str="Contest trading account"; break;
      case ACCOUNT_TRADE_MODE_REAL   : str="Real trading account";    break;
      default                        : str="Unknown trade account";
     }
//---
   return(str);
  }
//+------------------------------------------------------------------+
//| Get the property value "ACCOUNT_LEVERAGE"                        |
//+------------------------------------------------------------------+
long CAccountInfo::Leverage(void) const
  {
   return(AccountInfoInteger(ACCOUNT_LEVERAGE));
  }
//+------------------------------------------------------------------+
//| Get the property value "ACCOUNT_MARGIN_SO_MODE"                  |
//+------------------------------------------------------------------+
ENUM_ACCOUNT_STOPOUT_MODE CAccountInfo::StopoutMode(void) const
  {
   return((ENUM_ACCOUNT_STOPOUT_MODE)AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE));
  }
//+------------------------------------------------------------------+
//| Get the property value "ACCOUNT_MARGIN_SO_MODE" as string        |
//+------------------------------------------------------------------+
string CAccountInfo::StopoutModeDescription(void) const
  {
   string str;
//---
   switch(StopoutMode())
     {
      case ACCOUNT_STOPOUT_MODE_PERCENT: str="Level is specified in percentage"; break;
      case ACCOUNT_STOPOUT_MODE_MONEY  : str="Level is specified in money";      break;
      default                          : str="Unknown stopout mode";
     }
//---
   return(str);
  }
/*
//+------------------------------------------------------------------+
//| Get the property value "ACCOUNT_MARGIN_MODE"                     |
//+------------------------------------------------------------------+
ENUM_ACCOUNT_MARGIN_MODE CAccountInfo::MarginMode(void) const
  {
   return((ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE));
  }
*/
/*
//+------------------------------------------------------------------+
//| Get the property value "ACCOUNT_MARGIN_MODE" as string           |
//+------------------------------------------------------------------+
string CAccountInfo::MarginModeDescription(void) const
  {
   string str;
//---
   switch(MarginMode())
     {
      case ACCOUNT_MARGIN_MODE_RETAIL_NETTING: str="Netting";  break;
      case ACCOUNT_MARGIN_MODE_EXCHANGE      : str="Exchange"; break;
      case ACCOUNT_MARGIN_MODE_RETAIL_HEDGING: str="Hedging";  break;
      default                                : str="Unknown margin mode";
     }
//---
   return(str);
  }
*/
//+------------------------------------------------------------------+
//| Get the property value "ACCOUNT_TRADE_ALLOWED"                   |
//+------------------------------------------------------------------+
bool CAccountInfo::TradeAllowed(void) const
  {
   return((bool)AccountInfoInteger(ACCOUNT_TRADE_ALLOWED));
  }
//+------------------------------------------------------------------+
//| Get the property value "ACCOUNT_TRADE_EXPERT"                    |
//+------------------------------------------------------------------+
bool CAccountInfo::TradeExpert(void) const
  {
   return((bool)AccountInfoInteger(ACCOUNT_TRADE_EXPERT));
  }
//+------------------------------------------------------------------+
//| Get the property value "ACCOUNT_LIMIT_ORDERS"                    |
//+------------------------------------------------------------------+
int CAccountInfo::LimitOrders(void) const
  {
   return((int)AccountInfoInteger(ACCOUNT_LIMIT_ORDERS));
  }
//+------------------------------------------------------------------+
//| Get the property value "ACCOUNT_BALANCE"                         |
//+------------------------------------------------------------------+
double CAccountInfo::Balance(void) const
  {
   return(AccountInfoDouble(ACCOUNT_BALANCE));
  }
//+------------------------------------------------------------------+
//| Get the property value "ACCOUNT_CREDIT"                          |
//+------------------------------------------------------------------+
double CAccountInfo::Credit(void) const
  {
   return(AccountInfoDouble(ACCOUNT_CREDIT));
  }
//+------------------------------------------------------------------+
//| Get the property value "ACCOUNT_PROFIT"                          |
//+------------------------------------------------------------------+
double CAccountInfo::Profit(void) const
  {
   return(AccountInfoDouble(ACCOUNT_PROFIT));
  }
//+------------------------------------------------------------------+
//| Get the property value "ACCOUNT_EQUITY"                          |
//+------------------------------------------------------------------+
double CAccountInfo::Equity(void) const
  {
   return(AccountInfoDouble(ACCOUNT_EQUITY));
  }
//+------------------------------------------------------------------+
//| Get the property value "ACCOUNT_MARGIN"                          |
//+------------------------------------------------------------------+
double CAccountInfo::Margin(void) const
  {
   return(AccountInfoDouble(ACCOUNT_MARGIN));
  }
//+------------------------------------------------------------------+
//| Get the property value "ACCOUNT_FREEMARGIN"                      |
//+------------------------------------------------------------------+
double CAccountInfo::FreeMargin(void) const
  {
   return(AccountInfoDouble(ACCOUNT_FREEMARGIN));
  }
//+------------------------------------------------------------------+
//| Get the property value "ACCOUNT_MARGIN_LEVEL"                    |
//+------------------------------------------------------------------+
double CAccountInfo::MarginLevel(void) const
  {
   return(AccountInfoDouble(ACCOUNT_MARGIN_LEVEL));
  }
//+------------------------------------------------------------------+
//| Get the property value "ACCOUNT_MARGIN_SO_CALL"                  |
//+------------------------------------------------------------------+
double CAccountInfo::MarginCall(void) const
  {
   return(AccountInfoDouble(ACCOUNT_MARGIN_SO_CALL));
  }
//+------------------------------------------------------------------+
//| Get the property value "ACCOUNT_MARGIN_SO_SO"                    |
//+------------------------------------------------------------------+
double CAccountInfo::MarginStopOut(void) const
  {
   return(AccountInfoDouble(ACCOUNT_MARGIN_SO_SO));
  }
//+------------------------------------------------------------------+
//| Get the property value "ACCOUNT_NAME"                            |
//+------------------------------------------------------------------+
string CAccountInfo::Name(void) const
  {
   return(AccountInfoString(ACCOUNT_NAME));
  }
//+------------------------------------------------------------------+
//| Get the property value "ACCOUNT_SERVER"                          |
//+------------------------------------------------------------------+
string CAccountInfo::Server(void) const
  {
   return(AccountInfoString(ACCOUNT_SERVER));
  }
//+------------------------------------------------------------------+
//| Get the property value "ACCOUNT_CURRENCY"                        |
//+------------------------------------------------------------------+
string CAccountInfo::Currency(void) const
  {
   return(AccountInfoString(ACCOUNT_CURRENCY));
  }
//+------------------------------------------------------------------+
//| Get the property value "ACCOUNT_COMPANY"                         |
//+------------------------------------------------------------------+
string CAccountInfo::Company(void) const
  {
   return(AccountInfoString(ACCOUNT_COMPANY));
  }
//+------------------------------------------------------------------+
//| Access functions AccountInfoInteger(...)                         |
//+------------------------------------------------------------------+
long CAccountInfo::InfoInteger(const ENUM_ACCOUNT_INFO_INTEGER prop_id) const
  {
   return(AccountInfoInteger(prop_id));
  }
//+------------------------------------------------------------------+
//| Access functions AccountInfoDouble(...)                          |
//+------------------------------------------------------------------+
double CAccountInfo::InfoDouble(const ENUM_ACCOUNT_INFO_DOUBLE prop_id) const
  {
   return(AccountInfoDouble(prop_id));
  }
//+------------------------------------------------------------------+
//| Access functions AccountInfoString(...)                          |
//+------------------------------------------------------------------+
string CAccountInfo::InfoString(const ENUM_ACCOUNT_INFO_STRING prop_id) const
  {
   return(AccountInfoString(prop_id));
  }
/*
//+------------------------------------------------------------------+
//| Access functions OrderCalcProfit(...).                            |
//| INPUT:  name            - symbol name,                           |
//|         trade_operation - trade operation,                       |
//|         volume          - volume of the opening position,        |
//|         price_open      - price of the opening position,         |
//|         price_close     - price of the closing position.         |
//+------------------------------------------------------------------+
double CAccountInfo::OrderProfitCheck(const string symbol,const ENUM_ORDER_TYPE trade_operation,
                                      const double volume,const double price_open,const double price_close) const
  {
   double profit=EMPTY_VALUE;
//---
   if(!OrderCalcProfit(trade_operation,symbol,volume,price_open,price_close,profit))
      return(EMPTY_VALUE);
//---
   return(profit);
  }
*/
/*
//+------------------------------------------------------------------+
//| Access functions OrderCalcMargin(...).                           |
//| INPUT:  name            - symbol name,                           |
//|         trade_operation - trade operation,                       |
//|         volume          - volume of the opening position,        |
//|         price           - price of the opening position.         |
//+------------------------------------------------------------------+
double CAccountInfo::MarginCheck(const string symbol,const ENUM_ORDER_TYPE trade_operation,
                                 const double volume,const double price) const
  {
   double margin=EMPTY_VALUE;
//---
   if(!OrderCalcMargin(trade_operation,symbol,volume,price,margin))
      return(EMPTY_VALUE);
//---
   return(margin);
  }
*/
/*
//+------------------------------------------------------------------+
//| Access functions OrderCalcMargin(...).                           |
//| INPUT:  name            - symbol name,                           |
//|         trade_operation - trade operation,                       |
//|         volume          - volume of the opening position,        |
//|         price           - price of the opening position.         |
//+------------------------------------------------------------------+
double CAccountInfo::FreeMarginCheck(const string symbol,const ENUM_ORDER_TYPE trade_operation,
                                     const double volume,const double price) const
  {
   return(FreeMargin()-MarginCheck(symbol,trade_operation,volume,price));
  }
*/
/*
//+------------------------------------------------------------------+
//| Access functions OrderCalcMargin(...).                           |
//| INPUT:  name            - symbol name,                           |
//|         trade_operation - trade operation,                       |
//|         price           - price of the opening position,         |
//|         percent         - percent of available margin [1-100%].  |
//+------------------------------------------------------------------+
double CAccountInfo::MaxLotCheck(const string symbol,const ENUM_ORDER_TYPE trade_operation,
                                 const double price,const double percent) const
  {
   double margin=0.0;
//--- checks
   if(symbol=="" || price<=0.0 || percent<1 || percent>100)
     {
      Print("CAccountInfo::MaxLotCheck invalid parameters");
      return(0.0);
     }
//---1ロット計算マージン要件
   if(!OrderCalcMargin(trade_operation,symbol,1.0,price,margin) || margin<0.0)
     {
      Print("CAccountInfo::MaxLotCheck margin calculation failed");
      return(0.0);
     }
//---
   if(margin==0.0) //ペンディングオーダー
      return(SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX));
//---計算最大ボリューム
   double volume=NormalizeDouble(FreeMargin()*percent/100.0/margin,2);
//---正規化とチェック制限
   double stepvol=SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP);
   if(stepvol>0.0)
      volume=stepvol*MathFloor(volume/stepvol);
//---
   double minvol=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN);
   if(volume<minvol)
      volume=0.0;
//---
   double maxvol=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX);
   if(volume>maxvol)
      volume=maxvol;
//--- return volume
   return(volume);
  }
*/
//+------------------------------------------------------------------+

プラットフォームは、一度に1つアカウントにアクセスすることできます。よって、CAccountInfoインスタンスを作成することは必要ないかもしれません。


CExpertTrade

同じ最終目標を持つにもかかわらず、MQL4とMQL5は、トレードで実行されるメソッドが異なります。MQL4に、クロスプラットフォームEAのMQL5バージョンに関するトレードクラスを使用することできます。この場合、MQL4バージョンに、同じ名前のクラスを含む新しいヘッダーファイルを作成します。使用しているコンパイラの種類に応じて、適切なヘッダファイルを使用するように、基本ヘッダクラスファイルを保持します。

CExpertTradeファイル構造

次ようなコードを実行するとき、MQL5 CexpertTradeで見つかったメンバーとメソッドをエミュレートすることになります。

CExpertTradeトレード;
trade.Buy(/*params*/);

両方のバージョンは、ロングポジションを理解することができるでしょう。

この最小要件は、プラットフォーム上でポジションを入力するために使用されるメソッドをエミュレートすることです。つまり、CExpertTradeの売買メソッドです。ネイティブのPositionCloseメソッド(ヘッジ)を使用しながら、MQL4バージョンのOrderCloseをMQL5バージョンに実装します。次コードは、CExpertTradeのMQL4バージョンを示しています。コードは、主に1人のプログラマから変えることができるようになります。

#include <Arrays\ArrayInt.mqh>
enum ENUM_ORDER_TYPE_TIME
  {
   ORDER_TIME_GTC,
   ORDER_TIME_DAY,
   ORDER_TIME_SPECIFIED,
   ORDER_TIME_SPECIFIED_DAY
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CExpertTrade : public CObject
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
  {
protected:
   int               m_magic;
   ulong             m_deviation;
   ENUM_ORDER_TYPE_TIME m_order_type_time;
   datetime          m_order_expiration;
   bool              m_async_mode;
   uint              m_retry;
   int               m_sleep;
   color             m_color_long;
   color             m_color_short;
   color             m_color_buystop;
   color             m_color_buylimit;
   color             m_color_sellstop;
   color             m_color_selllimit;
   color             m_color_modify;
   color             m_color_exit;
   CSymbolInfo      *m_symbol;
public:
                     CExpertTrade(void);
                    ~CExpertTrade(void);
   //--- setters and getters
   color             ArrowColor(const ENUM_ORDER_TYPE type);
   uint              Retry() {return m_retry;}
   void              Retry(uint retry){m_retry=retry;}
   int               Sleep() {return m_sleep;}
   void              Sleep(int sleep){m_sleep=sleep;}
   void              SetAsyncMode(const bool mode) {m_async_mode=mode;}
   void              SetExpertMagicNumber(const int magic) {m_magic=magic;}
   void              SetDeviationInPoints(const ulong deviation) {m_deviation=deviation;}
   void              SetOrderExpiration(const datetime expire) {m_order_expiration=expire;}
   bool              SetSymbol(CSymbolInfo *);
   //-- trade methods   
   virtual ulong     Buy(const double,const double,const double,const double,const string);
   virtual ulong     Sell(const double,const double,const double,const double,const string);
   virtual bool      OrderDelete(const ulong);
   virtual bool      OrderClose(const ulong,const double,const double);
   virtual bool      OrderCloseAll(CArrayInt *,const bool);
   virtual bool      OrderModify(const ulong,const double,const double,const double,const ENUM_ORDER_TYPE_TIME,const datetime,const double);
   virtual ulong     OrderOpen(const string,const ENUM_ORDER_TYPE,const double,const double,const double,const double,const double,const ENUM_ORDER_TYPE_TIME,const datetime,const string);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CExpertTrade::CExpertTrade(void) : m_magic(0),
                                   m_deviation(10),
                                   m_order_type_time(0),
                                   m_symbol(NULL),
                                   m_async_mode(0),
                                   m_retry(3),
                                   m_sleep(100),
                                   m_color_long(clrGreen),
                                   m_color_buystop(clrGreen),
                                   m_color_buylimit(clrGreen),
                                   m_color_sellstop(clrRed),
                                   m_color_selllimit(clrRed),
                                   m_color_short(clrRed),
                                   m_color_modify(clrNONE),
                                   m_color_exit(clrNONE)
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CExpertTrade::~CExpertTrade(void)
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CExpertTrade::SetSymbol(CSymbolInfo *symbol)
  {
   if(symbol!=NULL)
     {
      m_symbol=symbol;
      return true;
     }
   return false;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CExpertTrade::OrderModify(const ulong ticket,const double price,const double sl,const double tp,
                               const ENUM_ORDER_TYPE_TIME type_time,const datetime expiration,const double stoplimit=0.0)
  {
   return ::OrderModify((int)ticket,price,sl,tp,expiration,m_color_modify);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CExpertTrade::OrderDelete(const ulong ticket)
  {
   return ::OrderDelete((int)ticket);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
ulong CExpertTrade::Buy(const double volume,const double price,const double sl,const double tp,const string comment="")
  {
   if(m_symbol==NULL)
      return false;
   m_symbol.RefreshRates();
   string symbol=m_symbol.Name();
   double stops_level=m_symbol.StopsLevel()*m_symbol.Point();
   double ask=m_symbol.Ask();
   if(symbol=="")
      return 0;
   if(price!=0)
     {
      if(price>ask+stops_level)
         return OrderOpen(symbol,ORDER_TYPE_BUY_STOP,volume,0.0,price,sl,tp,m_order_type_time,m_order_expiration,comment);
      if(price<ask-stops_level)
         return OrderOpen(symbol,ORDER_TYPE_BUY_LIMIT,volume,0.0,price,sl,tp,m_order_type_time,m_order_expiration,comment);
     }
   return OrderOpen(symbol,ORDER_TYPE_BUY,volume,0.0,ask,sl,tp,m_order_type_time,m_order_expiration,comment);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
ulong CExpertTrade::Sell(const double volume,const double price,const double sl,const double tp,const string comment="")
  {
   if(m_symbol==NULL)
      return false;
   m_symbol.RefreshRates();
   string symbol=m_symbol.Name();
   double stops_level=m_symbol.StopsLevel()*m_symbol.Point();
   double bid=m_symbol.Bid();
   if(symbol=="")
      return 0;
   if(price!=0)
     {
      if(price>bid+stops_level)
         return OrderOpen(symbol,ORDER_TYPE_SELL_LIMIT,volume,0.0,price,sl,tp,m_order_type_time,m_order_expiration,comment);
      if(price<bid-stops_level)
         return OrderOpen(symbol,ORDER_TYPE_SELL_STOP,volume,0.0,price,sl,tp,m_order_type_time,m_order_expiration,comment);
     }
   return OrderOpen(symbol,ORDER_TYPE_SELL,volume,0.0,bid,sl,tp,m_order_type_time,m_order_expiration,comment);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
ulong CExpertTrade::OrderOpen(const string symbol,const ENUM_ORDER_TYPE order_type,const double volume,
                              const double limit_price,const double price,const double sl,const double tp,
                              const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC,const datetime expiration=0,
                              const string comment="")
  {
   bool res;
   ulong ticket=0;
   color arrowcolor=ArrowColor(order_type);
   datetime expire=0;
   if(order_type>1 && expiration>0) expire=expiration*1000+TimeCurrent();
   double stops_level=m_symbol.StopsLevel();
   for(uint i=0;i<m_retry;i++)
     {
      if(ticket>0)
         break;
      if(IsStopped())
         return 0;
      if(IsTradeContextBusy() || !IsConnected())
        {
         ::Sleep(m_sleep);
         continue;
        }
      if(stops_level==0 && order_type<=1)
        {
         ticket=::OrderSend(symbol,order_type,volume,price,(int)(m_deviation*m_symbol.Point()),0,0,comment,m_magic,expire,arrowcolor);
         ::Sleep(m_sleep);
         for(uint j=0;j<m_retry;j++)
           {
            if(res) break;
            if(ticket>0 && (sl>0 || tp>0))
              {
               if(OrderSelect((int)ticket,SELECT_BY_TICKET))
                 {
                  res=OrderModify((int)ticket,OrderOpenPrice(),sl,tp,OrderExpiration());
                  ::Sleep(m_sleep);
                 }
              }
           }
        }
      else
        {
         ticket=::OrderSend(symbol,order_type,volume,price,(int)m_deviation,sl,tp,comment,m_magic,expire,arrowcolor);
         ::Sleep(m_sleep);
        }
     }
   return ticket>0?ticket:0;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CExpertTrade::OrderClose(const ulong ticket,const double lotsize=0.0,const double price=0.0)
  {
   if(!OrderSelect((int)ticket,SELECT_BY_TICKET))
      return false;
   if(OrderCloseTime()>0)
      return true;
   double close_price=0.0;
   int deviation=0;
   if(OrderSymbol()==m_symbol.Name() && price>0.0)
     {
      close_price=NormalizeDouble(price,m_symbol.Digits());
      deviation=(int)(m_deviation*m_symbol.Point());
     }
   else
     {
      close_price=NormalizeDouble(OrderClosePrice(),(int)MarketInfo(OrderSymbol(),MODE_DIGITS));
      deviation=(int)(m_deviation*MarketInfo(OrderSymbol(),MODE_POINT));
     }
   double lots=(lotsize>0.0 || lotsize>OrderLots())?lotsize:OrderLots();
   return ::OrderClose((int)ticket,lots,close_price,deviation,m_color_exit);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CExpertTrade::OrderCloseAll(CArrayInt *other_magic,const bool restrict_symbol=true)
  {
   bool res=true;
   int total= OrdersTotal();
   for(int i=total-1;i>=0;i--)
     {
      double bid=0.0,ask=0.0;
      if(!OrderSelect(i,SELECT_BY_POS)) continue;
      if(OrderSymbol()!=m_symbol.Name() && restrict_symbol) continue;
      if(OrderMagicNumber()!=m_magic && other_magic.Search(OrderMagicNumber())<0) continue;
      m_symbol.RefreshRates();
      if(OrderSymbol()==m_symbol.Name())
        {
         bid = m_symbol.Bid();
         ask = m_symbol.Ask();
        }
      else
        {
         bid = MarketInfo(OrderSymbol(),MODE_BID);
         ask = MarketInfo(OrderSymbol(),MODE_ASK);
        }
      if(res) res=OrderClose(OrderTicket(),OrderLots(),OrderType()==ORDER_TYPE_BUY?bid:ask);
     }
   return res;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
color CExpertTrade::ArrowColor(const ENUM_ORDER_TYPE type)
  {
   switch(type)
     {
      case ORDER_TYPE_BUY:        return m_color_long;
      case ORDER_TYPE_SELL:       return m_color_short;
      case ORDER_TYPE_BUY_STOP:   return m_color_buystop;
      case ORDER_TYPE_BUY_LIMIT:  return m_color_buylimit;
      case ORDER_TYPE_SELL_STOP:  return m_color_sellstop;
      case ORDER_TYPE_SELL_LIMIT: return m_color_selllimit;
     }
   return clrNONE;
  }
//+------------------------------------------------------------------+

MQL5バージョンために、CExpertTradeクラスはCTradeクラスから継承することに注意してください。一方、MQL4バージョンため、CExpertTradeクラスに直接CObjectから継承します。これは、MQL4バージョンのCTradeとCExpertTradeは、単一オブジェクトに統合されていることを意味します。

このような ORDER_TYPE_TIMEなど一部の関数はMQL4には直接対応するもありません。しかし、トレードクラスを拡張し、MQL4でMQL5のエミュレートをする必要ある場合に有用であるかもしれません。


CTradeManager

ネイティブのMQL5クラスのCExpertTradeはSetSymbolというメソッドを持っています。このメソッドは、他のシンボル情報インスタンス(CSymbolInfo)を指すように、そのシンボル情報のポインタを切り替えることできます。この設定では、クラス内で見られるメソッドの多くは、もはや処理する名前を表す文字列のシンボルパラメータを持っている必要はないでしょう。

ほとんど場合、単にCExpertTradeを使用し、シンボルを切り替えることで十分です。このアプローチを使用する場合、いくつか考慮すべき事があります。シンボルポインタが変更されたときに、偏差または最大スリッページを更新する必要あります。EAが異なる数字を扱う場合は特にこれが重要です。もう一つの要因は、EAは、各シンボルに入力されたポジションに別のマジックナンバーを使用する場合、マジックナンバーを更新する必要があります。

この問題に対するアプローチは、トレードマネージャを使用することです。以前のCSymbolManagerと同様に、このオブジェクトは、CArrayObjを拡張し、仮想シンボルマネージャなどのメソッドと同じセットを持っているでしょう。コンピュータに応じてファイルをコンパイルするために参照するベースヘッダーファイルがあります。シンボルマネージャーのような、トレードマネージャはストレージおよびデータ検索を扱います。したがって、そのコードの大部分で、基本ヘッダファイルを見つけることできます。ファイル構造を次図に示します。

トレードマネージャーファイル構造


トレードマネージャーの基本クラスコードを以下に示します。

(TradeManagerBase.mqh)

#include <Arrays\ArrayObj.mqh>
#include "ExpertTradeXBase.mqh"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CTradeManagerBase : public CArrayObj
  {
public:
                     CTradeManagerBase(void);
                    ~CTradeManagerBase(void);
   virtual int       Search(string);
   virtual bool      Add(CExpertTradeX*);
   virtual void      Deinit(void);
   CExpertTrade     *Get(const string);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CTradeManagerBase::CTradeManagerBase(void)
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CTradeManagerBase::~CTradeManagerBase(void)
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CTradeManagerBase::Deinit(void)
  {
   Shutdown();
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CTradeManagerBase::Add(CExpertTradeX *node)
  {
   if(Search(node.Name())==-1)
      return CArrayObj::Add(node);
   return false;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int CTradeManagerBase::Search(string symbol=NULL)
  {
   if(symbol==NULL)
      symbol= Symbol();
   for(int i=0;i<Total();i++)
     {
      CExpertTradeX *item=At(i);
      if(StringCompare(item.Name(),symbol)==0)
         return i;
     }
   return -1;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CExpertTrade *CTradeManagerBase::Get(const string name=NULL)
  {
   if(name==NULL && Total()>0)
      return At(0);
   for(int i=0;i<Total();i++)
     {
      CExpertTradeX *item=At(i);
      if(StringCompare(item.Name(),name)==0)
         return item;
     }
   return NULL;
  }
//+------------------------------------------------------------------+
#ifdef __MQL5__
#include "..\..\MQL5\Trade\TradeManager.mqh"
#else
#include "..\..\MQL4\Trade\TradeManager.mqh"
#endif
//+------------------------------------------------------------------+

単にCExpertTradeの単一インスタンスを使用し、それをスイッチオンするシンボルの独自コレクションを持っているので、延長することができます。また、マジックナンバーと偏差を格納し、特定のシンボルにリンクする必要あるので、追加メモリを使用します。

シンボルマネージャと同様に、このクラスは、2つのトレードオブジェクトを(トレードオブジェクトは一意である必要あります)を比較するためカスタム検索方式を使用しています。この比較は、その後にリンクするCSymbolInfoインスタンスの名前に基づいて、取引オブジェクトの名前を使用して実行されます。しかし、MQL5バージョンのため、CExpertTradeオブジェクトは、シンボルポインタもシンボル名もいずれも返しません。このオブジェクトインスタンスは、シンボル名を返すことできるようにCExpertTradeを拡張する必要あります。オブジェクトにCExpertTradeXを与えるでしょう。他mpすべてクラスで定義されたように、コンパイラに依存し、ヘッダを決定する基本ヘッダファイルが必要です。:

CExpertTradeXファイル構造


以下はクラスの基本実装を示しています。

(CExpertTradeXBase.mqh)

#include "ExpertTradeBase.mqh"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CExpertTradeXBase : public CExpertTrade
  {
public:
                     CExpertTradeXBase(void);
                    ~CExpertTradeXBase(void);
   string            Name(void);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CExpertTradeXBase::CExpertTradeXBase(void)
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CExpertTradeXBase::~CExpertTradeXBase(void)
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string CExpertTradeXBase::Name(void)
  {
   if (CheckPointer(m_symbol))
      return m_symbol.Name();
   return NULL;
  }
//+------------------------------------------------------------------+
#ifdef __MQL5__
#include "..\..\MQL5\Trade\ExpertTradeX.mqh"
#else 
#include "..\..\MQL4\Trade\ExpertTradeX.mqh"
#endif
//+------------------------------------------------------------------+

このCExpertTradeXクラスは、CExpertTradeを拡張することに注意してください。このオブジェクトは単一オブジェクトから継承するように思われます。しかし、現実には、MQL4とMQL5はCExpertTradeの異なるバージョンを持っています。これはかなり単純なオブジェクトであり、プラットフォーム固有のクラスを宣言するように、クロスプラットフォーム互換性あります。

(CExpertTradeX.mqh, MQL4 and MQL5 version)

class CExpertTradeX : public CExpertTradeXBase
  {
public:
                     CExpertTradeX(void);
                    ~CExpertTradeX(void);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CExpertTradeX::CExpertTradeX(void)
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CExpertTradeX::~CExpertTradeX(void)
  {
  }
//+------------------------------------------------------------------+

結論

MQL5標準ライブラリのいくつかのネイティブコンポーネントは、MQL4からこれらのクラスをコーディングするよりも、再構築する方法を実証しました。CSymbolInfo、CAccount、およびCExpertTradeクラス、およびCSymbolManagerやCTradeManagerなどは、EAと言ったオブジェクト(CSymbolInfo、CAccount、およびCExpertTrade)に複数のインスタンスを処理できるようにするために開発されました。

MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/2574

添付されたファイル |
MQLx-Reuse.zip (92.47 KB)
MQL5クックブック - 移動チャンネルのシグナルトレーディング MQL5クックブック - 移動チャンネルのシグナルトレーディング
この記事では、移動チャネルに基づいたシグナルを送信するクラスを実装するプロセスについて説明します。各々は、テスト結果を取引戦略が引き続きます。標準ライブラリのクラスは派生クラスを作成するために使用します。
クロスプラットフォームEA:序章 クロスプラットフォームEA:序章
この記事では、クロスプラットフォームのEAを容易に開発できるメソッドを詳述します。提案メソッドは、両方のバージョンによって共有関数を統合し、互換性のない関数の派生クラスを分割します。
MT5で取引戦略を迅速に開発しデバッグする方法 MT5で取引戦略を迅速に開発しデバッグする方法
スキャルピング自動システムはアルゴリズム取引の頂点にみなされていますが、コードを書くのは最も困難です。この記事では、受信ティックの分析に基づいて、戦略を構築するメソッドを示し、ビルトインツールとビジュアルテストをデバッグします。エントリーと決済の開発は、多くの場合、裁量取引の経験を必要とします。しかし、MT5ではヒストリー上で戦略をテストすることができます。
裁量トレードに向けたファジーロジック 裁量トレードに向けたファジーロジック
この記事では、ファジィ集合論を適用することにより、裁量の取引戦略を改善する方法を提案します。例として、相場参入のために過度に形式的な基準をぼかすため、ファジーロジックアプリケーションや戦略の検索、パラメータの選択について、ひとつひとつ説明してきました。このように、戦略の変更後、相場の状況に反応してポジションを開く柔軟な条件を使用します。