【裁量/EA両対応】移動平均のクロスでクローズ(手仕舞い)するEA(ソースコードあり)

 

移動平均のクロスで手仕舞い

移動平均のクロスでクローズ(手仕舞い)するEA

以前コメントにてAutoOrderModifyProに「移動平均のクロスで手仕舞いする機能をつけて欲しい」という要望をいただいたのですが、AutoOrderModifyシリーズにそういったテクニカルによるクローズロジックを付加するのは方向性が異なると思ったのでお断りさせていただきました…

単純なテクニカルで手仕舞いするロジックというのは比較的簡単に作れますし、他のEAと干渉する可能性も低いので別EAとして作ってみることにしました。

もちろん、AutoOrderModifyシリーズと併用できますので、両方稼働すれば「AutoOrderModifyに機能が拡張された」場合と同じ動作になります。

とりあえずソースコード(全文)を以下に掲載します。

ソースコード(全文)

//+------------------------------------------------------------------+
//|                                                  ExitMACross.mq4 |
//|                                 Copyright 2016, TradeAndSoftware |
//|                                                https://tasfx.net |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, TradeAndSoftware"
#property link      "https://tasfx.net"
#property version   "1.00"
#property strict

enum MAMode
{
   SMA = MODE_SMA,
   EMA = MODE_EMA,
   SMMA = MODE_SMMA,
   LWMA = MODE_LWMA
};

enum MATime
{
   M1 = PERIOD_M1,
   M5 = PERIOD_M5,
   M15 = PERIOD_M15,
   M30 = PERIOD_M30,
   H1 = PERIOD_H1,
   H4 = PERIOD_H4,
   W1 = PERIOD_W1,
   MN1 = PERIOD_MN1
};

enum MAPrice
{
   CLOSE = PRICE_CLOSE,
   OPEN = PRICE_OPEN,
   HIGH = PRICE_HIGH,
   LOW = PRICE_LOW,
   MEDIAN = PRICE_MEDIAN,
   TYPICAL = PRICE_TYPICAL,
   WEIGHTED = PRICE_WEIGHTED
};


input string MagicListExample = "ex)123456,77777,42515";   //MagicListExample(MAX10)
input string MagicList = "";
input MAMode MAMethod = EMA;     //MA Methord
input MATime MATimeFrame = H1;   //MA TimeFrame
input MAPrice MAAppliedPrice = CLOSE;  //MA Applied Price
input int FastMAPeriod = 5;   //Fast MA Period
input int SlowMAPeriod = 20;  //Slow MA Period
input int Slippage = 3;

int MagicListCount = 0;
int Magic[10];

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   if(MagicList != "")
   {
      MagicListCount = SetStringToArrayList(Magic);
   }
   
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
   
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
   for(int i=OrdersTotal()-1; i>=0; i--)
   {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) == false) break;
      bool isExistsList = ExistsMagicList(OrderMagicNumber());
      
      if(isExistsList)
      {
         double fastMAPrev = iMA(OrderSymbol(),MATimeFrame,FastMAPeriod,0,(int)MAMethod,(int)MAAppliedPrice,2);
         double fastMA = iMA(OrderSymbol(),MATimeFrame,FastMAPeriod,0,(int)MAMethod,(int)MAAppliedPrice,1);
         double slowMAPrev = iMA(OrderSymbol(),MATimeFrame,SlowMAPeriod,0,(int)MAMethod,(int)MAAppliedPrice,2);
         double slowMA = iMA(OrderSymbol(),MATimeFrame,SlowMAPeriod,0,(int)MAMethod,(int)MAAppliedPrice,1);
      
         if(OrderType()==OP_BUY)
         {
            if(fastMAPrev >= slowMAPrev && fastMA < slowMA)
            {
               if(!OrderClose(OrderTicket(),OrderLots(),MarketInfo(OrderSymbol(),MODE_BID),Slippage))
               {
                  Print("OrderClose Error : " + IntegerToString(GetLastError()));
               }
            }
         }
         else if(OrderType()==OP_SELL)
         {
            if(fastMAPrev <= slowMAPrev && fastMA > slowMA)
            {
               if(!OrderClose(OrderTicket(),OrderLots(),MarketInfo(OrderSymbol(),MODE_ASK),Slippage))
               {
                  Print("OrderClose Error : " + IntegerToString(GetLastError()));
               }
            }
         }
      }
   }
}

int SetStringToArrayList(int &list[])
{
   int beginIndex = 0;
   int endIndex = 0;
   int length = 0;
   int count = 0;
   int i = 0;
   for(i=0; i<10; i++)
   {
      endIndex = StringFind(MagicList,",",beginIndex);
      if(endIndex == -1)
      {
         length = StringLen(MagicList);
         list[i] = (int)StringSubstr(MagicList,beginIndex,length);
         break;
      }
      length = endIndex - beginIndex;
      list[i] = (int)StringSubstr(MagicList,beginIndex,length);
      beginIndex = endIndex + 1;
   }
   count = i + 1;
   return count;
}

bool ExistsMagicList(int magic)
{
   if(MagicListCount == 0) return true;
   
   for(int i=0;i<MagicListCount;i++)
   {
      if(magic == Magic[i]) return true;
   }
   
   return false;   
}

MetaEditorにコピー&ペーストしてコンパイルすれば動くはずです。

ファイル名はExitMACross.mq4としていますが、別になんでも構いません。

解説

ゼロから始めるEA開発」の番外編の位置づけで記事を書いていますので、プログラムの解説をしていきます。(ついでにパラメーターの説明も書きます)

定義(enum)

enum MAMode
{
   SMA = MODE_SMA,
   EMA = MODE_EMA,
   SMMA = MODE_SMMA,
   LWMA = MODE_LWMA
};

enumは数字をわかりやすい文字(単語)に置き換えられます。

メリットはプログラムがわかりやすいことと、MT4のパラメーターで使用した場合、enumで定義した文字列がMT4のパラメーター画面で「リスト表示」されることがあります。

利用者に「SMAは0、EMAは1と入力して下さい」と説明するよりもリストでSMA/EMA/SMMA/LWMAの中から選択するほうが良いに決まっています。

SMA = 0,EMA = 1…と定義してもよいのですが、せっかくMT4で定義されている定数があるので今回はそれ(MODE_xxx)を使いました。

TimeFrameも同じです。TimeFrameってなんのこと?という人がいてもM1/M5/M15…とリストがあれば何を設定する項目かわかると思います。

パラメーター

input string MagicListExample = "ex)123456,77777,42515";   //MagicListExample(MAX10)
input string MagicList = "";
input MAMode MAMethod = EMA;     //MA Methord
input MATime MATimeFrame = H1;   //MA TimeFrame
input MAPrice MAAppliedPrice = CLOSE;  //MA Applied Price
input int FastMAPeriod = 5;   //Fast MA Period
input int SlowMAPeriod = 20;  //Slow MA Period
input int Slippage = 3;

MagicListExampleは使い方の説明です。カンマ区切りでマジックナンバーを指定しましょう…という意味で書いています。(無くても動作には影響ありません)

MagicListにはMagicListExampleに書かれているようにカンマ区切りでマジックナンバーを設定します。

裁量トレードを対象にする場合には0を設定して下さい。ちなみに空にすると全てのマジックナンバーを対象にします。

MAMethodは使用するMAの種類、MATimeFrameは使用するMAの時間軸です。

MAAppliedPriceはMAを計算する時に使用する価格です。CLOSEだとCLOSE価格を計算に使用します。

FastMAPeriodは短期MA、SlowMAPeriodは長期MAの本数で、Slippageは許容するスリッページの設定です。

初期化処理

int OnInit()
{
   if(MagicList != "")
   {
      MagicListCount = SetStringToArrayList(Magic);
   }
   
   return(INIT_SUCCEEDED);
}

初期化処理ではSetStringToArrayList関数を呼び出します。

SetStringToArrayList関数は「カンマ区切りで書かれた文字列を、配列に変換する」という処理になっています。

関数が用意されていて一発変換してくれる言語も多いのですが、MQL4では自作する必要があります。

なぜわざわざ配列化しているかというと、プログラムの中で扱いやすいからです。forループで回して1つずつチェックすれば良いだけですからね!

bool ExistsMagicList(int magic)
{
   if(MagicListCount == 0) return true;
   
   for(int i=0;i<MagicListCount;i++)
   {
      if(magic == Magic[i]) return true; ←ここでチェックしています
   }
   
   return false;   
}

戻り値は「カンマ区切りで幾つマジックナンバーが指定されていたか」を返しています。

マジックナンバーが一致するかどうか

   for(int i=OrdersTotal()-1; i>=0; i--)
   {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) == false) break;
      bool isExistsList = ExistsMagicList(OrderMagicNumber());

最初のfor文で「オーダーの数だけ」ループします。オーダー(待機注文含む)があればループに入り、1つずつチェックしていきます。

ExistsMagicList関数はそのオーダーのマジックナンバーが、カンマ指定したマジックナンバーリストの中に「存在するか」調べる関数です。存在すればtrue、しなければfalseを返します。

MA算出

      if(isExistsList)
      {
         double fastMAPrev = iMA(OrderSymbol(),MATimeFrame,FastMAPeriod,0,(int)MAMethod,(int)MAAppliedPrice,2);
         double fastMA = iMA(OrderSymbol(),MATimeFrame,FastMAPeriod,0,(int)MAMethod,(int)MAAppliedPrice,1);
         double slowMAPrev = iMA(OrderSymbol(),MATimeFrame,SlowMAPeriod,0,(int)MAMethod,(int)MAAppliedPrice,2);
         double slowMA = iMA(OrderSymbol(),MATimeFrame,SlowMAPeriod,0,(int)MAMethod,(int)MAAppliedPrice,1);

マジックナンバーリストに指定されたマジックナンバーだった場合、MAを計算します。

iMAについては「ゼロから始めるEA開発」の中で解説していますので省略します。

判定

         if(OrderType()==OP_BUY)
         {
            if(fastMAPrev >= slowMAPrev && fastMA < slowMA)
            {
               if(!OrderClose(OrderTicket(),OrderLots(),MarketInfo(OrderSymbol(),MODE_BID),Slippage))
               {
                  Print("OrderClose Error : " + IntegerToString(GetLastError()));
               }
            }
         }

オーダーの種類が買いのオープンポジション(OP_BUY)だった場合、MAクロスの判定をします。

2本前(Prev)の短期MAが長期MA以上で、1本前の短期MAが長期MAより小さい場合には「デッドクロス」と判断して手仕舞いします。売りの場合は逆にします。(売りの場合の説明は省略)

「ゴールデンクロスで買いの手仕舞いをしたい」場合には売りと買いの条件を逆にして下さい。

他にも別のインジケーター(RSIなど)を併用するとか…クロスではなく単純に「短期MAが長期MAを下回ったら」という条件でも良さそうでです。

このあたりはご自身に合うよう作ってみてください。

カンマ文字列から配列に変換する関数

int SetStringToArrayList(int &list[])
{
   int beginIndex = 0;
   int endIndex = 0;
   int length = 0;
   int count = 0;
   int i = 0;
   for(i=0; i<10; i++)
   {
      endIndex = StringFind(MagicList,",",beginIndex);
      if(endIndex == -1)
      {
         length = StringLen(MagicList);
         list[i] = (int)StringSubstr(MagicList,beginIndex,length);
         break;
      }
      length = endIndex - beginIndex;
      list[i] = (int)StringSubstr(MagicList,beginIndex,length);
      beginIndex = endIndex + 1;
   }
   count = i + 1;
   return count;
}

実はAutoOrderModifyで作った関数をまるっと持ってきただけだったりします。

StringFind関数でカンマを探して、カンマより前に書いてある文字を抜き出して配列に格納。

最後だった場合(endIndex == -1)は残り全部を配列に入れています。

このあたりの記述は難しければ放置しても良いかと…。

この関数は、別のEAなどでも使い道は色々あると思います。

まとめ

チャートに設置するだけで、口座の全オーダーに対して機能しますので、裁量もEAも関係なく適用できます。

適用すると良くないEAがある場合には、適用したいEAや裁量のマジックナンバーをカンマ区切りで指定して下さい。

なお、「設置したチャートの通貨ペアや時間軸」は無関係です。適当なチャートに設置して下さい。

※ご利用の際はデモ口座などで良くご確認の上ご利用下さい。ざっと動作確認はしていますが動作保証はいたしかねます。

※不具合等ございましたら、コメント・メール等でご連絡下さい。

以上、「移動平均のクロスでクローズ(手仕舞い)するEA」の内容と解説でした。

  • このエントリーをはてなブックマークに追加
  • Pocket

コメント一覧

  1. furukawa より:

    お聞きしたい事があります。
    MT4標準インジのMAを、右へ表示移動させたものと、
    ノーマルMA(同一パラメーター)のクロスで、シグナルを出したいのですが、可能でしょうか?

    また、EA作成も可能でしょうか?

    furukawa

    • admin より:

      >MT4標準インジのMAを、右へ表示移動させたものと
      標準MAのパラメーター「表示移動(Shift)」で移動しませんか?

      >ノーマルMA(同一パラメーター)のクロスで、シグナルを出したいのですが、可能でしょうか?
      標準ではありません。検索すれば出てくるのでは‥?
      このあたりとか‥。
      http://mt4indicator.net/blog/archives/88

      EA作成のご依頼はお引き受けしておりません。
      「EA作成代行」等で検索するといろいろ出てくると思います。

この記事へのコメントはこちら

メールアドレスは公開されませんのでご安心ください。
また、* が付いている欄は必須項目となりますので、必ずご記入をお願いします。

内容に問題なければ、下記の「コメント送信」ボタンを押してください。