EA自作企画第5弾!準備がまだ!って人は先に準備しましょう!こっちのページを参照してね!

こちらのサイトのようなところへ行けば、EA自体は購入が可能です。

投資家の祭典 GogoJungle AWARD 2023

前回はロットサイズを計算する関数を準備して、それを画面に表示させました。今回は無駄なエントリーを減らすために、自分が持っているポジションからエントリーしてよいかどうかを判定します!

目標とするEAに近づけたい…

自作EAの条件

損切しない!

スワップが増える方向にだけエントリー

似たようなところでエントリーしない!

最大ポジション数を取った時にレバレッジ10倍を超えない!

今回は似たようなところでエントリーしない!をやってみます!前回、externでzoneってのを50に設定していました。アレが意味するところは自分が今持っているポジションに対して、エントリーしたところの周り50Pipsではエントリーしないようにしたいという思いで書いてます。ただ、通貨ペアによっては50pips動くのに何日もかかるようなものもあれば、毎日のように動くものもあるので、自分で設定できるようにしています。

#property copyright "Copyright 2025, FPshima"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

extern bool LongOn = true;//ロングを許可
extern bool ShortOn = false;//ショートを許可

extern int zone = 50;//エントリー不可範囲
extern int maxPosition = 4;//最大ポジション数
extern double risk = 10;//取りうる最大リスク

double calculateLotSize()
{
   double accountBalance = AccountBalance();
   double totalRiskAmount = accountBalance * risk/100;
   double eachPositionRisk = totalRiskAmount/maxPosition;
   double minLot = MarketInfo(NULL,MODE_MINLOT);
   double marginRequire = MarketInfo(NULL,MODE_MARGINREQUIRED)*minLot;
   double lotSize = (eachPositionRisk / marginRequire)*minLot;
   if(lotSize <= minLot)
   {
      lotSize = minLot;
   }
   if(lotSize <= 20.0)
   {
     lotSize = NormalizeDouble(lotSize,2);
   }
   if(lotSize > 20.0)
   {
      lotSize = 20.0;
   }
   return lotSize;
}

bool EntryJudge(int tradeType)// 自作関数を設定 引数に整数型をいれて答えはboolが返す
{
   double zonePips = zone *Point*10;//Pointはその通貨ペアの最小単位一般に0.1Pips
   int currentPositions = 0;//最大ポジション数を超えないようにポジションを数える元
   
   for(int i = 0 ; i < OrdersTotal(); i++)//iを整数として、OrdersTotal()未満でループ
   {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))//i番目のポジションを選択
      {
         currentPositions++;//ポジションがあったらポジション数を増加
         if(OrderType() == tradeType && MathAbs(OrderOpenPrice()-Ask) <= zonePips && OrderType() == OP_BUY)
         {
            return false;// if()内の条件に合ってたらfalseを返す
         }
         
         if(OrderType() == tradeType && MathAbs(OrderOpenPrice()-Bid) <= zonePips && OrderType() == OP_SELL)
         {
            return false;//Sellバージョン
         }
      }
   }
   if(currentPositions < maxPosition)//for文が終わった後のポジション数がMaxposition以下なら
   {
      return true;//trueを返す
   }else{
   
      return false;//違ったらfalseを返す
   }
}
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---

   double tradeLot = calculateLotSize();
   Comment("lotSize",tradeLot,"  Zonejudge  " , EntryJudge(OP_BUY));//EntryJudgeがtrueかfalseか表示
   if(EntryJudge(OP_BUY))
   {
     OrderSend(NULL,OP_BUY,tradeLot,Ask,5,0,0,"Long",0,0,clrRed);//EntryJudgeがtrueならLong
   }
   
  }
//+------------------------------------------------------------------+

さて、今回はエントリー判断をポジション数と、ゾーンにいるかどうかだけで判断しています。

具体的に見ていきましょう



bool EntryJudge(int tradeType) // 自作関数を設定 引数に整数型をいれて答えはboolが返す
{
   double zonePips = zone *Point*10; //Pointはその通貨ペアの最小単位一般に0.1Pips
   int currentPositions = 0; //最大ポジション数を超えないようにポジションを数える元
   
   for(int i = 0 ; i < OrdersTotal(); i++) //iを整数として、OrdersTotal()未満でループ
   {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) //i番目のポジションを選択
      {
         currentPositions++;//ポジションがあったらポジション数を増加
         if(OrderType() == tradeType && MathAbs(OrderOpenPrice()-Ask) <= zonePips && OrderType() == OP_BUY)
         {
            return false;// if()内の条件に合ってたらfalseを返す
         }
         
         if(OrderType() == tradeType && MathAbs(OrderOpenPrice()-Bid) <= zonePips && OrderType() == OP_SELL)
         {
            return false;//Sellバージョン
         }
      }
   }
   if(currentPositions < maxPosition)//for文が終わった後のポジション数がMaxposition以下なら
   {
      return true;//trueを返す
   }else{
   
      return false;//違ったらfalseを返す
   }
}

boolでEntryJudge()という関数を定義しました。この際、()にint tradeTypeとしたので、整数を引数として取る必要があります。boolで宣言したので、returnはtrueかfalseですね。

ローカル変数としてzonePipsをdoubleで宣言。externで設定できるzoneに、MQL変数のPointを使用。Pointはその通貨ペアの最小単位を返します。通常0.1Pipsなので10倍してPipsに変換しました。したがって、zoneで設定したpipsがどの程度の値動きか判定されます。

currentPositionを整数intで宣言しました。ポジション数は少数を取ったりしないので、整数でOK。この後のfor文で数を数えたいので、初期化として0を格納。

for文です、整数でiを宣言し、OrdersTotal()でポジションの数を取得。この数になるまでiを増やしていきます。(OrdersTotal()だけでもポジション数を知ることが出来ますが、Long、Shortを分けられません)

OrdersSelect()は現在のポジションのi番目を決定します。この際気を付けたいのは、1つ目のポジションは0番であることです。なので、iが0から始まっています。なおポジション0の時はOrdersTotal()が0なので動きません。で、ポジションがあったらcurrentPositionを++ このプラスプラスは1足すという事。+=1と書いたり、currentPosition=currentPositon+1とか書いたりもします。

if()内で条件判定

OrderType() == tradeType 「==」は同じときという意味で、OrderType()はMQL関数でどんなトレードか(OP_BUYなど)を返します。また、tradeTypeはこの関数の引数です。ここでは、tradeTypeがOP_BUYかOP_SELLが入ることを想定しています。

&& MathAbs(OrderOpenPrice()-Ask) <= zonePips  「&&」は他の条件とand条件で繋げています。MathAbs()はカッコ内の絶対値を返します。ここではOrderOpenPrice()でi番目のポジションをとった価格を調べ、現在のロング時の価格であるAskと比較し、差の絶対値がzonePips内にあるかどうかを確認しています。

&& OrderType() == OP_BUY) 最後にこのトレードタイプがOP_BUYかどうかを確認しています。

すぐ下のif文は、上述の論理式のSELLバージョンです。

  if(currentPositions < maxPosition)//for文が終わった後のポジション数がMaxposition以下なら
   {
      return true;//trueを返す
   }else{
   
      return false;//違ったらfalseを返す
   }

ここでは、さっき数えたcurrentPositionsがextern設定したmaxPositionより小さいかを調べています。小さくなかったらfalseが返ってきます。

OnTickの中も見てみましょう

void OnTick()
  {
//---

   double tradeLot = calculateLotSize();
   Comment("lotSize",tradeLot,"  Zonejudge  " , EntryJudge(OP_BUY));//EntryJudgeがtrueかfalseか表示
   if(EntryJudge(OP_BUY))
   {
     OrderSend(NULL,OP_BUY,tradeLot,Ask,5,0,0,"Long",0,0,clrRed);//EntryJudgeがtrueならLong
   }
   
  }
//+------------------------------------------------------------------+

コメントに直接EntryJudge()関数の引数OP_BUYを設定しています。また、if文でEntryJudgeがtrueだったら(trueの時は==で書かなくても良い。もちろん==trueとしても良い)OrderSend()関数でOP_BUYしています。OrderSend()関数の引数は(通貨ペア、売買の方法、エントリー価格、スリッページ、損切、利確、”コメント”、マジックナンバー、有効期間、色)となっています。

2ポジション持っていて、1つ目と2つ目のポジションの間隔があいていますね!で、今の値はzone内にいるのでfalseでトレードできません!

MAXPOSITONの4つとったので、この後はず~っとfalseでエントリーされません!

これで、ポジションをとるコードはかけましたね!次はLongOnとの対応を見ていきます!

楽天証券(FX)

おすすめFXアイテム

過去検証や分析はMT4かFT4、Trading viewがおすすめです。

無料が良い人はMT4で、MT4を使わせてくれる口座を使用すると良いです。おすすめはFXTF

ガチで過去検証をやりたい人はFT4、

チャート分析に毎月課金してもいいよって人はTrading viewがおすすめです。無料もあります

Twitterでフォローしよう

おすすめの記事