
EA自作企画第5弾!準備がまだ!って人は先に準備しましょう!こっちのページを参照してね!
こちらのサイトのようなところへ行けば、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アイテム
過去検証や分析はMT4かFT4、Trading viewがおすすめです。
無料が良い人はMT4で、MT4を使わせてくれる口座を使用すると良いです。おすすめはFXTF
チャート分析に毎月課金してもいいよって人はTrading viewがおすすめです。無料もあります


