
クロスプラットフォームEA:MQL5標準ライブラリからコンポーネントの再利用
目次
イントロダクション
クロスプラットフォームのEA開発に有用なMQL5標準ライブラリコンポーネントが存在します。しかし、MQL4コンパイラと互換性のないMQL4クロスプラットフォームでは使用できなくなります。この場合、少なくとも2つの選択肢があります。
- 両方のバージョンでサポートされるコンポーネントを保ち、スクラッチから書き直します。
- クラスをコピーし、ヘッダファイルをを変更します。
この記事では、2番目オプションを検討します。このメソッドを使用すると、MQL4側でかなり緩い実装になるでしょう。しかし、その主な欠点として、多くコードを書き直す必要ないことです。また、最初からすべてを書き換えるよりも、MQL5クラスの最新バージョンにアップデートするでしょう。
フォルダ構成
使用するほとんどクラスとは異なり、MQL5標準ライブラリから再利用するクラスオブジェクトは、MQL4データフォルダincludeフォルダ内のどこかにコピーする必要あります。そのため、バージョンに関係なく、使用することできるでしょう。メソッドは変更になる場合あります。しかし、最も簡単なメソッドは、特定ヘッダファイルをリンクし、ヘッダファイルを作ることです。これは通常、カスタムメイドのクラスオブジェクト上で行われます。
MQL5バージョンについて、メインヘッダファイルは、使用するヘッダファイルの元ファイルにリンクする必要あります。
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と互換性ない行をコメントにします。結果ファイル構造は、以下ようになります。
次のコードで、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コンパイラを使用してコンパイルします。ファイル構造は、これまで説明してきた他のクラスようになります。
修正されたクラスは以下通りです。
//+------------------------------------------------------------------+ //| 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バージョンに、同じ名前のクラスを含む新しいヘッダーファイルを作成します。使用しているコンパイラの種類に応じて、適切なヘッダファイルを使用するように、基本ヘッダクラスファイルを保持します。
次ようなコードを実行するとき、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すべてクラスで定義されたように、コンパイラに依存し、ヘッダを決定する基本ヘッダファイルが必要です。:
以下はクラスの基本実装を示しています。
(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





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