50歳手前の糖尿病メタボおっちゃんの色々悪あがき日記

老後の健康とお金のため・仕事をサボるため、あくせく悪あがきして生きています♪

とりあえず使えるようになる!メタトレーダー5でバックテスト~(6)オーダーを実装する。

 今回は、遂にエキスパートを完成します。
 エキスパートの主機能である「発注」を実装いたします。
 MT4で一行で済んでいた「OrderSend」関数が、なんやらヘンチクリンなことになっています。

 

 

今回のステップ

・MT5を使おう<基礎編>
 □.MT5をインストールする。
    ↓
 □.何もしないEAを作り、動作させる。
    ↓
 □.何か適当なメッセージをログ出力してみる。
    ↓
 □.過去一定期の四本値を取得してみる。
    ↓
 □.単純な売買ルール「山越えで売り・谷越えで買い」を実装する。
    ↓
 □.オーダーを実装する。
    ↓
 □.バックテスト。

 

実習

早速実習です。今回は前回作成した「test04.mq5」を使用いたします。

①エディターを起動し「test04.mq5」を開きます。

 

ソースコードに、以下を追加します。
 場所はソースコード先頭部。
 赤字部分をコピーし、ソースコードに貼り付けてください。

//+------------------------------------------------------------------+
//|                                                       test01.mq5 |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#define EXPERT_MAGIC 123456 
//外部変数
input int Kikan = 60;
input double MinBand = 40;

 

ソースコードの以下を一旦削除します。
 前回「工事中」の「Ordr」関数

  
double valPips(double pips)
{
   double price = 0;

   int digits = (int)Digits();

   if(digits == 3 || digits == 5){
     price = pips / MathPow(10, digits) * 10;
   } else {
     price = pips / MathPow(10, digits);
   }
   price = NormalizeDouble(price, digits);
   return(price);
}

void Ordr(string BuySell,double Lots) {
  //工事中
}

 

ソースコードに以下を貼り付けます。
 場所はソースコード末尾
 赤字部分をコピーし、ソースコードに貼り付けてください。

  
double valPips(double pips)
{
   double price = 0;

   int digits = (int)Digits();

   if(digits == 3 || digits == 5){
     price = pips / MathPow(10, digits) * 10;
   } else {
     price = pips / MathPow(10, digits);
   }
   price = NormalizeDouble(price, digits);
   return(price);
}

void Ordr(string strOdr,double valLots)
  {
   MqlTradeRequest request={0};
   MqlTradeResult  result={0};
   bool ret;
request.magic = EXPERT_MAGIC; request.action = TRADE_ACTION_DEAL; request.symbol = Symbol(); request.volume = valLots; if (strOdr == "BUY") { request.type = ORDER_TYPE_BUY; request.price = SymbolInfoDouble(Symbol(),SYMBOL_ASK); request.sl = SymbolInfoDouble(Symbol(),SYMBOL_BID) - valPips(20); request.tp = SymbolInfoDouble(Symbol(),SYMBOL_BID) + valPips(20); } else { request.type = ORDER_TYPE_SELL; request.price = SymbolInfoDouble(Symbol(),SYMBOL_BID); request.sl = SymbolInfoDouble(Symbol(),SYMBOL_ASK) + valPips(20); request.tp = SymbolInfoDouble(Symbol(),SYMBOL_ASK) - valPips(20); } ret = OrderSend(request,result); }

 

⑤別名で保存 
 今回は正式名「YamaTani.mq5」で保存してください。

 

コンパイル

 前回同様エラーにならない事を確認してください。

 

⑦テスト

 今回動作させると、「ストラテジーテスター」の「バックテスト」に、売買を行った結果が反映されます。

f:id:edger_arkw:20200517062447p:plain

バックテスト

 同様にグラフにも反映されます。

f:id:edger_arkw:20200517062601p:plain

グラフ

 

 ~ 以上で終了です。


実習の説明

構造体

 構造体は「変数の詰め合わせ」です。
 MT4のときは、関数の引数は変数だけでした。
 MT5では、引数に複数の変数を渡す必要が関数は、この構造体を使ってまとめて渡す必要があります。
 関数で使用する構造体は、あらかじめ準備されているので、新たに宣言する必要はありません。
 普段使いのプログラムで便利と感じないので、積極的に使わなくて構わないかと。
 MT5の仕様で、嫌嫌使わされる感覚でいいと思います。

 

関数「Ordr」について

 まず、2つの引数を受け取ります。
 そのオーダーが「買い」なのか「売り」なのかを示す文字型変数「strOdr」と、どれだけの数量をオーダーするかを示す実数型変数「valLots」の2つです。

void Ordr(string strOdr,double valLots)
{

 

 次に発注関数「OrderSend()」への受け渡しのための「MqlTradeRequest型構造体」の「request」と、逆に実行結果を返却する「MqlTradeResult型構造体」の「result」を初期化しています。

MqlTradeRequest request={0};
MqlTradeResult result={0};

 

 「売り」「買い」に関係ない共通の構造体変数を設定しています。

request.magic  = EXPERT_MAGIC;     マジックナンバー
request.action = TRADE_ACTION_DEAL;  ←アクション
request.symbol = Symbol();       ←通貨ペア
request.volume = valLots;        ←ロット数

 

説明 内容
マジックナンバー エキスパートの個体ナンバーです。同じ証券口座で複数エキスパートを実働する場合にしか意味ないです。適当な番号を実習工程②で指定しました。
アクション この関数、発注する以外にも様々な機能があります。ここでは「TRADE_ACTION_DEAL(発注)」を指定しています。
通貨ペア ストラテジーテスターで指定した通貨ペアを「Symbol()」関数で取得しています。
ロット数 引数「valLots」を渡しています。1ロット10万通貨(ドルなら10万ドル、ユーローなら10万ユーロ)に対し、0.01ロットは1000通貨となります。

 

 引数「strOdr」の「売り」「買い」で処理を分岐しています。

   if (strOdr == "BUY") 
      request.type  = ORDER_TYPE_BUY; ←買い
      request.price = SymbolInfoDouble(Symbol(),SYMBOL_ASK); ←買い値
      request.sl    = SymbolInfoDouble(Symbol(),SYMBOL_BID) - valPips(20); 損切り
      request.tp    = SymbolInfoDouble(Symbol(),SYMBOL_BID) + valPips(20); ←利得値
   } else {
      request.type  = ORDER_TYPE_SELL; ←売り
      request.price = SymbolInfoDouble(Symbol(),SYMBOL_BID); ←売り値
      request.sl    = SymbolInfoDouble(Symbol(),SYMBOL_ASK) + valPips(20); 損切り
      request.tp    = SymbolInfoDouble(Symbol(),SYMBOL_ASK) - valPips(20); ←利得値
   }

 今回の場合「成り行き=そのときの値段で売買」でオーダーしています。
 注文と同時に、20Pips以上の損失時にロスカット、20Pips以上の利益に利食いするよう設定しています。 

 

 発注関数「OrderSend」を実行します。
 結果が「result」に返却されますが、バックテストでは、こちらの提示した売買値・数量で100%取引が成立するので、例外処理などは一切していません。

ret = OrderSend(request,result);

 

~ 今回は以上となります。オツカレサマでした。