MT4・MT5の共通化

MT4・MT5の違い

 MT4とMT5は、MetaQuotes Softwareが開発した2つのトレーディングプラットフォームです。

MT4によるソースコード

 ほぼ書籍で紹介されていたサンプルソースになっています。

#property strict
sinput double Lots = 0.1;      //売買ロット数
input int FastMAPeriod = 20;   //短期移動平均の期間
input int SlowMAPeriod = 50;   //長期移動平均の期間
int Ticket = 0;                //チケット番号
//ティック時実行関数
void OnTick()
{
   //1本前の移動平均
   double FastMA1 = iMA(_Symbol, 0, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
   double SlowMA1 = iMA(_Symbol, 0, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
   //2本前の移動平均
   double FastMA2 = iMA(_Symbol, 0, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 2);
   double SlowMA2 = iMA(_Symbol, 0, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 2);
   int pos = 0; //ポジションの状態
   //未決済ポジションの有無
   if (OrderSelect(Ticket, SELECT_BY_TICKET) && OrderCloseTime() == 0) {
      if(OrderType() == OP_BUY) pos = 1;           //買いポジション
      if(OrderType() == OP_SELL) pos = -1;         //売りポジション
   }
   
   bool ret; //決済状況
   if (FastMA2 <= SlowMA2 && FastMA1 > SlowMA1) {   //買いシグナル
      //売りポジションがあれば決済注文
      if (pos < 0) {
         ret = OrderClose(Ticket, OrderLots(), OrderClosePrice(), 0);
         if (ret) pos = 0;                //決済成功すればポジションなしに
      }
      //ポジションがなければ買い注文
      if (pos == 0) Ticket = OrderSend(_Symbol, OP_BUY, Lots, Ask, 0, 0, 0); 
   }
   if (FastMA2 >= SlowMA2 && FastMA1 < SlowMA1) {   //売りシグナル
      //買いポジションがあれば決済注文
      if (pos > 0) {
         ret = OrderClose(Ticket, OrderLots(), OrderClosePrice(), 0);
         if (ret) pos = 0;                 //決済成功すればポジションなしに
      }
      //ポジションがなければ売り注文
      if (pos == 0) Ticket = OrderSend(_Symbol, OP_SELL, Lots, Bid, 0, 0, 0); 
   }
}

MT5によるソースコード

 ほぼ書籍で紹介されていたサンプルソースになっています。

sinput double Lots = 0.1;      //売買ロット数
input int FastMAPeriod = 20;   //短期移動平均の期間
input int SlowMAPeriod = 50;   //長期移動平均の期間
ulong Ticket = 0;              //チケット番号
double FastMA[];               //短期移動平均用配列
double SlowMA[];               //長期移動平均用配列
int FastMAHandle;              //短期移動平均用ハンドル
int SlowMAHandle;              //長期移動平均用ハンドル
//初期化関数
int OnInit()
{
   //テクニカル指標の初期化
   FastMAHandle = iMA(_Symbol, 0, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
   SlowMAHandle = iMA(_Symbol, 0, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
   ArraySetAsSeries(FastMA, true);
   ArraySetAsSeries(SlowMA, true);
   return 0;
}
//ティック時実行関数
void OnTick()
{
   //テクニカル指標の更新
   CopyBuffer(FastMAHandle, 0, 0, 3, FastMA);
   CopyBuffer(SlowMAHandle, 0, 0, 3, SlowMA);
   int pos = 0; //ポジションの状態
   //未決済ポジションの有無
   if (PositionSelectByTicket(Ticket)) {
      if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) pos = 1;    //買いポジション
      if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) pos = -1;  //売りポジション
   }
   if(FastMA[2] <= SlowMA[2] && FastMA[1] > SlowMA[1]) {   //買いシグナル   
      //売りポジションがあれば決済注文
      if (pos < 0) {
         MqlTradeRequest request = {};
         MqlTradeResult result = {}; 
         request.action = TRADE_ACTION_DEAL;
         request.symbol = _Symbol;
         request.volume = Lots;
         request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
         request.type = ORDER_TYPE_BUY;
         request.position = Ticket;
         bool b = OrderSend(request, result);
         if (result.retcode == TRADE_RETCODE_DONE) pos = 0;   //決済成功すればポジションなしに
      }
      //ポジションがなければ買い注文
      if (pos == 0) {
         MqlTradeRequest request = {};
         MqlTradeResult result = {}; 
         request.action = TRADE_ACTION_DEAL;
         request.symbol = _Symbol;
         request.volume = Lots;
         request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
         request.type = ORDER_TYPE_BUY;
         bool b = OrderSend(request, result);
         if (result.retcode == TRADE_RETCODE_DONE) Ticket = result.deal;
      }
   }
   if (FastMA[2] >= SlowMA[2] && FastMA[1] < SlowMA[1]) {   //売りシグナル
      //買いポジションがあれば決済注文
      if (pos > 0) {
         MqlTradeRequest request = {};
         MqlTradeResult result = {}; 
         request.action = TRADE_ACTION_DEAL;
         request.symbol = _Symbol;
         request.volume = Lots;
         request.price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
         request.type = ORDER_TYPE_SELL;
         request.position = Ticket;
         bool b = OrderSend(request, result);
         if(result.retcode == TRADE_RETCODE_DONE) pos = 0;   //決済成功すればポジションなしに
      }
      //ポジションがなければ売り注文
      if(pos == 0) {
         MqlTradeRequest request = {};
         MqlTradeResult result = {}; 
         request.action = TRADE_ACTION_DEAL;
         request.symbol = _Symbol;
         request.volume = Lots;
         request.price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
         request.type = ORDER_TYPE_SELL;
         bool b = OrderSend(request, result);
         if(result.retcode == TRADE_RETCODE_DONE) Ticket = result.deal;
      }
   }
}

 MT4は、長年にわたって多くのトレーダーに愛用されてきた古典的なプラットフォームであり、MT5は、より現代的なデザインと高度な機能を備えた新しいプラットフォームです。しかし、MT5がより高度な機能を持っているため、MT4からMT5に移行する際には、MT4のカスタムインジケーターやEAなどのソースコードをMT5に移植する必要があります。この場合、MT4とMT5のソースコードを共通化することが有効です。

共通化するには

 MT4はMQL4という独自のプログラミング言語を使用し、MT5はMQL5という独自のプログラミング言語を使用します。

 これらのプログラミング言語は似ている部分がありますが、構文や機能には違いがあります。しかし、MT4とMT5のソースコードを共通化するために、両方のプログラミング言語を統合する方法があります。具体的には、MQL5でMT4の機能を呼び出すことができます。これにより、MT4とMT5のソースコードを共通化することができます。

 このアプローチは、既存のMT4のカスタムインジケーターやEAのコードを再利用できるため、移行の効率を向上させることができます。

その方法は

 MT4とMT5のソースコードを共通化する方法については、開発者やコミュニティの助けを借りることが重要です。MT4とMT5の両方に精通した開発者やコミュニティに参加することで、移行の手順やベストプラクティスについてのアドバイスや支援を得ることができます。

 これにピッタリな書籍がありました。

 この書籍内のリンク先から共通ライブラリをダウンロードができます。共通ライブラリの入手ができるだけでも、価値のある一冊だと思っています。

共通ライブラリ

//共通ライブラリ
#include "LibEA/LibEA.mqh"

 この1行を記述するだけで、MT4・MT5共通プログラムを作ることができます。このライブラリファイルは、以下の6本のファイルから構成されており、Experts/LibEA に格納しています。なお、6本すべての記述は必要なくコンパイル時に必要なものは自動的に呼び出されるようになっています。
 これらは、本書内に記述されているリンク先から、ダウンロードが可能です。

  • LibEA.mqh:EAのプログラムから直接読み込まれるファイルで、MQL4、MQL5共通の関数をライブラリ化したものです。
  • LibEA4.mqh:2022年10月に追加されたものです。
  • LibOrder4.mqh:MQL4のトレード関数をライブラリ化したものです。
  • LibOrder5.mqh:MQL5のトレード関数をライブラリ化したものです。
  • LibMQL4.mqh:MQL5で対応していないMQL4の関数(時間関数、テクニカル指標関数)をMQL5で利用るためにライブラリ化したものです。
  • LibTF5.mqh:MQL4で対応していないMQL5のタイムフレームや、テクニカル指標関数MQL4で利用するためにライブラリ化したものです。

MT4・MT5を共通化すると

 書籍で紹介されていたソースは、別ロジックになっていましたので、これは MT5 を共通ライブラリ化したものになっています。
 取引システムがMT4からMT5へ移行しても、組み替えることなくそのままで継続使用ができます。

//共通ライブラリ
#include "LibEA/LibEA.mqh"
sinput double Lots = 0.1;       //売買ロット数
input int FastMAPeriod = 20;    //短期移動平均の期間
input int SlowMAPeriod = 50;    //長期移動平均の期間
//ティック時実行関数
void Tick()
{
   //1本前と2本前の移動平均
   double FastMA1 = iMA(_Symbol, 0, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
   double FastMA2 = iMA(_Symbol, 0, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 2);
   double SlowMA1 = iMA(_Symbol, 0, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
   double SlowMA2 = iMA(_Symbol, 0, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 2);
   int pos = 0;    //ポジションの状態
   //未決済ポジションの有無
   if (MyOrderType(0) == OP_BUY) pos = 1;     //買いポジション
   if (MyOrderType(0) == OP_SELL) pos = -1;   //売りポジション
   if (FastMA2 <= SlowMA2 && FastMA1 > SlowMA1) {    //買いシグナル
      //売りポジションがあれば決済注文
      if (pos < 0) {
         MyOrderClose(0);
         pos = 0;    //決済成功すればポジションなしに
      }
      //ポジションがなければ買い注文
      if (pos == 0) MyOrderSend(OP_BUY, Lots, 0, 0); 
   }
   if (FastMA2 >= SlowMA2 && FastMA1 < SlowMA1) {     //売りシグナル
      //買いポジションがあれば決済注文
      if (pos > 0) {
         MyOrderClose(0);
         pos = 0;    //決済成功すればポジションなしに
      }
      //ポジションがなければ売り注文
      if (pos == 0) MyOrderSend(OP_SELL, Lots, 0, 0);
   }
}

 ステップ数もかなり短くなり、わかりやすいソースコードになっています。
 このままで MT4、MT5 のどちらの環境でもコンパイルしてもエラーは発生せず同じ動作をしてくれます。

 ティックごとに実行されるTick()関数では、「MyOrderType」・「MyOrderSend」・「MyOrderClose」などの共通ライブラリ関数に置き換わっています。