ゼロから始めるEA開発Part6 移動平均の使い方
前回はストップロスとテイクプロフィットの計算について解説しました。これで、基本の形は一応完成したので…
今回は、いよいよインジケーターを用いて自動売買システムを作っていきたいと思います。
移動平均の呼び出し
今までは「開始時間に買う」というだけのシステムでしたが、テクニカルを組み込んで売買するように修正します。
「指数平滑移動平均(EMA)よりも価格が上」であれば「買い」、「指数平滑移動平均(EMA)よりも価格が下」であれば「売り」を行うようにしてみましょう。
if(Hour() == StartHour && OrdersTotal() == 0 && IsOpened == false) { double stopLoss = 0; double takeProfit = 0; double ema = iMA(Symbol(),0,EMAPeriod,0,MODE_EMA,PRICE_CLOSE,0); if(Ask > ema) { stopLoss = Ask - StopLoss * Point; takeProfit = Bid + TakeProfit * Point; OrderSend(Symbol(),OP_BUY,Lots,Ask,Slippage,stopLoss,takeProfit,OrdersComment,Magic,0,clrBlue); } if(ema > Bid) { stopLoss = Bid + StopLoss * Point; takeProfit = Ask - TakeProfit * Point; OrderSend(Symbol(),OP_SELL,Lots,Bid,Slippage,stopLoss,takeProfit,OrdersComment,Magic,0,clrRed); } IsOpened = true; }
オープンのロジックは大幅に変更しました。
まずは「買い」「売り」両方でstopLossという変数を使用するので一番上へ移動しました。
そしてiMA関数を実行し、EMAを取得しています。
double ema = iMA(Symbol(),0,EMAPeriod,0,MODE_EMA,PRICE_CLOSE,0);
最初のSymbol()はOrderSendと同様「使用している通貨ペア」を返します。もしここに”USDJPY”と書けばEURUSDのチャートからUSDJPYに発注する事もできます。
次の0は時間軸。0とすると「現在の時間軸」を指定したことになります。他の時間軸の移動平均を取りたい場合にはPERIOD_H4等と書けば取得できます。(PERIOD_H4は4時間足です。他にもPERIOD_M5やPERIOD_M30などがあります)
その後ろが期間です。今回はパラメーターにしていますので、パラメーターにEMAPeriodをdouble型で定義してください。
その次の0は移動平均の右方向シフトするバー(足)の数です。シフトしたい場合には1以上の値を指定します。
そして次のMODE_EMAが指数平滑移動平均(EMA)を取得するための指定です。単純移動平均の場合にはMODE_SMAを指定してください。
次が移動平均に使用する価格で、PRICE_CLOSEは「終値で移動平均を計算する」指定です。PRICE_OPENやPRICE_HIGH、PRICE_TYPICAL(高値+安値+終値を3で割った値)など指定できます。
最後の0は「何本前から計算するか」です。0は現在のバー(足)になります。たとえば1本前の足から移動平均計算したい場合には1を指定します。
関数の使い方については細かく書いているサイトもあります(検索すればすぐに見つかります)し、関数ライブラリとして「FXメタトレーダー実践プログラミング」を1冊買っても良いと思います。何年もEA開発していますが、いまだに愛用している書籍です。(「入門」もありますが、それは使っていません。)
次に「取得したEMA」と「価格」を比較します。
if(Ask > ema)
これで買値よりもEMAが大きい場合には買いです。売りの場合は売値と比較します。
売りの場合の「ストップロスの計算式」や「テイクプロフィットの計算式」は買いの場合と異なるので注意して下さい。
OrderSendも「OP_SELL」を指定し、「Bid」で注文しています。
以下、修正したプログラム全文です。
//+------------------------------------------------------------------+ //| ZeroCreatePart2.mq4 | //| | //| | //+------------------------------------------------------------------+ #property copyright "" #property link "" #property version "1.00" #property strict input int Magic = 123465; input double Lots = 0.1; input int Slippage = 2; input string OrdersComment = "ZeroCreate"; input int StopLoss = 200; input int TakeProfit = 400; input int StartHour = 9; input int StopHour = 18; input int EMAPeriod = 20; bool IsOpened = false; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { if(Hour() == StartHour && OrdersTotal() == 0 && IsOpened == false) { double stopLoss = 0; double takeProfit = 0; double ema = iMA(Symbol(),0,EMAPeriod,0,MODE_EMA,PRICE_CLOSE,0); if(Ask > ema) { stopLoss = Ask - StopLoss * Point; takeProfit = Bid + TakeProfit * Point; OrderSend(Symbol(),OP_BUY,Lots,Ask,Slippage,stopLoss,takeProfit,OrdersComment,Magic,0,clrBlue); } if(ema > Bid) { stopLoss = Bid + StopLoss * Point; takeProfit = Ask - TakeProfit * Point; OrderSend(Symbol(),OP_SELL,Lots,Bid,Slippage,stopLoss,takeProfit,OrdersComment,Magic,0,clrRed); } IsOpened = true; } if(Hour() == StopHour) { if(OrdersTotal() > 0) { for(int i=0; i<=OrdersTotal()-1; i++) { if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) == false) break; if(OrderType() == OP_BUY) { OrderClose(OrderTicket(),OrderLots(),Bid,Slippage,clrBlue); } else if(OrderType() == OP_SELL) { OrderClose(OrderTicket(),OrderLots(),Ask,Slippage,clrRed); } } } IsOpened = false; } } //+------------------------------------------------------------------+
それでは、最適化してみましょう。(EMAの期間(EMA_Period)で最適化しました)
・・・悪化しましたね・・・。優位性はないようです・・・。
時刻指定を廃止して移動平均で売買する
「時刻指定」を外して「買いの場合には移動平均を下回ったら」「売りの場合には移動平均を上回ったら」と変えてみました。
//+------------------------------------------------------------------+ //| ZeroCreatePart2.mq4 | //| | //| | //+------------------------------------------------------------------+ #property copyright "" #property link "" #property version "1.00" #property strict input int Magic = 123465; input double Lots = 0.1; input int Slippage = 2; input string OrdersComment = "ZeroCreate"; input int StopLoss = 200; input int TakeProfit = 400; //input int StartHour = 9; //input int StopHour = 18; input int EMAPeriod = 20; bool IsOpened = false; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { double ema = iMA(Symbol(),0,EMAPeriod,0,MODE_EMA,PRICE_CLOSE,0); //if(Hour() == StartHour && OrdersTotal() == 0 && IsOpened == false) if(OrdersTotal() == 0) { double stopLoss = 0; double takeProfit = 0; //double ema = iMA(Symbol(),0,EMAPeriod,0,MODE_EMA,PRICE_CLOSE,0); if(Ask > ema) { stopLoss = Ask - StopLoss * Point; takeProfit = Bid + TakeProfit * Point; OrderSend(Symbol(),OP_BUY,Lots,Ask,Slippage,stopLoss,takeProfit,OrdersComment,Magic,0,clrBlue); } if(ema > Bid) { stopLoss = Bid + StopLoss * Point; takeProfit = Ask - TakeProfit * Point; OrderSend(Symbol(),OP_SELL,Lots,Bid,Slippage,stopLoss,takeProfit,OrdersComment,Magic,0,clrRed); } //IsOpened = true; } //if(Hour() == StopHour) //{ if(OrdersTotal() > 0) { for(int i=0; i<=OrdersTotal()-1; i++) { if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) == false) break; //if(OrderType() == OP_BUY) if(OrderType() == OP_BUY && ema > Ask) { OrderClose(OrderTicket(),OrderLots(),Bid,Slippage,clrBlue); } //else if(OrderType() == OP_SELL) else if(OrderType() == OP_SELL && Bid > ema) { OrderClose(OrderTicket(),OrderLots(),Ask,Slippage,clrRed); } } } IsOpened = false; //} } //+------------------------------------------------------------------+
修正点が分かるように修正前をコメントで残していますが、修正版が次回のベースになりますので残しておく必要はありません。
なお、上記のロジックでは「移動平均付近で価格が上下すると何度もオープン・クローズを繰り返す」という問題がありますので、このままバックテストを実行してもまったく勝てません…。
その辺りを含めて次回、もう少し改良・改善していきたいと思っています。
移動平均以外のインジケーターについて
この「ゼロから始めるEA開発」では、今後、移動平均以外のインジケーターについて解説する予定はありません。(必要に応じて解説することはあるかもしれません)
移動平均以外のインジケーターも「使い方は基本的に同じ」です。
たとえばRSIの場合はこのようになります。
double rsi = iRSI(Symbol(),0,RSIPeriod,PRICE_CLOSE,0);
移動平均の場合と同じような項目ですので、ほとんど説明は不要だと思います。(2番めのゼロは時間軸、最後のゼロは何本目からRSIの計算をするか?です。)
大抵のインジケーターは「iMA(移動平均)の使い方」を理解していれば使えると思います。
さて、次回は最後に修正した「移動平均で売買するシステム」を改良していきます。
以上、初心者向けEA講座「自動売買システムを作ろう!ゼロから始めるEA開発Part6 移動平均の使い方」でした。
コメント
はじめまして(^-^)
ブログの方かなり勉強になります。
ありがとうございますm(__)m
dmija様にどうしても連絡を取らせて頂きたくブログ内に連絡先メールアドレスなどがないか探しましたが見当たりませんでした。
もしよろしければ自分のメールアドレスに連絡頂けないでしょうか?
ここでは書けない内容ですので宜しくお願い致しますm(__)m
コメントありがとうございます。
メールアドレスは「詳しいプロフィール」に記載しているのですが、見つけづらいかもしれませんね…
tradeandsoftwareあっとま~くgmail.com
です。
あっとま~くは@に置き換えてください。
買い注文の場合、以下の書き方をされています。
OrderSend(Symbol(),OP_BUY,Lots,Ask,Slippage,stopLoss,takeProfit,OrdersComment,Magic,0,clrBlue);
売買価格の指定は「買い」なので「Bid」かと思ったのですが、なぜ「Ask」なのでしょうか?
売値がBid、買値がAskなので、買い注文はAskを指定しているのではないでしょうか‥。