目次

, ,

MQL5 標準ライブラリのラッパークラスを作ろう (CSymbolInfo 編)

ラッパークラスを作る目的

MQL5 にはカスタムインジケーターや EA のコード記述を簡易化するための標準ライブラリが用意されている。
標準ライブラリは、<データフォルダ>\MQL5\Include フォルダー配下に .mqh ファイルで格納されている。

MQL4 にも同様に標準ライブラリは存在するが公式ドキュメントがなく、また MQL5 標準ライブラリに用意されているクラスが MQL4 標準ライブラリにないといったことがある。

MT5 がそれほど普及せず MT4 がいまだに使われ続けている現状では、MQL5 標準ライブラリを使って開発したものを MQL4 に移植したいことがあるかもしれない。
というより管理人は実際にこの状況に直面し、ラッパークラスを作ることで MQL5、MQL4 に両対応した。
他にも方法はあるかもしれないが、同じような境遇に直面している方の道しるべとなればよいと思い記事にする。

参考:MQL5 リファレンス 標準ライブラリ

MQL4 / MQL5 標準ライブラリの違い

実際に標準ライブラリのフォルダーやファイルを見比べてみると、MQL5 にあって MQL4 にないクラスがあることがよくわかる。

「<データフォルダ>\MQL4\Include」フォルダーの例

「<データフォルダ>\MQL5\Include」フォルダーの例

カスタムインジケーターや EA を実装する上で大きく影響があったのは、MQL4 標準ライブラリには取引操作に関する機能 (取引クラス Trade Classes) がないことだった。
自作のカスタムインジケーターや EA の MQL5 ソースは、取引クラスの機能を多く参照していたため、それらの機能を MQL4 側にも実装する必要があった。
目標は、MQL5 ソースで参照している取引クラスのメソッドをラップしてMQL5 / MQL4 両方で使えるようにすることになった。

どこから手を付ける?

なにごとも簡単そうなところから手をつけるのがいい。
この記事では比較的単純なCSymbolInfo のラッパークラスを紹介する。
管理人の事例では最終的に下記のクラスのラッパーが必要になった。

CSymbolInfo ラッパークラスの作成

ラップしたメソッド

CSymbolInfo のメソッド全部を使えるようにするのが理想だが、それでは手間がかかりすぎる。
MQL5 ソースで使っている必要最小限のメソッドだけラップすることにした。
ほかのメソッドが必要になった場合は後から足していけばよい。

MQL4 と MQL5 のコードの切り分け方法

プリプロセッサでコードを切り分ける。
MQL4 のソースをビルドするとき、ソースに #define _MQL4 を定義すれば MQL4 版のコードがビルドされる。
定義しなければ MQL5 版のコードがビルドされる。

#ifdef _MQL4
    // MQL4 版のコードをここに書く
#else  // _MQL4
    // MQL5 版のコードをここに書く
#endif // _MQL4

CSymbolInfo のソースを確認して MQL4 に移植していく

MQL5 版のラップメソッドのコードは CSymbolInfo の該当メソッドを呼ぶだけでよい。
MQL4 版のほうはわりと大変💦 だが、SymbolInfoDouble()SymbolInfoInteger() を使って対応する値がおおむね取得できる。
MQL5 標準ライブラリ CSymbolInfo のソース (<データフォルダ>\MQL5\Include\Trade\SymbolInfo.mqh) を確認しながら同等な処理を行うように移植していく。

ラッパークラス ClSymbolInfoHelper 完成!

3 分クッキング方式( ^ω^)・・・

コード

クリックするとコードが開きます

SymbolInfoHelper.mqh
//+------------------------------------------------------------------+
//|                                             SymbolInfoHelper.mqh |
//+------------------------------------------------------------------+
#ifndef _SYMBOLINFOHELPER_MQH_
#define _SYMBOLINFOHELPER_MQH_
 
//+------------------------------------------------------------------+
//| インクルード                                                     |
//+------------------------------------------------------------------+
#ifdef _MQL4
#include <Object.mqh>
 
#else  // _MQL4
#include <Trade\SymbolInfo.mqh>
 
#endif // _MQL4
 
//+------------------------------------------------------------------+
//| ClSymbolInfoHelperクラス                                         |
//+------------------------------------------------------------------+
class ClSymbolInfoHelper : public CObject
{
public:
                     ClSymbolInfoHelper(void);
    virtual         ~ClSymbolInfoHelper(void);
 
    bool                Refresh(void);
    bool                RefreshRates();
    bool                Name(const string name);                    // シンボル設定
    string              Name(void);
    int                 Spread(void) const;
    double              Bid(void);
    double              Ask(void);
    int                 Digits(void);
    double              Point(void);
    double              LotsMin(void) const;
    double              LotsMax(void) const;
    double              LotsStep(void) const;
    double              SwapLong(void) const;
    double              SwapShort(void) const;
 
protected:
#ifdef _MQL4
    string              l_name;                                     // シンボル
    MqlTick             l_tick;                                     // ティック
    double              l_point;                                    // ポイント
    double              l_lots_min;                                 // 最小ロット
    double              l_lots_max;                                 // 最大ロット
    double              l_lots_step;                                // ロットステップ
    double              l_swap_long;                                // スワップ(ロング)
    double              l_swap_short;                               // スワップ(ショート)
    int                 l_digits;                                   // 桁
 
#else  // _MQL4
    CSymbolInfo         l_SymbolInfo;                               // シンボル情報
 
#endif // _MQL4
};
//+------------------------------------------------------------------+
//| コンストラクター                                                 |
//+------------------------------------------------------------------+
ClSymbolInfoHelper::ClSymbolInfoHelper(void)
{
#ifdef _MQL4
    l_name = "";
    ZeroMemory(l_tick);
    l_point = 0.0;
    l_lots_min = 0.0;
    l_lots_max = 0.0;
    l_lots_step = 0.0;
    l_swap_long = 0.0;
    l_swap_short = 0.0;
    l_digits = 0;
#else
 
#endif
}
//+------------------------------------------------------------------+
//| デストラクター                                                   |
//+------------------------------------------------------------------+
ClSymbolInfoHelper::~ClSymbolInfoHelper(void)
{
}
//+------------------------------------------------------------------+
//| Refresh                                                          |
//+------------------------------------------------------------------+
bool ClSymbolInfoHelper::Refresh(void)
{
#ifdef _MQL4
// クラス変数の設定
    long tmp_long = 0;
    if(!SymbolInfoDouble(l_name, SYMBOL_POINT, l_point))
        return(false);
    if(!SymbolInfoDouble(l_name, SYMBOL_VOLUME_MIN, l_lots_min))
        return(false);
    if(!SymbolInfoDouble(l_name, SYMBOL_VOLUME_MAX, l_lots_max))
        return(false);
    if(!SymbolInfoDouble(l_name, SYMBOL_VOLUME_STEP, l_lots_step))
        return(false);
    if(!SymbolInfoDouble(l_name, SYMBOL_SWAP_LONG, l_swap_long))
        return(false);
    if(!SymbolInfoDouble(l_name, SYMBOL_SWAP_SHORT, l_swap_short))
        return(false);
    if(!SymbolInfoInteger(l_name, SYMBOL_DIGITS, tmp_long))
        return(false);
    l_digits = (int)tmp_long;
 
    return(true);
 
#else
    return(l_SymbolInfo.Refresh());
 
#endif
}
//+------------------------------------------------------------------+
//| レート更新                                                       |
//+------------------------------------------------------------------+
bool ClSymbolInfoHelper::RefreshRates(void)
{
#ifdef _MQL4
    return(SymbolInfoTick(l_name, l_tick));
 
#else
    return(l_SymbolInfo.RefreshRates());
 
#endif
}
//+------------------------------------------------------------------+
//| シンボル設定                                                     |
//+------------------------------------------------------------------+
bool ClSymbolInfoHelper::Name(const string name)
{
#ifdef _MQL4
    l_name = name;
    if(!Refresh())
    {
        return(false);
    }
    return(true);
 
#else
    return(l_SymbolInfo.Name(name));
 
#endif
}
//+------------------------------------------------------------------+
//| シンボル                                                         |
//+------------------------------------------------------------------+
string ClSymbolInfoHelper::Name(void)
{
#ifdef _MQL4
    return(l_name);
 
#else
    return(l_SymbolInfo.Name());
 
#endif
}
//+------------------------------------------------------------------+
//| スプレッド                                                       |
//+------------------------------------------------------------------+
int ClSymbolInfoHelper::Spread(void) const
{
#ifdef _MQL4
    return((int)SymbolInfoInteger(l_name, SYMBOL_SPREAD));
 
#else
    return(l_SymbolInfo.Spread());
 
#endif
}
//+------------------------------------------------------------------+
//| 売値                                                             |
//+------------------------------------------------------------------+
double ClSymbolInfoHelper::Bid(void)
{
#ifdef _MQL4
    return(l_tick.bid);
 
#else
    return(l_SymbolInfo.Bid());
 
#endif
}
//+------------------------------------------------------------------+
//| 買値                                                             |
//+------------------------------------------------------------------+
double ClSymbolInfoHelper::Ask(void)
{
#ifdef _MQL4
    return(l_tick.ask);
 
#else
    return(l_SymbolInfo.Ask());
 
#endif
}
//+------------------------------------------------------------------+
//| 通貨ペアの小数点以下桁数                                         |
//+------------------------------------------------------------------+
int ClSymbolInfoHelper::Digits(void)
{
#ifdef _MQL4
    return(l_digits);
 
#else
    return(l_SymbolInfo.Digits());
 
#endif
}
//+------------------------------------------------------------------+
//| 通貨ペアのポイント                                               |
//+------------------------------------------------------------------+
double ClSymbolInfoHelper::Point(void)
{
#ifdef _MQL4
    return(l_point);
 
#else
    return(l_SymbolInfo.Point());
 
#endif
}
//+------------------------------------------------------------------+
//| 最小ロット                                                       |
//+------------------------------------------------------------------+
double ClSymbolInfoHelper::LotsMin(void) const
{
#ifdef _MQL4
    return(l_lots_min);
 
#else
    return(l_SymbolInfo.LotsMin());
 
#endif
}
//+------------------------------------------------------------------+
//| 最大ロット                                                       |
//+------------------------------------------------------------------+
double ClSymbolInfoHelper::LotsMax(void) const
{
#ifdef _MQL4
    return(l_lots_max);
 
#else
    return(l_SymbolInfo.LotsMax());
 
#endif
}
//+------------------------------------------------------------------+
//| 最大ロット                                                       |
//+------------------------------------------------------------------+
double ClSymbolInfoHelper::LotsStep(void) const
{
#ifdef _MQL4
    return(l_lots_step);
 
#else
    return(l_SymbolInfo.LotsStep());
 
#endif
}
//+------------------------------------------------------------------+
//| スワップ(ロング)                                                 |
//+------------------------------------------------------------------+
double ClSymbolInfoHelper::SwapLong(void) const
{
#ifdef _MQL4
    return(l_swap_long);
 
#else
    return(l_SymbolInfo.SwapLong());
 
#endif
}
//+------------------------------------------------------------------+
//| スワップ(ショート)                                               |
//+------------------------------------------------------------------+
double ClSymbolInfoHelper::SwapShort(void) const
{
#ifdef _MQL4
    return(l_swap_short);
 
#else
    return(l_SymbolInfo.SwapShort());
 
#endif
}
#endif // _SYMBOLINFOHELPER_MQH_
//+------------------------------------------------------------------+

使用例

プリプロセッサでコードを切り分けたので、MQL4 のソースをビルドするときはソースに #define _MQL4 を定義することに留意する。

//+------------------------------------------------------------------+
//|                                                       Sample.mq4 |
//+------------------------------------------------------------------+
#property strict
#property copyright     ""
#property version       "1.0"
 
// MQL4用ソースを使用
#define _MQL4
 
// インクルード
#include "SymbolInfoHelper.mqh"
 
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
    ClSymbolInfoHelper symbolInfo;
    if(!symbolInfo.Name(Symbol()))
    {
        Print("Error initializing symbol.");
        return(INIT_FAILED);
    }
 
    if(!symbolInfo.RefreshRates())
    {
        Print("Error initializing symbol.");
        return(INIT_FAILED);
    }
 
    PrintFormat("シンボル = %s", symbolInfo.Name());
    PrintFormat("スプレッド = %d", symbolInfo.Spread());
    PrintFormat("Ask = %s", DoubleToString(symbolInfo.Ask(), symbolInfo.Digits()));
    PrintFormat("Bid = %s", DoubleToString(symbolInfo.Bid(), symbolInfo.Digits()));
 
    return(INIT_SUCCEEDED);
}
// (以下、略)