goo blog サービス終了のお知らせ 

海外FX口座でFXMT4自動売買に挑戦!

XMTrading,TitanFM,iFOREXなどの海外FX口座でMT4を使ってFX自動売買に挑戦

Moving Average.mq4を移動平均線のゴールドクロス・デッドクロスに改造

2018-05-11 19:12:48 | MT4(メタトレーダー4)
前回、
Moving Average.ex4について
http://trading-fx.blog.jp/archives/8854259.html
でMT4付属のEA、Moving Average.mq4の中身を見ました。
内容は移動平均線と値段の交差でエントリー・決済してるEAでした。

今回これを改造して期間が異なる移動平均線を二つ用意して
短期移動平均線が長期移動平均線を上に抜けるゴールデンクロスで買い、逆のデッドクロスで売り
決済はその逆の条件というEAに変えたいと思います。

まずマジックナンバーがかぶらないように
#define MAGICMA  20131111
これを
#define MAGICMA  20180511
と適当に今日の日付にでも変えます。

次に期間のパラメータを追加します。
//--- Inputs
input double Lots          =0.1;
input double MaximumRisk   =0.02;
input double DecreaseFactor=3;
input int    MovingPeriod  =12;
input int    MovingShift   =6;
これにもう一つの期間を追加します。
//--- Inputs
input double Lots          =0.1;
input double MaximumRisk   =0.02;
input double DecreaseFactor=3;
input int    MovingPeriodS =7;
input int    MovingPeriodL =21;input int    MovingShift   =6;
短期(Short)と長期(Long)という事でそれぞれMovingPeriodS,MovingPeriodLとし、デフォルトで適当に7,21を設定しました。

次にポジションをとるときの条件を変えます。
//+------------------------------------------------------------------+
//| Check for open order conditions                                  |
//+------------------------------------------------------------------+
void CheckForOpen()
  {
   double ma;
   int    res;
//--- go trading only for first tiks of new bar
   if(Volume[0]>1) return;
//--- get Moving Average 
   ma=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,0);
//--- sell conditions
   if(Open[1]>ma && Close[1]<ma)
     {
      res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,0,0,"",MAGICMA,0,Red);
      return;
     }
//--- buy conditions
   if(Open[1]<ma && Close[1]>ma)
     {
      res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,0,0,"",MAGICMA,0,Blue);
      return;
     }
//---
  }
これを
//+------------------------------------------------------------------+
//| Check for open order conditions                                  |
//+------------------------------------------------------------------+
void CheckForOpen()
  {
   double maS0;
   double maS1;   double maL0;   double maL1;  int    res;
//--- go trading only for first tiks of new bar
   if(Volume[0]>1) return;
//--- get Moving Average 
   maS0=iMA(NULL,0,MovingPeriodS,MovingShift,MODE_SMA,PRICE_CLOSE,0);   maS1=iMA(NULL,0,MovingPeriodS,MovingShift,MODE_SMA,PRICE_CLOSE,1);   maL0=iMA(NULL,0,MovingPeriodL,MovingShift,MODE_SMA,PRICE_CLOSE,0);   maL1=iMA(NULL,0,MovingPeriodL,MovingShift,MODE_SMA,PRICE_CLOSE,1);//--- sell conditions
   if(maS1>maL1 && maS0<maL0)     {
      res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,0,0,"",MAGICMA,0,Red);
      return;
     }
//--- buy conditions
   if(maS1<maL1 && maS0>maL0)     {
      res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,0,0,"",MAGICMA,0,Blue);
      return;
     }
//---
  }
maS0,maS1,maL0,maL1を作ってそれぞれに
短期移動平均線現在の足、一本前の足、長期移動平均線現在の足、一本前の足
を当てはめます。
デッドクロスを、一本前の長期移動平均線より短期移動平均線が大きく、現在の足の長期移動平均線より短期移動平均線が小さいと表します。
ゴールデンクロスはその逆です。

決済の時の条件も同様に変えます。
//+------------------------------------------------------------------+
//| Check for close order conditions                                 |
//+------------------------------------------------------------------+
void CheckForClose()
  {
   double ma;
//--- go trading only for first tiks of new bar
   if(Volume[0]>1) return;
//--- get Moving Average 
   ma=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,0);
//---
   for(int i=0;i<OrdersTotal();i++)
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
      if(OrderMagicNumber()!=MAGICMA || OrderSymbol()!=Symbol()) continue;
      //--- check order type 
      if(OrderType()==OP_BUY)
        {
         if(Open[1]>ma && Close[1]<ma)
           {
            if(!OrderClose(OrderTicket(),OrderLots(),Bid,3,White))
               Print("OrderClose error ",GetLastError());
           }
         break;
        }
      if(OrderType()==OP_SELL)
        {
         if(Open[1]<ma && Close[1]>ma)
           {
            if(!OrderClose(OrderTicket(),OrderLots(),Ask,3,White))
               Print("OrderClose error ",GetLastError());
           }
         break;
        }
     }
//---
  }
ここも同様に
//+------------------------------------------------------------------+
//| Check for close order conditions                                 |
//+------------------------------------------------------------------+
void CheckForClose()
  {
   double maS0;
   double maS1;
   double maL0;
   double maL1;
//--- go trading only for first tiks of new bar
   if(Volume[0]>1) return;
//--- get Moving Average 
   maS0=iMA(NULL,0,MovingPeriodS,MovingShift,MODE_SMA,PRICE_CLOSE,0);
   maS1=iMA(NULL,0,MovingPeriodS,MovingShift,MODE_SMA,PRICE_CLOSE,1);
   maL0=iMA(NULL,0,MovingPeriodL,MovingShift,MODE_SMA,PRICE_CLOSE,0);
   maL1=iMA(NULL,0,MovingPeriodL,MovingShift,MODE_SMA,PRICE_CLOSE,1);
//---
   for(int i=0;i<OrdersTotal();i++)
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
      if(OrderMagicNumber()!=MAGICMA || OrderSymbol()!=Symbol()) continue;
      //--- check order type 
      if(OrderType()==OP_BUY)
        {
         if(maS1>maL1 && maS0<maL0)
           {
            if(!OrderClose(OrderTicket(),OrderLots(),Bid,3,White))
               Print("OrderClose error ",GetLastError());
           }
         break;
        }
      if(OrderType()==OP_SELL)
        {
         if(maS1<maL1 && maS0>maL0)
           {
            if(!OrderClose(OrderTicket(),OrderLots(),Ask,3,White))
               Print("OrderClose error ",GetLastError());
           }
         break;
        }
     }
//---
  }
と買いポジションはデッドクロスで、売りポジションはゴールデンクロスで決済にします。

これで長期を短期が上抜けで買い、長期を短期がした抜けで売り、ポジション取った後は逆の条件で決済
というEAがおそらくできたはず…

それではJPYUSD5分足でいざバックテスト!
screenshot_36
見事な右下がりになりました…

Moving Average.ex4について

2018-05-10 16:15:59 | MT4(メタトレーダー4)
前回バックテストを行いました
XMのMT4に最初から付属しているMoving Average.ex4について素人ながらみていきたいと思います。
Moving Average.ex4は直接見ることができないのでMoving Average.mq4を開きます。
EAに書かれているプログラムの大まかな流れとしては
・外部から変更可能なパラメータの設定
・所有ポジションを調べる関数作成
・ロットサイズの設定
・ポジションを持つかどうかの判断の関数作成
・ポジションを決済するかどうかの判断の関数の作成
・ティックがうごいた時に読み込む関数の指定
といった感じでしょうか?
//+------------------------------------------------------------------+ //| Moving Average.mq4 | //| Copyright 2005-2014, MetaQuotes Software Corp. | //| http://www.mql4.com | //+------------------------------------------------------------------+
「//」で始まるところはプログラムとは機能しないのでメモやコメントなどを書いたりします。

#property copyright   "2005-2014, MetaQuotes Software Corp."
#property link        "http://www.mql4.com"
#property description "Moving Average sample expert advisor"
「#property」で設定しておくとEAについての説明みたいなものが起動したときに表示されます。
screenshot_34
linkは表示されないのでしょうか??よくわかりません。

#define MAGICMA  20131111
「#define」は文字列を定義して数字を代入することができるそうです。
「MAGICMA」という文字列を使うと定義してそこに「20131111」という数字を入れています。
後ほどOrderMagicNumber()が出てきますが、注文に番号を付けることでどのEAでトレードしたかが分かります。

//--- Inputs
input double Lots          =0.1;
input double MaximumRisk   =0.02;
input double DecreaseFactor=3;
input int    MovingPeriod  =12;
input int    MovingShift   =6;
「input」は「extern」と同じような働きをします。
「input」はプログラム内では値が変えられないようです。変数に値を入力します。
「double」は小数点まで扱えて、「int」は整数のみです。
このように記載しておくといちいちプログラムを書き換えなくてもEAを起動した時の「パラメータの入力」やバックテストの際に値を変えたりすることができます。
screenshot_35

//+------------------------------------------------------------------+
//| Calculate open positions                                         |
//+------------------------------------------------------------------+
int CalculateCurrentOrders(string symbol)
  {
   int buys=0,sells=0;
//---
   for(int i=0;i<OrdersTotal();i++)
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
      if(OrderSymbol()==Symbol() && OrderMagicNumber()==MAGICMA)
        {
         if(OrderType()==OP_BUY)  buys++;
         if(OrderType()==OP_SELL) sells++;
        }
     }
//--- return orders volume
   if(buys>0) return(buys);
   else       return(-sells);
  }
オープンポジション(所有ポジション)の計算をしています。
CalculateCurrentOrders()という関数を作って
OrderSelect()で所有ポジションがあるか調べ、OrderSymbol()で通貨ペアとマジックナンバーが一致しているか調べて、買いならbuysの値を増やし、売りならsellsの値を増やしてマイナスをかけています。

//+------------------------------------------------------------------+
//| Calculate optimal lot size                                       |
//+------------------------------------------------------------------+
double LotsOptimized()
  {
   double lot=Lots;
   int    orders=HistoryTotal();     // history orders total
   int    losses=0;                  // number of losses orders without a break
//--- select lot size
   lot=NormalizeDouble(AccountFreeMargin()*MaximumRisk/1000.0,1);
//--- calcuulate number of losses orders without a break
   if(DecreaseFactor>0)
     {
      for(int i=orders-1;i>=0;i--)
        {
         if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false)
           {
            Print("Error in history!");
            break;
           }
         if(OrderSymbol()!=Symbol() || OrderType()>OP_SELL)
            continue;
         //---
         if(OrderProfit()>0) break;
         if(OrderProfit()<0) losses++;
        }
      if(losses>1)
         lot=NormalizeDouble(lot-lot*losses/DecreaseFactor,1);
     }
//--- return lot size
   if(lot<0.1) lot=0.1;
   return(lot);
  }
ロットサイズの計算をしています。
HistoryTotal()はOrdersHistoryTotal()の昔の関数でクローズした注文数の値です。
AccountFreeMargin()は余剰証拠金額を取得します。
それに最初設定したMaximumRiskをかけて1000で割ったものの小数点第1位まで求めています。
lossesで負けトレード数をカウントして負けるとロット数を減らすようにしています。
0.1より小さいときは0.1にしています。

//+------------------------------------------------------------------+
//| Check for open order conditions                                  |
//+------------------------------------------------------------------+
void CheckForOpen()
  {
   double ma;
   int    res;
//--- go trading only for first tiks of new bar
   if(Volume[0]>1) return;
//--- get Moving Average 
   ma=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,0);
//--- sell conditions
   if(Open[1]>ma && Close[1]<ma)
     {
      res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,0,0,"",MAGICMA,0,Red);
      return;
     }
//--- buy conditions
   if(Open[1]<ma && Close[1]>ma)
     {
      res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,0,0,"",MAGICMA,0,Blue);
      return;
     }
//---
  }
CheckForOpen()という関数を作ってポジションを持つときの状態を確認しています。
Volume[0]>1というのは新しい足にティック数がある場合を指します。
この時はreturnで戻っているので新しい足にティック数がある場合はトレードしない、
つまり新しい足ができた直後トレードするようになっています。
iMA()関数は移動平均線の関数でそれが
Open[1](一つ前の足の始値)より小さくかつClose[1](一つ前の足の終値)より大きい、つまり移動平均線を価格が下に抜けた場合に売り注文をだします。
その逆なら買い注文を出します。
注文はOrderSend()関数を使います。


//+------------------------------------------------------------------+
//| Check for close order conditions                                 |
//+------------------------------------------------------------------+
void CheckForClose()
  {
   double ma;
//--- go trading only for first tiks of new bar
   if(Volume[0]>1) return;
//--- get Moving Average 
   ma=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,0);
//---
   for(int i=0;i<OrdersTotal();i++)
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
      if(OrderMagicNumber()!=MAGICMA || OrderSymbol()!=Symbol()) continue;
      //--- check order type 
      if(OrderType()==OP_BUY)
        {
         if(Open[1]>ma && Close[1]<ma)
           {
            if(!OrderClose(OrderTicket(),OrderLots(),Bid,3,White))
               Print("OrderClose error ",GetLastError());
           }
         break;
        }
      if(OrderType()==OP_SELL)
        {
         if(Open[1]<ma && Close[1]>ma)
           {
            if(!OrderClose(OrderTicket(),OrderLots(),Ask,3,White))
               Print("OrderClose error ",GetLastError());
           }
         break;
        }
     }
//---
  }
CheckForClose()という関数を作ってポジションを決済するときの状態を確認しています。
買い注文のポジションを持っている場合は、移動平均線が1つ前の足の始値より小さくかつ終値より大きい場合、つまり移動平均線を価格が下に抜けた場合に決済されます。


//+------------------------------------------------------------------+
//| OnTick function                                                  |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- check for history and trading
   if(Bars<100 || IsTradeAllowed()==false)
      return;
//--- calculate open orders by current symbol
   if(CalculateCurrentOrders(Symbol())==0) CheckForOpen();
   else                                    CheckForClose();
//---
  }
//+------------------------------------------------------------------+
OnTick()でティックが更新されるたびに読み込みます。
Bars<100で足の数が100未満、IsTradeAllowed()==falseでトレードができない場合は注文を出しません。
CalculateCurrentOrders(Symbol())==0)はポジションがない状態を指します。その時はCheckForOpen()の関数でポジションを取るかどうかの判定に移ります。それ以外の時はポジションがある状態ですのでCheckForClose()関数で決済するかどうかの判定に移ります。

ロットサイズの計算とかちょっとややこしいですね。
Moving Averageというから移動平均線のゴールデンクロスやデッドクロスを使うのかと思ったら、
移動平均線が価格を上抜けした場合にロング、逆ならショート、
決済条件はポジションを取ったときの条件の逆というシンプルなものでした。

MT4でEAバックテスト

2018-04-27 21:49:09 | MT4(メタトレーダー4)
前回、
MT4でヒストリーデータをダウンロード1~データのインストール~
http://trading-fx.blog.jp/archives/8806901.html
でMT4でヒストリーデータをダウンロードしましたので、
EA(エキスパートアドバイザー)というプログラムを使ってバックテストをしていきたいと思います。

ツールバーの【表示】→【ストラテジーテスター】をクリックします。
screenshot_20

すると下に【ストラテジーテスター】画面が表示されます。
screenshot_21

初期証拠金を日本円にするために【エキスパートの設定】をクリックします。
screenshot_21

しかし候補には出てこないので、
screenshot_28

強引に【JPY】を入力します。
screenshot_29
【ポジション】は変えることでトレードをロングだけ、ショートだけにする事が出来ますが両方できるようにそのままにします。

では試しに
  • 最初からMT4に付属しているMoving Average.ex4
  • 通貨ペアは以前にヒストリカルデータをダウンロードした「USDJPY」
  • 時間足は「5分足」
  • 期間:2010.01.01~2018.01.01
でバックテストを行います。
設定出来たら【スタート】をクリックしてみましょう。
screenshot_31

緑色のバーが現れますのでしばらく待ちます。
screenshot_32

音が鳴るおもちゃみたいな音がしたら終了です。
下のタブで【グラフ】をクリックすると右下下がりですね…
screenshot_33

この「Moving Average.ex4」がどのような条件をターゲットにしたEAなのかわかりませんが、
この条件ではダメだという事が分かりました。
色々いじってみたいと思います。

MT4でヒストリーデータをダウンロード2~1分足から他の時間足を作成~

2018-04-27 13:28:09 | MT4(メタトレーダー4)
前回の
MT4でヒストリーデータをダウンロード1~データのインストール~
http://trading-fx.blog.jp/archives/8806901.html
では1分足のヒストリーデータをダウンロードしました。
今回はそれを元に他の時間足を作ります。

作り方は1分足のオフラインチャートに他の時間足を作るスクリプトを適用して作る感じです。
MT4に付属してるスクリプトを使って一つずつ作る方法と、公開されている便利なスクリプトをダウンロードして導入して一気に全部作る方法があります。

この確認は特に必要ではありませんが、
現在のヒストリーデータの状態を確認をしてみましょう。【ファイル】→【データフォルダを開く】をクリック。
このフォルダはよく使うのでデスクトップにショートカットを作っておくといいかもしれません。
screenshot_03


エクスプローラーが起動しますので【history】フォルダを開きます。

screenshot_12

【XMTrading-Demo 3】フォルダを開きます。ここはXMtradingのデモ口座を使ってるのでこの名前になっていますがお使いの業者によって名前が違います。
screenshot_13

フォルダを開くと【USDJPY1.hst】というファイルがあります。これがドル円1分足のデータです。
それ以外はまだありません。
screenshot_16
確認は以上で終わりです。

他の時間足を作っていきましょう。
ツールバーの【ファイル】→【オフラインチャート】をクリック。
2018-04-27_12h28_51


オフラインチャートを開くとヒストリーデータリストが表示されますので
【USDJPY,M1】を選んで【開く】をクリック。
下の【USDJPY,M1(Every tick)】はおそらく起動したときに読み込んだ直近のデータだと思いますがバーが少ないので使いません。
2018-04-27_12h53_29

オフラインチャートが開きます。
  • 付属のスクリプトを使う方法
左下の【スクリプト】の中にある【PeriodConverter】をダブルクリック。
2018-04-27_12h37_20

スクリプトが起動したら【パラメータの入力】タブをクリック。
2018-04-27_12h38_45

値の【3】と書かれているところをダブルクリックして、まずは5分足を作るので【5】と書き換えて【OK】をクリック。
2018-04-27_12h39_09

下の【エキスパート】タブを開いて【PeriodConverter~~record(s) written】と表示されればコンバート終了です。
screenshot_01

また同様に【PeriodConverter】をダブルクリック。このような表示が出ますが【はい】をクリック。
2018-04-27_12h40_16

次は15分足を作りますので同様に【5】と書いたところを【15】と書いて【OK】をクリック。
その作業を30分足の【30】、1時間足の【60】、4時間足の【240】、日足の【1440】、週足の【10080】、月足の【43200】と入力して繰り返して全ての時間足を作成します。
  • period_converter_ALL.mq4を使う方法
もう一つの方法は公開されている
period_converter_ALL.mq4を使って自動的に一気に作る方法です。

period converter ALL - скрипт для MetaTrader 4
https://www.mql5.com/ru/code/11201
にアクセスして
矢印のところをクリックしてperiod_converter_ALL.mq4をダウンロードします。
screenshot_02

【ファイル】→【データフォルダを開く】でフォルダを開きます。
screenshot_03

フォルダを開いたら【MQL4】、
screenshot_04
【Scripts】フォルダ内にperiod_converter_ALL.mq4を入れます。
screenshot_05

MT4を再起動してもいいですが左の【ナビゲーター】内で右クリックして
screenshot_06


メニューの【更新】をクリックします。
screenshot_07

少し待つと【period_converter_ALL】が現れますので1分足のオフラインチャートが表示されている状態でダブルクリックします。
screenshot_09

するとチャート内左上に、変換する残りのバー数が表示され5分足から順番に作られるのでしばらく待ちましょう。
screenshot_10

表示が消えたら終わりです。
screenshot_11


【ファイル】→【オフラインチャート】を開くと他の時間足ができました。
screenshot_18

また、最初に確認しましたフォルダに他の時間足のファイルが出来ていることもわかります。
screenshot_15

以上が1分足から他の時間足を作る方法です。
二つ目のスクリプトを使う方法がスクリプトの導入の手間がありますが楽だと思います。
今後もネットでスクリプトやインジケーターをダウンロードして導入することも増えると思いますので
こっちの方法に慣れたほうがいいでしょう。

iMA()関数

2018-04-26 13:33:07 | MT4(メタトレーダー4)
移動平均線インジケーターを計算しその値を求める関数です。
iMA(symbol, timeframe,ma_period,ma_shift,ma_method,applied_price,shift)
 
パラメータ
  • symbol
インジケーターが計算する通貨の名前です。"NULL"にすると使用するチャートの通貨が適応されます。
  • Timeframe
適応する時間足です。
文字数値適応される時間足
PERIOD_CURRENT現在の時間足
PERIOD_M111分足
PERIOD_M555分足
PERIOD_M151515分足
PERIOD_M303030分足
PERIOD_H1601時間足
PERIOD_H42404時間足
PERIOD_D11440日足
PERIOD_W110080週足
PERIOD_MN143200月足
  • ma_period
移動平均線が計算する期間です。
  • ma_shift
移動平均線が右側にシフトするバーの数です。
  • ma_method
移動平均線の種類です。文字または数値で入力します。
文字数値移動平均線の種類
MODE_SMA0単純移動平均線
MODE_EMA1指数移動平均線
MODE_SMMA2平滑移動平均線
MODE_LWMA3線形加重移動平均線
  • applied_price
適応する価格の種類です。文字または数値で入力します。
文字数値価格の種類
PRICE_CLOSE0終値
PRICE_OPEN1始値
PRICE_HIGH2高値
PRICE_LOW3安値
PRICE_MEDIAN4中央値:(高値+安値)/2
PRICE_TYPICAL5代表値:(高値+安値+終値)/3
PRICE_WEIGHTED6加重終値:(高値+安値+終値+終値)/4
  • shift
値を取得したいバーの位置です。0なら現在のバー、1なら一つ前のバーです。
  • サンプル
double MA= iMA(NULL,0,21,0,MODE_EMA,PRICE_CLOSE,1);
適応してるチャートの通貨・時間足で、21本分のデータを使ってシフトなしで1つ前のバーの終値でEMAの値を求めます。