MQL5でエグジット後のバー数を返す関数

MQL5で直近のトレードがエグジットしてから経過したバー(ローソク足)の本数を返す関数を作った。

直近のトレードが勝ちのときはエグジットしてからX本後、負けのときはエグジットしてからY本後までエントリーしたくないときなどに使える。

この関数はEAが最後にエグジットした時間を起点としている。このため、トレーダーが手動でポジションを決済した場合、その時間は起点とはならず、あくまでもEAが最後にエグジットした時間が起点となったままである点に注意が必要だ。恐らく、EA自身がエグジットした場合しかエグジット時間が記録されないのだろう。

ポジションが存在するかいなかを返す関数を内部で使用しているので、この関数も併せて書く。

(補足)取引が存在するかいなかを返す関数も追加しておく。この関数は必要ないが、エグジット後のバー数を返す関数を直近のトレードがエグジットしてから一定のバー数を経過するまでエントリーしたくないときに使う場合は併用したほうがいい。例えばエグジットしてから10本以上経過しないとエントリーしないとする。これを売買ルールに入れると、1回もエントリーしないということが起きる。なぜなら最初のエントリーではその前のエグジットが存在しないため、エグジット後のバー数が0になるからだ。よって、少なくとも1回は取引が存在することは確認する必要がある。

なお、MQL5での取引とは入金、エントリー、エグジットのタイミングで発生する。例えば、バックテストをして10回トレードがあった場合、取引数は21回になる。最初の入金1回、エントリー10回、エグジット10回で計21回というわけだ。ここではトレードはエントリー1回、エグジット1回のセットという意味で使うことにする。したがって必ずしも「取引=トレード」ではない。

環境

  • OANDA MetaTrader 5: 5.00 build 4040
  • MetaEditor: 5.00 build 4040

エグジット後のバー数を返す関数

//+------------------------------------------------------------------+
//| 取引が存在するかいなか(2023/12/08動作確認)                               |
//+------------------------------------------------------------------+
bool isDealExist(int magic // マジックナンバー
                )
 {
  bool res=false; // 戻り値
  HistorySelect(0,TimeCurrent());
  for(int i=0;i<HistoryDealsTotal();i++)
    {
    ulong deal_ticket=HistoryDealGetTicket(i); // 取引のチケット
    string deal_symbol=HistoryDealGetString(deal_ticket,DEAL_SYMBOL); // 取引の銘柄
    ulong deal_magic=HistoryDealGetInteger(deal_ticket,DEAL_MAGIC); // 取引のマジックナンバー
    if(deal_symbol==Symbol() && deal_magic==magic)
      {
      res=true;
      break;
      }
    }
  return(res);
 }
//+------------------------------------------------------------------+
//| ポジションが存在するかいなか(2023/11/10動作確認)                            |
//+------------------------------------------------------------------+
bool isPositionExist(int magic // マジックナンバー
                    )
 {
  bool res=false; // 戻り値
  for(int i=0;i<PositionsTotal();i++)
    {
    string position_symbol=PositionGetSymbol(i); // ポジションの銘柄
    long position_magic=PositionGetInteger(POSITION_MAGIC); // ポジションのマジックナンバー
    if(position_symbol==Symbol() && position_magic==magic)
      {
      res=true;
      break;
      }
    }
  return(res);
 }
//+------------------------------------------------------------------+
//| エグジット後のバー数(2023/12/09動作確認)                                  |
//+------------------------------------------------------------------+
int BarsSinceExit(ENUM_TIMEFRAMES period, // 期間
                  int magic // マジックナンバー
                 )
 {
  HistorySelect(0,TimeCurrent());
  int res=0; // 戻り値
  //--- 新しい順に検索している点に注意。ここでは最新の取引のみ検索対称としている
  for(int i=HistoryDealsTotal()-1;i>=0;i--)
    {
    ulong deal_ticket=HistoryDealGetTicket(i); // 取引のチケット
    string deal_symbol=HistoryDealGetString(deal_ticket,DEAL_SYMBOL); // 取引の銘柄
    ulong deal_magic=HistoryDealGetInteger(deal_ticket,DEAL_MAGIC); // 取引のマジックナンバー
    ulong deal_entry=HistoryDealGetInteger(deal_ticket,DEAL_ENTRY); // 取引のエントリー
    datetime deal_time=(datetime)HistoryDealGetInteger(deal_ticket,DEAL_TIME); // 取引の時間
    if(deal_symbol==Symbol() && deal_magic==magic && deal_entry==DEAL_ENTRY_OUT)
      {
      res=iBarShift(NULL,period,deal_time,false);
      break;
      }
    }
  //---
  return(res);
 }

使用例

マジックナンバーが1であるとして、直近のトレードが勝ちの場合は日足で1本後にエントリー、負けの場合は日足で5本後にエントリーするという条件を加えたい場合、以下のようにする。

if((直近の取引の損益>0 && BarsSinceExit(PERIOD_D1,1)>=1) || (直近の取引の損益<0 && BarsSinceExit(PERIOD_D1,1)>=5 || isDealExist(1)==false) && 他のエントリー条件)
  新規注文;