トレード備忘録 & MT4/MT5インディケータ及びEAの開発

日々のトレード備忘録及びMT4/MT5に関する事項

「FXメタトレーダー入門」のEAを新MT4 Strict クラスで書き換える【3】

2018-08-06 20:58:36 | 投資

 前2回に亘って「FXメタトレーダー入門」掲載、最初のEAプログラム例MACross_Exp.mq4を新MT4のメタエディターを使って書き換えてきた。プログラムとしては完結したEAとなったが、今回は新MT4でも新たに装備されたクラス機能を使えばどのような形になるのか、個人的な興味もあって試してみることにした。

 オリジナルEAでは組み込みテクニカル指標、iMA()が使用されているが、この部分は新MT4でクラスライブラリとして定義されているCiMAを使って書き換えることができる。このクラスを利用するためにはプログラムの最初に#include <Indicators\Indicators.mqh>と記載(インクルード)しておく必要がある。クラスオブジェクトを作成してEAで利用する方法については豊島久道著ラトルズ版「メタトレーダーで始めるFXシステムトレードプログラミング」に詳しく説明されている。該当部分をほとんど丸写しで使用させていただいて、完成したEAは下記のとおりである。

 過去ブログでも紹介のとおり、豊島先生は昨年9月にMT4/5共通ライブラリLibEA.mqhを公開された。そこではテクニカル指標の扱いが大きく異なるMT5においても、従来のMT4の組み込みテクニカル指標(iMaやiBands)とまったく同じ感覚で利用できるように工夫されている。旧MT4の基本知識があれば十分なので、雑多に装備されたMT4/5搭載のクラス機能を改めて勉強する必要はないといってもよい。

//MACross_Exp_CiMA.mq4

#property strict

//マジックナンバー
#define MAGIC 20070828

#include <Indicators\Indicators.mqh> //テクニカル指標クラスの定義

//テクニカル指標の設定
CiMA FastMA, SlowMA; //移動平均のオブジェクト
input int FastMAPeriod = 10; // 短期移動平均の期間
input int SlowMAPeriod = 40; // 長期移動平均の期間

input double Lots = 0.1;
input int SlippagePips = 3;
int Slippage;

//仕掛けシグナル関数
int EntrySignal()
{
//テクニカル指標の初期化
if(FastMA.MaPeriod() < 0)
FastMA.Create(_Symbol, 0, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
if(SlowMA.MaPeriod() < 0)
SlowMA.Create(_Symbol, 0, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE);

//テクニカル指標の更新
FastMA.Refresh();
SlowMA.Refresh();

int ret = 0; //シグナルの初期化

//買いシグナル
if(FastMA.Main(1) > SlowMA.Main(1)
&& FastMA.Main(2) <= SlowMA.Main(2)) ret = 1;

//売りシグナル
if(FastMA.Main(1) < SlowMA.Main(1)
&& FastMA.Main(2) >= SlowMA.Main(2)) ret = -1;

return ret; //シグナルの出力
}

//ポジション決済関数
void ClosePositions()
{
for(int i=0; i<OrdersTotal(); i++)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) == false) break;
if(OrderMagicNumber() != MAGIC || OrderSymbol() != Symbol()) continue;
//オーダータイプのチェック
if(OrderType()==OP_BUY)
{
int ticket = OrderClose(OrderTicket(),OrderLots(),Bid,Slippage,White);
break;
}
if(OrderType()==OP_SELL)
{
int ticket = OrderClose(OrderTicket(),OrderLots(),Ask,Slippage,White);
break;
}
}
}
//初期化関数
int OnInit()
{
Slippage = SlippagePips*10;
if(_Digits == 2 || _Digits == 4)
{
Slippage = SlippagePips;
}
return(INIT_SUCCEEDED);
}

//ティック関数 
void OnTick()
{

//トレード可能かチェック
if(IsTradeAllowed()==false) return;

int sig_entry = EntrySignal();

// 買い注文
if(sig_entry > 0)
{
ClosePositions();
static datetime time = Time[0];
if(time != Time[0])
{
int ticket = OrderSend(Symbol(),OP_BUY,Lots,Ask,Slippage,0,0,"",MAGIC,0,Blue);
time = Time[0];
}
}

//売り注文
if(sig_entry < 0)
{
ClosePositions();
static datetime time = Time[0];
if(time != Time[0])
{
int ticket = OrderSend(Symbol(),OP_SELL,Lots,Bid,Slippage,0,0,"",MAGIC,0,Red);
time = Time[0];
}
}

}

(注1)豊島先生は、共通ライブラリLibEA.mqh開発前には3種類のライブラリを公開されてきた。そのうち、MyLib.mqhは旧MT4に対応するもので、「FXメタトレーダー実践プログラミング」にて採用されている。現在でもこのライブラリは広く愛用されていて、引き続き旧メタエディター上でプログラムを作成している人が多い。その後、MyPosition.mqhを「FXメタトレーダー4&5 一挙両得プログラミング」にてMT4、MT5別個のライブラリとして公開。そして、MT4/5 共通ライブラリの先駆ともいえるLibPosition.mqhをラトルズ版「FXシステムプログラミング」にて公開されてきた。最新のLibEA.mqhはMT4/5共通ライブラリの完成版であり、現在では上記3種類の旧ライブラリはすべてこのライブラリに実質統合されている。

(注2)仕掛けシグナル関数中、テクニカル指標の更新(Refresh())はMT4では必要としないが、MT5との共通性を考慮してそのまま残している。コメントアウトすることができる。

 


「FXメタトレーダー入門のEAを新MT4 Strictで書き換える【2】

2018-08-05 11:09:16 | 投資

 前ブログでは、豊島久道著「FXメタトレーダー入門」の最初のEA例、MACross_Exp.mq4の内容を変えずにそのまま新MT4 Strictにて書き換えたサンプルを示した。ただし、そこでのEA例は文法的には正しいが、実際にデモで試してみると不都合なところが出てくる。その内容は;

① Slippageのピップス表示の問題

 「FXメタトレーダー入門」は2008年1月に刊行されている。当時の通貨ペアの価格表示はドル円では小数点以下2桁表示、ユーロドルでは小数点以下4桁表示が通常となっていた。その後、通貨ペアの価格表示は小数点以下3桁表示ないしは5桁表示が一般的になってきている。プログラム中のSlippage 3は小数点以下の最小単位3 Pointsを意味するが、これは現在の価格表示に合わせると30 Pointsに相当する。換言すると、1 pipの価値は現在では1/10となり、ドル円0.003円、ユーロドルでは0.00003ドルに相当し、そのままでは本来の意図とは異なる結果となる。ピップスのポイントへの換算が自動的に行われるよう、初期化関数OnInit()内で調整した。 

② Volume[0] > 1の誤作動

 この関数がしばしば正常に作動しないことが知られている。この条件を削除して新たに static datetime time = Time[0]を使って代替した。 

③ 新MT4クラスライブラリーの利用

 クラスによってiMa()を書き換えることを考えたが、これをOntick関数内で行うと、プログラムが複雑になるので、稿を改めて別途エントリー関数を作成することとしたい。以下①②を修正したEA例;

//MACross_Exp_Strict Rev.mq4

#property strict

 //マジックナンバー

#define MAGIC  20070828

//パラメーター

input int FastMA_Period = 10;

input int SlowMA_Period = 40;

input double Lots = 0.1;

input int SlippagePips = 3;

int Slippage;

//| ポジションを決済する                                            

void ClosePositions()

{

   for(int i=0; i<OrdersTotal(); i++)

   {

      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) == false) break;

      if(OrderMagicNumber() != MAGIC || OrderSymbol() != Symbol()) continue;

      //オーダータイプのチェック

      if(OrderType()==OP_BUY)

      {

         int ticket = OrderClose(OrderTicket(),OrderLots(),Bid,Slippage,White);

         break;

      }

      if(OrderType()==OP_SELL)

      {

         int ticket = OrderClose(OrderTicket(),OrderLots(),Ask,Slippage,White);

         break;

      }

   }

}

//Expert initialization function                                   |

int OnInit()

  {

    Slippage =  SlippagePips*10;

    if(_Digits == 2 || _Digits == 4)

    {

      Slippage = SlippagePips;

    }

      return(INIT_SUCCEEDED);

  }

//Expert tick function                                             |

void OnTick()

  {

   //トレード可能かチェック

   if(IsTradeAllowed()==false) return;

    //移動平均の計算

   double FastMA1 = iMA(_Symbol,0,FastMA_Period,0,MODE_SMA,PRICE_CLOSE,1);

   double SlowMA1 = iMA(_Symbol,0,SlowMA_Period,0,MODE_SMA,PRICE_CLOSE,1);

   double FastMA2 = iMA(_Symbol,0,FastMA_Period,0,MODE_SMA,PRICE_CLOSE,2);

   double SlowMA2 = iMA(_Symbol,0,SlowMA_Period,0,MODE_SMA,PRICE_CLOSE,2);

   //買いシグナル

   if(FastMA2 <= SlowMA2 && FastMA1 > SlowMA1)

   {

      ClosePositions();

      static datetime time = Time[0];

      if(time != Time[0])

      {

        int ticket = OrderSend(Symbol(),OP_BUY,Lots,Ask,Slippage,0,0,"",MAGIC,0,Blue);

        time = Time[0];

      }

      return;

   }

 

   //売りシグナル

   if(FastMA2 >= SlowMA2 && FastMA1 < SlowMA1)

   {

      ClosePositions();

      static datetime time = Time[0];

      if(time != Time[0])

      {

        int ticket = OrderSend(Symbol(),OP_SELL,Lots,Bid,Slippage,0,0,"",MAGIC,0,Red);

        time = Time[0];

      }

      return;

   }

  

  }

 


「FXメタトレーダー入門」のEAを新MT4 Strictで書き直す【1】

2018-08-03 15:14:40 | 投資

  豊島久道著「FXメタトレーダー入門」で最初のEAとして登場したのは「MACross_Exp.mq4」というプログラム例であった(同著222頁)。長短2本の移動平均線を使った途転売買システムで、およそ実用には堪えないEAであったが、初めてプログラムに取り組む初級者にとっては、格好な教材であった。 

 今回はこの旧MT4で書かれた「MACross_Exp.mq4」を新MT4 Strictで書き直してみるとどうなるのか、オリジナルの中身を変えないでエラーやウオーニングが出ない範囲の修正で改造してみたのを末尾に掲げておいた。出来上がったソースコードをコンパイルするとエラーも警告も出てこない。それでは、これでEAとして完全な姿かというと実はそうではない。著者もその後の著作やブログで修正を重ねておられるが、補強すべきところは次の諸点である。次回には、改良後のEAを紹介したい。

① Slippage

 著書刊行当時の通貨ペアの表示は、小数点以下2桁(ドル円)と4桁(ユーロドル)が主流であり、Slippageの単位も当時の1point単位であった。ドル円では0.01円、ユ→ロドルでは0.0001ドルであった。最近では、3桁と5桁表示とするのがほとんどであり、最小表示単位である1pointの価値も1/10となっている。プログラム中のSlippage 3も10倍しなければならない。 

② if(volume[0] > 1) return;

 エントリーは仕掛け条件を満足した次のローソク足の始値でなされることになっており、そのため volume[0] > 1 というフィルターが加えられている。ところがこの関数が実際の運用ではしばしば正しく作動しないことが分かっており、著者もその後のEAでは一切採用されていない。代替処理を必要としている。 

③ クラスライブラリーの活用

 新MT4では構造体をさらに拡張した「クラス」機能を利用した「標準ライブラリー」が用意されている。本EAにも使われているテクニカル指標もCiMAとして定義されている。これのオブジェクトを作成してEAのiMA()に替えた場合のプログラムも試してみたい。 

// MACross_Exp_Strict.mq4

#property strict

//マジックナンバー

#define MAGIC  20070828

//パラメーター

input int FastMA_Period = 10;

input int SlowMA_Period = 40;

input double Lots = 0.1;

input int Slippage = 3;

 

// ポジションを決済する                                             |

void ClosePositions()

{

   for(int i=0; i<OrdersTotal(); i++)

   {

      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) == false) break;

      if(OrderMagicNumber() != MAGIC || OrderSymbol() != Symbol()) continue;

      //オーダータイプのチェック

      if(OrderType()==OP_BUY)

      {

         int ticket = OrderClose(OrderTicket(),OrderLots(),Bid,Slippage,White);

         break;

      }

      if(OrderType()==OP_SELL)

      {

         int ticket = OrderClose(OrderTicket(),OrderLots(),Ask,Slippage,White);

         break;

      }

   }

}

//+------------------------------------------------------------------+

//| Expert tick function                                             |

//+------------------------------------------------------------------+

void OnTick()

{

   //バーの始値でトレード可能かチェック

   if(Volume[0]>1 || IsTradeAllowed()==false) return;

 

   //移動平均の計算

   double FastMA1 = iMA(_Symbol,0,FastMA_Period,0,MODE_SMA,PRICE_CLOSE,1);

   double SlowMA1 = iMA(_Symbol,0,SlowMA_Period,0,MODE_SMA,PRICE_CLOSE,1);

   double FastMA2 = iMA(_Symbol,0,FastMA_Period,0,MODE_SMA,PRICE_CLOSE,2);

   double SlowMA2 = iMA(_Symbol,0,SlowMA_Period,0,MODE_SMA,PRICE_CLOSE,2);

 

   //買いシグナル

   if(FastMA2 <= SlowMA2 && FastMA1 > SlowMA1)

   {

      ClosePositions();

      int ticket = OrderSend(Symbol(),OP_BUY,Lots,Ask,Slippage,0,0,"",MAGIC,0,Blue);

      return;

   }

 

   //売りシグナル

   if(FastMA2 >= SlowMA2 && FastMA1 < SlowMA1)

   {

      ClosePositions();

      int ticket = OrderSend(Symbol(),OP_SELL,Lots,Bid,Slippage,0,0,"",MAGIC,0,Red);

      return;

   }

}

//+------------------------------------------------------------------+