【FX自動売買】EA入門 確実に一定の利益を確保する関数を作る【MT4】

FX 自動売買(EA)

この記事は【EAの教科書シリーズ】の一部です。全記事は以下から確認できます。

MT4をまだダウンロードしていない方はこちらのページでダウンロード方法を案内しているので、事前にMT4を用意しておいてください。

今回作っていく関数の概要

今回作っていく関数の名前はBreakEven()とします。Break evenは収支がトントンになるといったような意味があります。この関数は実行中のトレードが一定の利益を出したら、あらかじめ指定した価格をストップロスに設定し、確実に利益を確保・または損失を出さないようにするために使います。

この関数は実行中のトレードがあるときにのみ、毎ティック実行されます。ですのでOnTick()関数の中でif文で実行中のトレードがあるかを確認し、ある場合にはBreakEven()関数を実行するようにします。

また今回はこの関数自体を使うかどうかを設定できるようにするためのbool値をグローバルエリアにextern(EA実行時に値を変更できる)で宣言しておきます。デフォルト値はtrueに設定します。

グローバルエリアには他にextern int型のMoveToBreakEven、extern int型のPipsProfitLockがあります。

MoveToBreakEvenはいくらのpip数分の利益が出ていれば損切りポイントを変更するかを指定します。

PipsProfitLockはいくらの利益を最低限確保したいかを指定するために使います。0である場合はトントンを意味し、20である場合は確実に20pipsの利益は確保できることを意味します。

つまり、MoveToBreakEvenが40でPipsProfitLockが20である場合、40pips以上の利益が出ている状態であれば、20pipsの利益は確保できるように損切りポイントを変更するということになります。即座に決済注文が出されるわけではないので、さらに含み益が伸びる可能性もありますし、好ましくない方向に市場価格が動いても確実に20pipsの利益は確保できます。

コードの確認

それでは実際にBreakEven()関数のコードを紹介していきます。

void BreakEven() //1
{
for(int i=OrdersTotal();i>0;i--) //2
   {
   if(OrderSelect(i-1,SELECT_BY_POS,MODE_TRADES)) //3
      {
      if(OrderType()==OP_BUY) //4
         {
         if(Bid-OrderOpenPrice()>MoveToBreakEven*pips) //5
            {
            if(OrderOpenPrice()>OrderStopLoss()) //6
               {
               bool res1=OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()+PipsProfitLock*pips,OrderTakeProfit(),0,clrNONE); //7
               Alert("Yes");
               }
            }
         }
      if(OrderType()==OP_SELL)
         {
         if(OrderOpenPrice()-Bid>MoveToBreakEven*pips)
            {
            if(OrderOpenPrice()<OrderStopLoss())
               {
               bool res1=OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()-PipsProfitLock*pips,OrderTakeProfit(),0,clrNONE);
               }
            }
         }
      }
   }
}

それではコメントにふった番号に沿って説明していきます。

  1. まずは関数の宣言です。戻り値はないのでvoidとし、名前はBreakEven()にします。
     
  2. 注文の総数分だけ繰り返すfor文です。
     
  3. OrderSelect()関数を使ってトレードプールの中から一つのトレードを選択しています。指定した番号のトレードが存在する場合にはtrueを返します。このfor文は注文分繰り返すので、繰り返されている間は必ずtrueを返すはずです。
     
  4. トレードが選択されたら、そのトレードが買い注文かをチェックしています。買い注文の場合はif文の中の処理に移ります。
     
  5. 現在の価格と注文時の価格の差分(pips)がMoveToBreakEvenに設定した値より大きいかをチェックしています。たとえばMoveToBreakEven変数の値を40にしていた場合、この変数自体は単位がpipsになっていないので、pips変数とかけて単位がpipsになるように変換しています。pipsが0.0001だった場合、0.0040になります。そして差分が0.0040より大きいということは、現在の市場価格が自分にとって良い方に40pips以上動いたということになります。この場合は買い注文ですので、40pips以上価格が上がったということです。売り注文の場合は逆になります。そして次の処理に移ります。
    40pips以上動いていない場合はif文の中身を飛ばして次の処理に移ります。

pips変数については以前の記事で解説しているので、詳しく知りたい方は以下の記事を御覧ください。

  1. このif文は損切り値(Stoploss)がこの関数によって既に動かされていないかをチェックしています。初回は必ずtrueを返すはずなので、if文の中の処理に移ります。そうでない場合は次の売り注文かをチェックするif文に飛ばされます。
     
  2. OrderModify()関数を使って注文内容を変更します。今回変更したいのは損切りポイントです。それ以外は特に変更しません。
    ここでは買い注文なので、利益を確保したい分のpipsをOrderOpenPrice()に足します。再度確認しておきますが、PipsProfitLock変数自体はint値なので、pips変数を使ってpipsを表す値に変換しています。
     
  3. これと同様の処理を売り注文の場合にも行います。ただし売り注文の場合は約定価格から現在の買い価格(Ask)を引いた値がMoveToBreakEvenより大きければ、現時点で一定の利益が出ているということになる点に注意してください。

グローバル変数の確認

extern int TakeProfit=50;
extern int StopLoss=25;
extern double LotSize=0.01;
extern bool UseBreakEven=true;
extern int MoveToBreakEven=40;
extern int PipsProfitLock=20;
double pips;

上のコードは宣言している全てのグローバル変数になります。pips変数には何も値が代入されていませんが、事前に定義したPipsFunction()によって適切な値がプログラム実行時に代入されるので、問題ありません。

以前の記事ではStopLossやTakeProfitには0.0050や0.0025のような値が入っていましたが、これもpips変数を使って適切な値に変換できるので、整数値に変更しています。

また以前作成したNewOrder()関数内でもNomalizeDouble()関数を使ってすべてを小数点以下4桁に変換しています。NewOrder()関数については以下の記事を御覧ください。


最後にコード全体を載せておきます。

//+------------------------------------------------------------------+
//|                                                         test.mq4 |
//|                                                         Kanrinin |
//|                                           https://codelabsjp.net |
//+------------------------------------------------------------------+
#property copyright "Kanrinin"
#property link      "https://codelabsjp.net"
#property version   "1.00"
#property strict

extern int TakeProfit=50;
extern int StopLoss=25;
extern double LotSize=0.01;
extern bool UseBreakEven=true;
extern int MoveToBreakEven=40;
extern int PipsProfitLock=20;
double pips;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   PipsFunction();
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
if(IsNewCandle()){
   if(TotalOpenOrders()<1){
      NewOrder();
   }
   
   if(TotalOpenOrders()>0){
      if(UseBreakEven){    //BreakEvenを使うかのチェック
         BreakEven();
      }
   }
}
   
  }
//+------------------------------------------------------------------+
void NewOrder()
{

int Result=OrderSend(Symbol(),OP_BUY,LotSize,Ask,3,NormalizeDouble(Ask-StopLoss*pips,4),NormalizeDouble(Ask+TakeProfit*pips,4),NULL,0123,0,clrNONE);
return;
}

bool IsNewCandle()
{
   static int BarsOnChart=0;
   if(Bars==BarsOnChart){
      BarsOnChart = Bars;
      return(false);
   }
   BarsOnChart = Bars;
   return(true);
}

int TotalOpenOrders()
{
int Orders=0;
int Total=OrdersTotal();
   for(int i=Total; i>0; i--)
      {
      bool res=OrderSelect(i-1,SELECT_BY_POS,MODE_TRADES);
      if(OrderType()==OP_BUY || OrderType()==OP_SELL)
         {
         Orders++;
         }
      }
   return(Orders);
}

void CloseAllOrders()   //1
{
int Total=OrdersTotal();   //2
   for(int i=Total;i>0;i--)   //3
      {
      if(OrderSelect(i-1,SELECT_BY_POS,MODE_TRADES))  //4
         {
         if(OrderType()==OP_SELL)   //5
            {
            bool res1=OrderClose(OrderTicket(),OrderLots(),Ask,3,clrNONE); //6
            }
         if(OrderType()==OP_BUY) //7
            {
            bool res2=OrderClose(OrderTicket(),OrderLots(),Bid,3,clrNONE); //8
            }
         if(OrderType()==OP_BUYLIMIT || OrderType()==OP_BUYSTOP || OrderType()==OP_SELLLIMIT || OrderType()==OP_SELLSTOP)  //9
            {
            bool res3=OrderDelete(OrderTicket(),clrNONE);   //10
            }
         }
      }
return;
}

void PipsFunction() //1
{
double ticksize=MarketInfo(Symbol(),MODE_TICKSIZE); //2
   if(ticksize == 0.00001) //3
   {
   pips = ticksize*10; //4
   }
   else
   {
   pips = ticksize; //5
   }
return;
}

void BreakEven() //1
{
for(int i=OrdersTotal();i>0;i--) //2
   {
   if(OrderSelect(i-1,SELECT_BY_POS,MODE_TRADES)) //3
      {
      if(OrderType()==OP_BUY) //4
         {
         if(Bid-OrderOpenPrice()>MoveToBreakEven*pips) //5
            {
            if(OrderOpenPrice()>OrderStopLoss()) //6
               {
               bool res1=OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()+PipsProfitLock*pips,OrderTakeProfit(),0,clrNONE); //7
               Alert("Yes");
               }
            }
         }
      if(OrderType()==OP_SELL)
         {
         if(OrderOpenPrice()-Ask>MoveToBreakEven*pips)
            {
            if(OrderOpenPrice()<OrderStopLoss())
               {
               bool res1=OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()-PipsProfitLock*pips,OrderTakeProfit(),0,clrNONE);
               }
            }
         }
      }
   }
}
      

完全無料で通えるプログラミングスクール

プログラミング学習はどうしても一人だとつまづいてしまう時がきます。調べればわかることも少なくないですが、最初のうちは調べ方もわからないことが多いため、あまり効率的ではありません。

効率的かつ挫折せずにプログラミングを学習したい方はスクールを検討してみるのも一つの手です。

中には無料で通えるスクールや、就職保証をしてくれるスクールなどもあるので、きっとあなたの目的に応じて最適のスクールが見つかります!以下の記事で評判がよく特におすすめのスクールをいくつかピックアップしているので、スクール選びで後悔したくない方は御覧ください!

プロフィール

プロフィール
コードラボJP

大学卒業後SEに就職、現在は退職しフリーランスとして活動中。
『初心者でも挫折せずに一人でプログラミングを学べる』をモットーに、コードラボJPを開設
お問い合わせ等はcodelabsjp@gmail.comまで

コードラボJPをフォローする
タイトルとURLをコピーしました