【超入門】MQL5 EA講座 第100回「ブレイクイーブンストップ関数を作る」

MQL5でEA作ろう講座

——————

前回は、ブレイクイーブンストップの概要について解説しました。

改めて前回の内容をおさらいすると、

ブレイクイーブンストップトレーリングストップと同様に、相場の変化に応じてストップロスを移動させる概念です。

ただ、トレーリングストップと違い、ブレイクイーブンストップストップロスを移動させる回数は1回のみです。

ブレイクイーブンストップを実装できるようになると、仮にテイクプロフィットに到達する前に相場が逆行しても、ほぼプラマイゼロでその取引を終えることができますし、逆に利益方向に価格が伸びていった時に、一時的な相場の揺り戻しにポジションが絡めとられずに、大きな利益を確定させることができる可能性が高まります。

EA開発をするにあたっての、手札の1つとして持っておくことには大きな意味があるでしょう。

前回はそのブレイクイーブンストップを実装するサンプルコードを紹介したわけですが、今回は、ブレイクイーブンストップを簡単に設定する為の関数を作っていきたいと思います。

スポンサーリンク
スポンサーリンク

ブレイクイーブンストップ関数実装へのロードマップ

ブレイクイーブンストップ関数を導入する為には、以下の手順を踏んで実現させます。

OriginalTrailingStop.mqhファイル内にある、OriginalCTrailingクラスの中でブレイクイーブンストップ関数を宣言する。

BreakEven関数引数を設定する

ブレイクイーブンストップ関数の処理実装記述を行う。

一つ一つ順を追って見ていきましょう

OriginalTrailingStop.mqhファイル内にある、OriginalCTrailingクラスの中でブレイクイーブンストップ関数を宣言する。

まずはOriginalTrailingStop.mqhファイルにブレイクイーブンストップ関数を宣言します。

OriginalTrailingStop.mqhファイルは第96回「トレーリングストップクラスを作る1」で作った、トレーリングストップ処理に必要なクラス関数を集約することを目的としたインクルードファイルです。

ブレイクイーブンストップ関数の宣言は、ファイル内に作ったOriginalCTrailingクラスpublicセクション内に行います。

public:
		MqlTradeResult result;
		bool TrailingStop(ulong parTicket, int parTrailPoints, int parMinProfit = 0, int parStep = 10);
		bool TrailingStop(ulong parTicket, double parTrailPrice, int parMinProfit = 0, int parStep = 10);
		//ブレイクイーブンストップ関数の宣言
		bool BreakEven(ulong parTicket, int parBreakEven, int parLockProfit=0);

関数名を「BreakEven」としました。

ブレイクイーブンストップ処理が正常に行われた場合にはtrue,正常に行われなかった場合にはfalseを返す設計にするので、戻り値bool型とします。

BreakEven関数の仮引数を設定する

BreakEven関数引数は以下の通りです。

ulong型の第1仮引数「 parTicket」

ulong型の第1引数「parTicket」にはポジション番号が記述される想定です。

int型の第2仮引数「 parBreakEven」

int型の第2引数parBreakEven」はブレイクイーブンストップを発動させる損益ポイントを設定するのに使います。input変数で設定した値が記述される想定です。

ブレイクイーブンストップを発動させる損益ポイントについては、前回99回の、

int型のinput変数「BreakEven」セクション

をご覧ください。

int型の第3仮引数「 parLockProfit」

int型の第3引数「 parLockProfit」は約定値に追加するポイントを設定するのに使います。

これもinput変数で設定した値が記述される想定です。

約定値に追加するポイントについての詳細は、これも前回第99回の、

int型のinput変数「LockProfit」セクション

をご覧ください。

初期値は0と設定しておきます。ここが0の場合、ブレイクイーブンストップ発動時に移動するストップロス価格は約定価格と同じ値になります。

ブレイクイーブンストップ関数の処理実装記述を行う。

宣言が終わったので、続いてブレイクイーブンストップ関数の処理実装記述に移ります。

処理実装記述の場所は、OriginalTrailingStop.mqhファイル内であればどこでも良いのですが、今回は、TrailingStop関数書式2の下に処理実装記述を行います。

bool OriginalCTrailing::BreakEven(ulong parTicket, int parBreakEven, int parLockProfit=0)
{

}

BreakEven関数OriginalCTrailingクラス所属の関数であるという記述をしたうえで、{}内に処理実装記述を行います。

クラス所属の関数である事を記述する方法についての詳細は、

MQL5 EA講座 第49回「クラスについて2 -クラスの使い方-」

をご覧ください。

具体的な実装記述の解説に移ります。

ポジション選択を確認する。

最初にポジション選択が正常に行われているかどうかを確認します。

bool OriginalCTrailing::BreakEven(ulong parTicket, int parBreakEven, int parLockProfit=0)
{

//ポジション選択が正しく行われ、parBreakEvenが0より大きければ
	if(PositionSelectByTicket(parTicket) == true && parBreakEven > 0)
	{ 

  }
  else return(false);//ポジションが選択席なければfalseを返して終了
}

if文()内の最初の条件文、

PositionSelectByTicket(parTicket) == true

はポジションが正常に選択された事を意味しています。引数「parTicket」には、メインプログラムで利用する際には、ポジション番号が記述される想定です。

論理積 &&で繋いだ二つ目の条件文

parBreakEven > 0

は、前回99回の時に、「ブレイクイーブンストップ発動に必要な条件文を記述する」セクションで解説した内容とほぼ同じです。

引数である「parBreakEven 」はブレイクイーブンストップを発動させる損益ポイント、即ち「ポジションがどれくらいの利益が出たらブレイクイーブンストップを発動させるか?」が設定される想定になっており、メインプログラムではinput変数にてパラメータ化した値が入ります。

この値が0の場合は、ブレイクイーブンストップ発動させる為の、利益ポイントが設定されていないという事になります。

※このif文()内の条件がfalseの時は、ポジション選択が正常に行われなかったか、ブレイクイーブンストップを発動させる正常な値設定がされていないので、returnでfalseを返して終了します。

続いては

if(PositionSelectByTicket(parTicket) == true && parBreakEven > 0)

の条件文がtrueだった場合の記述を{}内に行っていきます。

ブレイクイーブンストップに必要な値を取得する

ポジションが正常に選択出来たら、ブレイクイーブンストップに必要な値を取得し、必要に応じてクラスメンバ変数ローカル変数代入を行っていきます。

		request.action = TRADE_ACTION_SLTP;//.actionへの設定
		request.position = parTicket;//.positionへの設定
		
		long posType = PositionGetInteger(POSITION_TYPE);//ポジションタイプの取得
		double currentSL = PositionGetDouble(POSITION_SL);//ストップロス値の取得
		double currentLimit = PositionGetDouble(POSITION_TP);//テイクプロフィット値の取得
		
		double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);//約定価格の取得
		string symbol = PositionGetString(POSITION_SYMBOL);//ポジション銘柄情報の取得
		
		double point = SymbolInfoDouble(symbol,SYMBOL_POINT);//ポイント情報の取得
		int digits = (int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);//ポジション銘柄の桁数情報取得
		
		
		double breakEvenStop;//ブレイクイーブン発動価格を格納する変数
		double currentProfit;//ポジションの損益情報を格納する変数

MqlTradeRequest構造体メンバ変数.actionには、ストップロス変更を行う「TRADE_ACTION_SLTP」を代入します。

メンバ変数 .positionにはポジション番号代入します。ここでは、メインプログラムでポジション番号情報を格納する想定である引数「parTicket」を記述します。

long型ローカル変数「posType」にはポジションタイプを格納します。

ポジションタイプ情報はPositionGetInteger関数引数定数POSITION_TYPE」を記述して取得します。

double型ローカル変数「currentSL」には現在のストップロス値を格納します。

現在のストップロス値はPositionGetDouble関数引数定数POSITION_SL」を記述して取得します。

double型ローカル変数「 currentLimit 」には現在のテイクプロフィット値を格納します。

現在のテイクプロフィット値は、PositionGetDouble関数引数定数POSITION_TP」を記述して取得します。

double型ローカル変数「openPrice」にはポジションの約定価格を格納します。

ポジションの約定価格はPositionGetDouble関数引数定数POSITION_PRICE_OPEN」を記述して取得します。

string型ローカル変数「symbol」 にはポジション銘柄情報を格納します。ポジション銘柄情報は PositionGetString関数引数定数POSITION_SYMBOL」を記述して取得します。

double型ローカル変数「point」 にはポイント情報を格納します。ポイント情報は SymbolInfoDouble関数の第2引数定数「SYMBOL_POINT」を記述して取得します。

int型ローカル変数「digits」には ポジション銘柄の桁数情報が格納されます。ポジション銘柄の桁数情報はSymbolInfoInteger関数の第2引数定数SYMBOL_DIGITS」を記述して取得します。

SymbolInfoInteger関数の前についている、

(int)

という記述は型変換(キャスト)と呼ばれるものです。型変換(キャスト)については下記をご覧ください。↓

double型ローカル変数「breakEvenStop」は、ブレイクイーブンストップ発動価格を格納する変数です。この値は買いポジションと売りポジションで、算出する値が異なるので、具体的な値はこの後のdo-while文中の発注回路にて行います。

double型ローカル変数「currentProfit」は、ポジションの損益情報を格納する変数です。この値も買いポジションと売りポジションで、算出する値が異なるので、具体的な値はこの後のdo-while文中の発注回路にて行います。

リトライ回数とリターンコードを格納する変数を宣言する

注文のリトライ回数とリターンコードを格納する変数を宣言します

第72回第76回第85回第86回第96回でも同じ記述が出てきますのでご参照ください。

	// リトライ回数とリターンコードを格納する変数を宣言する
		int retryCount = 0;
		int checkRes = 0;
		
		//Bid値、Ask値格納変数の初期化
		double bid = 0, ask = 0;

変数「retryCount」は、注文を出して注文エラーが発生した時、エラー内容次第では再注文すればエラーが解消する可能性があるので、指定回数はエラーが出たときに再注文を出す回路を組み込む為に使います。

変数「checkRes」は、注文後、MqlTradeResult構造体インスタンス「result」が受け取るリターンコードを格納するためのものです。注文が成功したのか?、失敗したのならばその理由は何か? を確認する為に使います。

double型ローカル変数「bid」と 「ask」は 現在値Bid値とAsk値を格納します。

変数「bid」と 「ask」ですが、買いポジション、売りポジションそれぞれの損益情報を算出するのに使います。

do-while文の中に発注回路を組み込んでいく

発注回路はdo-while文の中に記述していきます。PositionOpen関数SetSLTP関数ClosePosition関数PendingOpen関数TrailingStop関数等でも共通して使われている回路です。

do-while構文については、→第39回「do-while文について」の記事をご覧ください。

do 
		{  //ポジションタイプが「買い」の場合
			if(posType == POSITION_TYPE_BUY)
			{
				bid = SymbolInfoDouble(symbol,SYMBOL_BID);
				breakEvenStop = openPrice + (parLockProfit* point);//ブレイクイーブン発動価格を変数に格納
				currentProfit = bid - openPrice;//ポジション損益情報を変数に格納
				
				//正規化
				breakEvenStop = NormalizeDouble(breakEvenStop, digits);
				currentProfit = NormalizeDouble(currentProfit, digits);
				
				if(currentSL < breakEvenStop && currentProfit >= parBreakEven * point) 
				{//現在のSL値が約定価格+指定値より小さい、かつポジション損益が指定値より大きい
				
				
				
					request.sl = breakEvenStop;
					request.tp= currentLimit;
					bool sent = OrderSend(request,result);
				}
				else return(false);
			}
			//ポジションタイプが売りの場合
			else if(posType == POSITION_TYPE_SELL)
			{
				ask = SymbolInfoDouble(symbol,SYMBOL_ASK);
				breakEvenStop = openPrice - (parLockProfit * point);//ブレイクイーブン発動価格を変数に格納
				currentProfit = openPrice - ask;//ポジション損益情報を変数に格納
				
				//正規化
				breakEvenStop = NormalizeDouble(breakEvenStop, digits);
				currentProfit = NormalizeDouble(currentProfit, digits);
				
				if((currentSL > breakEvenStop || currentSL == 0) && currentProfit >= parBreakEven * point)
				{//<現在のSL値が約定価格-指定値より大きい、または現在のSL値が0のとき>、かつポジション損益が指定値より大きい
					request.sl = breakEvenStop;
					request.tp= currentLimit;
					bool sent = OrderSend(request,result);
				}
				else return(false);
			}
			
			//リターンコードの確認
			checkRes = ReturnCodeCheck(result.retcode);
		   
		   //正常に注文が行われていればループを抜ける
			if(checkRes == CHECK_RETCODE_OK) break;
			else if(checkRes == CHECK_RETCODE_ERROR)
			{  //エラー情報の格納
				string errDesc = TradeServerReturnCodeDescription(result.retcode);
				Alert("ブレイクイーブン注文エラー: エラー内容 ",result.retcode," - ",errDesc);
				break;
			}
			//再注文により、エラーが解消される可能性がある倍
			else
			{
				Print("サーバーエラーを検知, 再試行中...");
				Sleep(RETRY_MILLISECONDS);
				retryCount++;
			}
		}
		while(retryCount < RETRY_LIMIT);

do-while文の中を見ていきましょう。まずはポジションが買いの場合です。

ブレイクイーブンストップの注文を出す(買いの場合)

ポジションタイプが「買い」の場合の条件文は

if(posType ==POSITION_TYPE_BUY)

になります。

//ポジションタイプが「買い」の場合
			if(posType == POSITION_TYPE_BUY)
			{
				bid = SymbolInfoDouble(symbol,SYMBOL_BID);
				breakEvenStop = openPrice + (parLockProfit* point);//ブレイクイーブン発動価格を変数に格納
				currentProfit = bid - openPrice;//ポジション損益情報を変数に格納
		

変数「bid」には現在値であるBid値を格納します。Bid値の取得にはSymbolInfoDouble関数の第2引数定数「SYMBOL_BID」を記述して実現します。

変数「breakEvenStop」には、ブレイクイーブンストップ発動価格を代入します。買いポジションにおけるブレイクイーブンストップ発動価格は、

約定価格+任意に設定した値という事になるので、

openPrice + (parLockProfit* point)

という記述で実現します。

変数「openPrice 」には約定価格が記述され、引数「parLockProfit」にはinput変数などで設定した値が入る想定になっています。

変数「currentProfit」にはポジション損益情報が格納されます。

ポジション損益情報は bid(現在値) – openPrice(約定価格)の計算式を代入します。

//正規化
				breakEvenStop = NormalizeDouble(breakEvenStop, digits);
				currentProfit = NormalizeDouble(currentProfit, digits);

続いて、変数「breakEvenStop」「currentProfit」をそれぞれ正規化します。

正規化というのは、プログラムが取り扱うルールに則って値を整える作業

のことを言います。正規化にはNormalizeDouble関数を用います。

NormalizeDouble関数についての詳細は↓の記事をご覧ください。

ブレイクイーブンストップの発注をOrderSend関数で出すためのif文を記述していきます。↓

	if(currentSL < breakEvenStop && currentProfit >= parBreakEven * point) 
				{//現在のSL値が約定価格+指定値より小さい、かつポジション損益が指定値より大きい
					request.sl = breakEvenStop;
					request.tp= currentLimit;
					bool sent = OrderSend(request,result);
				}
				else return(false);

if(currentSL < breakEvenStop && currentProfit >= parBreakEven * point)

現在のSL値が約定価格+指定値より小さい、かつポジション損益が指定値より大きい

と読み解く事ができます。

この条件文の理屈については前回99回の、

「if(posType==POSITION_TYPE_BUY)の中2:ブレイクイーブンストップを発動させる条件文を記述する」セクション

で解説しているので詳しくはそちらをご参照ください。

メンバ変数.sl に変数「breakEvenPrice」を、

メンバ変数 .tp変数「currentLimit」を

それぞれ代入をした上で、OrderSend関数引数MqlTradeRequest構造体インスタンス「request」、MqlTradeResult構造体インスタンス「result」を記述して終了です。

以上が買いポジションの場合でした。

ブレイクイーブンストップの注文を出す(売りの場合)

続いては売りポジションの場合です。

//ポジションタイプが売りの場合
			else if(posType == POSITION_TYPE_SELL)
			{
				ask = SymbolInfoDouble(symbol,SYMBOL_ASK);
				breakEvenStop = openPrice - (parLockProfit * point);//ブレイクイーブン発動価格を変数に格納
				currentProfit = openPrice - ask;//ポジション損益情報を変数に格納

変数「ask」には現在値であるAsk値を格納します。Ask値の取得にはSymbolInfoDouble関数の第2引数定数「SYMBOL_ASK」を記述して実現します。

変数「breakEvenStop」には、ブレイクイーブンストップ発動価格を代入します。売りポジションにおけるブレイクイーブンストップ発動価格は、

約定価格 – 任意に設定した値という事になるので、

openPrice – (parLockProfit* point)

という記述で実現します。

変数「openPrice 」には約定価格が記述され、引数「parLockProfit」にはinput変数などで設定した値が入る想定になっています。

変数「currentProfit」にはポジション損益情報が格納されます。

ポジション損益情報は openPrice(約定価格)- Ask(現在値) の計算式を代入します。

//正規化
				breakEvenStop = NormalizeDouble(breakEvenStop, digits);
				currentProfit = NormalizeDouble(currentProfit, digits);

続いてNormalizeDouble関数を使い、変数「breakEvenStop」「currentProfit」をそれぞれ正規化します。

次は、ブレイクイーブンストップの発注をOrderSend関数で出すためのif文を記述していきます。↓

if((currentSL > breakEvenStop || currentSL == 0) && currentProfit >= parBreakEven * point)
				{//<現在のSL値が約定価格-指定値より大きい、または現在のSL値が0のとき>、かつポジション損益が指定値より大きい
					request.sl = breakEvenStop;
					request.tp= currentLimit;
					bool sent = OrderSend(request,result);
				}
				else return(false);
			}
			

if((currentSL > breakEvenStop || currentSL == 0) && currentProfit >= parBreakEven * point)

<現在のSL値が約定価格-指定値より大きい、または現在のSL値が0のとき>、かつポジション損益が指定値より大きい時

と読み解く事ができます。

買いポジションの条件文の時に比べて、論理和 ||で繋いだ、

currentSL == 0

という記述が加わっています。

これは、変数「currentSL」の値がゼロ、即ち最初のストップロス価格が設定されていない場合、いつまで経ってもcurrentSL > breakEvenStop という条件を満たさず、ブレイクイーブンストップが発動しないので、それに備えた記述です。

メンバ変数.sl に変数「breakEvenPrice」を、

メンバ変数 .tp変数「currentLimit」を

それぞれ代入をした上で、OrderSend関数引数MqlTradeRequest構造体インスタンス「request」、MqlTradeResult構造体インスタンス「result」を記述して終了です。

ここの部分は買いポジションの時と変わりません。以上で売りの発注記述は終了です。

注文成功・失敗・再試行の条件分岐を行う

買いと売りそれぞれの発注記述が終わったので、その注文結果に応じた条件分岐の記述を行います。

//リターンコードの確認
			checkRes = ReturnCodeCheck(result.retcode);
		   
		   //正常に注文が行われていればループを抜ける
			if(checkRes == CHECK_RETCODE_OK) break;
      //エラーの場合
			else if(checkRes == CHECK_RETCODE_ERROR)
			{  //エラー情報の格納
				string errDesc = TradeServerReturnCodeDescription(result.retcode);
				Alert("ブレイクイーブン注文エラー: エラー内容 ",result.retcode," - ",errDesc);
				break;
			}
			//再注文により、エラーが解消される可能性がある場合
			else
			{
				Print("サーバーエラーを検知, 再試行中...");
				Sleep(RETRY_MILLISECONDS);
				retryCount++;
			}
		}
		while(retryCount < RETRY_LIMIT);

OrderSend関数での発注結果を、ReturnCodeCheck関数で確認し次の行動を規定します。発注結果は

「発注が成功した場合」

2「再試行しても解決しないエラーの場合」

3「再試行すれば解決する可能性のあるエラーの場合」というの3つの場合を想定し、

if文 else文で条件分岐させ処理を切り分けていきます

<参考リンク>

再注文試行が上限回数に達した場合の記述

do-while構文の中の記述が終わったので、次は再注文試行が上限回数に達した場合の記述に移ります。

//再試行の上限に達した場合
		if(retryCount >= RETRY_LIMIT)
		{
			string errDesc = TradeServerReturnCodeDescription(result.retcode);
			Alert("再試行の上限に達しました: エラー内容 ",result.retcode," - ",errDesc);
		}

if(retryCount >= RETRY_LIMIT)

という記述は↑決済注文の試行回数が#define命令で設定した定数RETRY_LIMIT」の数を上回っている事を意味します。

TradeServerReturnCodeDescription関数リターンコードを獲得後、変数「errDesc」に格納→Alert関数変数に格納された内容を発出します。

ブレイクイーブンストップ注文の結果をPrint関数でログ出力する

ブレイクイーブンストップ注文の結果が、成功なのか失敗なのかを含めた結果をPrint関数でログ出力します。

string errDesc = TradeServerReturnCodeDescription(result.retcode);
		Print("ブレイクイーブンストップ: ",esult.retcode," - ",errDesc,
		      ", #",parTicket,", SL: ",request.sl,", Bid: ",bid,", Ask: ",ask,
		      ", Stop Level: ",SymbolInfoInteger(symbol,SYMBOL_TRADE_STOPS_LEVEL));

他の関数を解説した時にも出てきた記述ですが、ログ出力する内容はブレイクイーブンストップに準じたものになっています。

戻り値を返す

最後に戻り値を返す記述を行います。↓

if(checkRes == CHECK_RETCODE_OK) return(true);
		else return(false);
	}
	else return(false);//ポジションが選択できなければfalseを返して終了
}

変数「checkRes」にはReturnCodeCheck関数で取得したリターンコードが格納されています。

if(checkRes == CHECK_RETCODE_OK)の条件文がtrueだった場合、無事にブレイクイーブンストップ処理が行われたことを意味するので、returnにて、trueを返します。

checkRes == CHECK_RETCODE_OK以外だった場合、ブレイクイーブンストップ処理に何らかの問題が発生していることを意味するのでelse文の後に、returnにてfalseを返します。

BreakEven関数の処理実装記述は以上になります。

まとめ

今回はブレイクイーブンストップを簡単に実装するために、OriginalCTrailingクラスメンバ関数として、BreakEven関数を追加しました。

BreakEven関数の、OriginalCTrailingクラスpublicセクションにおける記述は以下の通りです。

public:
		bool BreakEven(ulong parTicket, int parBreakEven, int parLockProfit=0);

BreakEven関数の、具体的な処理実装記述の全体は以下の通りです。

//BreakEven関数
bool OriginalCTrailing::BreakEven(ulong parTicket, int parBreakEven, int parLockProfit=0)
{  //ポジション選択が正しく行われ、parBreakEvenが0より大きければ
	if(PositionSelectByTicket(parTicket) == true && parBreakEven > 0)
	{  
		request.action = TRADE_ACTION_SLTP;//.actionへの設定
		request.position = parTicket;//.positionへの設定
		
		long posType = PositionGetInteger(POSITION_TYPE);//ポジションタイプの取得
		double currentSL = PositionGetDouble(POSITION_SL);//ストップロス値の取得
		double currentLimit = PositionGetDouble(POSITION_TP);//テイクプロフィット値の取得
		
		double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);//約定価格の取得
		string symbol = PositionGetString(POSITION_SYMBOL);//ポジション銘柄情報の取得
		
		double point = SymbolInfoDouble(symbol,SYMBOL_POINT);//ポイント情報の取得
		int digits = (int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);//ポジション銘柄の桁数情報取得
		
		
		double breakEvenStop;//ブレイクイーブン発動価格を格納する変数
		double currentProfit;//ポジションの損益情報を格納する変数
		
		// リトライ回数とリターンコードを格納する変数を宣言する
		int retryCount = 0;
		int checkRes = 0;
		
		//Bid値、Ask値格納変数の初期化
		double bid = 0, ask = 0;
		
		do 
		{  //ポジションタイプが「買い」の場合
			if(posType == POSITION_TYPE_BUY)
			{
				bid = SymbolInfoDouble(symbol,SYMBOL_BID);
				breakEvenStop = openPrice + (parLockProfit* point);//ブレイクイーブン発動価格を変数に格納
				currentProfit = bid - openPrice;//ポジション損益情報を変数に格納
				
				//正規化
				breakEvenStop = NormalizeDouble(breakEvenStop, digits);
				currentProfit = NormalizeDouble(currentProfit, digits);
				
				if(currentSL < breakEvenStop && currentProfit >= parBreakEven * point) 
				{//現在のSL値が約定価格+指定値より小さい、かつポジション損益が指定値より大きい

					request.sl = breakEvenStop;
					request.tp= currentLimit;
					bool sent = OrderSend(request,result);
				}
				else return(false);
			}
			//ポジションタイプが売りの場合
			else if(posType == POSITION_TYPE_SELL)
			{
				ask = SymbolInfoDouble(symbol,SYMBOL_ASK);
				breakEvenStop = openPrice - (parLockProfit * point);//ブレイクイーブン発動価格を変数に格納
				currentProfit = openPrice - ask;//ポジション損益情報を変数に格納
				
				//正規化
				breakEvenStop = NormalizeDouble(breakEvenStop, digits);
				currentProfit = NormalizeDouble(currentProfit, digits);
				
				if((currentSL > breakEvenStop || currentSL == 0) && currentProfit >= parBreakEven * point)
				{//<現在のSL値が約定価格-指定値より大きい、または現在のSL値が0のとき>、かつポジション損益が指定値より大きい
					request.sl = breakEvenStop;
					request.tp= currentLimit;
					bool sent = OrderSend(request,result);
				}
				else return(false);
			}
			
			//リターンコードの確認
			checkRes = ReturnCodeCheck(result.retcode);
		   
		   //正常に注文が行われていればループを抜ける
			if(checkRes == CHECK_RETCODE_OK) break;
			else if(checkRes == CHECK_RETCODE_ERROR)
			{  //エラー情報の格納
				string errDesc = TradeServerReturnCodeDescription(result.retcode);
				Alert("ブレイクイーブン注文エラー: エラー内容 ",result.retcode," - ",errDesc);
				break;
			}
			//再注文により、エラーが解消される可能性がある場合
			else
			{
				Print("サーバーエラーを検知, 再試行中...");
				Sleep(RETRY_MILLISECONDS);
				retryCount++;
			}
		}
		while(retryCount < RETRY_LIMIT);
		
	   //再試行の上限に達した場合
		if(retryCount >= RETRY_LIMIT)
		{
			string errDesc = TradeServerReturnCodeDescription(result.retcode);
			Alert("再試行の上限に達しました: エラー内容 ",result.retcode," - ",errDesc);
		}
		
		string errDesc = TradeServerReturnCodeDescription(result.retcode);
		Print("ブレイクイーブンストップ: ",result.retcode," - ",errDesc,
		      ", #",parTicket,", SL: ",request.sl,", Bid: ",bid,", Ask: ",ask,
		      ", Stop Level: ",SymbolInfoInteger(symbol,SYMBOL_TRADE_STOPS_LEVEL));
		
		if(checkRes == CHECK_RETCODE_OK) return(true);
		else return(false);
	}
	else return(false);//ポジションが選択席なければfalseを返して終了

今回は以上とさせていただきます。

最後までお読みいただきありがとうございました。

ブレイクイーブンストップについては以下の記事もご参照ください。

【超入門】MQL5 EA講座 第99回「ブレイクイーブンストップについて」

     →【超入門】MQL5 EA講座 第101回「資金管理とロット調整について」

コメント

タイトルとURLをコピーしました