スポンサーリンク
ホーム » MQL5でEA作ろう講座 » 【超入門】MQL5 EA講座 第77回「固定SLTPを計算する関数を実装する」【MT5用EAの作り方】
a

【超入門】MQL5 EA講座 第77回「固定SLTPを計算する関数を実装する」【MT5用EAの作り方】

MQL5でEA作ろう講座
スポンサーリンク

前回OriginalTrade.mqhファイルに、SLとTPを設定する関数を追加しました。

しかし、ストップロスとテイクプロフィットを設定するにしても、その設定に必要な値は、どうやって算出されるべきなのでしょうか?

前回ストップロスとテイクプロフィットを「設定する」為の関数についての記事でしたが、今回はストップロスとテイクプロフィットを「計算する」為の関数についてお話しします。

スポンサーリンク

SLTPを計算する関数実装のためのロードマップ

ひと口にストップロス、テイクプロフィットと言っても運用するEAによって、様々な戦略がある訳で、統一したSLTP計算関数を作ることなどはできません。

ポイントベースで算出するのか、それとも変動率で算出するのか、一度設定したら以降は変更しない固定SLTP方式にするのか、それとも相場の動きに応じてSLTPも変化させていく動的SLTP方式にするのか等、様々なやり方が採用可能です。

今回は最もオーソドックスな、約定価格に固定のSLTPを設定する関数を実装していきます。

ポジションには「買い」と「売り」があり、それぞれにSLとTPをつけることを想定し、

の4つの関数を今回は作っていきます。

ポイントについては→コチラをご覧ください。

CalBuySL関数の処理実装記述

まずは買いポジションのSL値を算出する関数からです。

関数名は「CalBuySL」としました。戻り値double型です。引数構成は以下の通りです。

double CalBuySL(string parSymbol,int parStopPoints, double parOpenPrice = 0)

引数は3つで、parSymbolには銘柄、parStopPointsにはポイントベースのストップロス値、parOpenPriceはポジションがオープンする価格がそれぞれ入力される予定です。

第3引数のparOpenPriceには初期値が割り振られているので、省略可能です(基本的に約定価格が入るので設定は不要だが、EAの戦略によっては設定したい場合もあるので、初期値をつけてオプションの1つにした・・・という感じです)

関数の初期値については→コチラをご覧ください。

CalBuySL関数の処理実装記述は以下の通りです

//買いのSLを設定する関数
double CalBuySL(string parSymbol,int parStopPoints, double parOpenPrice = 0)
{
	if(parStopPoints <= 0) return(0);
	
	double openPrice;
	if(parOpenPrice > 0) openPrice = parOpenPrice;
	else openPrice = SymbolInfoDouble(parSymbol,SYMBOL_ASK);
	//指定があればその値、なければASKを基準値として採用
	
	double point = SymbolInfoDouble(parSymbol,SYMBOL_POINT);
	double stopLoss = openPrice - (parStopPoints * point);
	//現在値-pStopPoints * pointを損切りプライスとして代入
	
	long digits = SymbolInfoInteger(parSymbol,SYMBOL_DIGITS);
	stopLoss = NormalizeDouble(stopLoss,(int)digits);
	
	return(stopLoss);
}

これまでの講座記事で学んでいる人なら、もう一々解説する必要もないレベルの記述ですが、一応順を追って見ていきます

処理実装記述1:引数「parStopPoints」の値確認
if(parStopPoints <= 0) return(0);

引数「parStopPoints」にはポイントベースの損切り値が記述されているはずです。

これが0以下の場合、ストップロス値を設定していないか異常値である、という事を意味しますので次の処理に進まずreturnで終了させます。

returnについては→コチラをご覧ください。

処理実装記述3:引数「parStopPoints」の値確認
double openPrice;
	if(parOpenPrice > 0) openPrice = parOpenPrice;
	else openPrice = SymbolInfoDouble(parSymbol,SYMBOL_ASK);
	//指定があればその値、なければASKを基準値として採用

買いポジションのSL値を算出する関数の項目でも書いたように、引数「parOpenPrice」には初期値が割り振られているので呼び出し時に省略可能です。

従って、引数「parOpenPrice」による指定された値があればその値、なければSymbolInfoDouble関数によって取得したASK値を基準値として採用し、double型ローカル変数「openPrice」に格納しています。

ローカル変数については→コチラをご覧ください。

if文else文については↓の記事をご覧ください。

処理実装記述4:SLを設定する値を計算する
double point = SymbolInfoDouble(parSymbol,SYMBOL_POINT);
	double stopLoss = openPrice - (parStopPoints * point);
	//現在値-pStopPoints * pointを損切りプライスとして代入

買いポジションの損切り値というのは、

(ポジションオープン価格) – (設定したポイント

で求められます。

SymbolInfoDouble関数で、銘柄のポイントを取得し(定義済み変数_Pointを使っても可)、変数「point」に格納したら、

openPrice – (parStopPoints * point) の計算結果を変数「stopLoss」に格納します。

openPrice にはポジションオープン予定価格が入っています(仮に銘柄がドル円で150.000とします)

parStopPoints にはinput変数などでパラメータ化した値が入っているはずです(仮に500とします)

ドル円は価格の表示桁数が3桁通貨なのでポイントは0.001です。(parStopPoints * point)は(500*0.001)となりその答えは0.5。

ポジションオープン予定価格の150.000にこの値を足して、150.500という値が導き出されます。これが変数「stopLoss」に格納されます。

処理実装記述5:桁数情報の取得と「stopLoss」格納値の正規化
//桁数情報を取得
long digits = SymbolInfoInteger(parSymbol,SYMBOL_DIGITS);
//値の正規化
stopLoss = NormalizeDouble(stopLoss,(int)digits);

return(stopLoss);

変数「stopLoss」にめでたくSL値が格納されたので、これを戻り値として返して終了・・・としたいところですが最後にもうひと手間かけます。

MT5で取り扱っている取引銘柄には、銘柄ごとに小数点以下何桁までを表示するか定められています。例えばドル円などの、クロス円通貨であれば小数点以下3桁まで、ユーロドルなどのクロスドルなら小数点以下5桁まで・・・といった感じです。

取引銘柄ごとの桁数を取得するにはSymbolInfoInteger関数の第2引数定数値SYMBOL_DIGITSを記述します(定義済み変数_Digitsでも可)。

取引銘柄ごとの桁数に関する情報を取得出来たら、最後に正規化を行い、値の形を整えます。

正規化とは数値・データを特定のルールに従った形に整えることを言います。ここでいう「特定のルール」とは変数「stopLoss」に格納されているストップロス値を適切な桁数にそろえることを指します。

例えば、ドル円であれば3桁通貨なので、ストップロス値をトレードサーバーに注文として出すときに150.50845・・・などのような3桁以上のデータを提出するのは望ましくない、という事です。

(最も現行バージョンのMT5では自動的に値の切り詰め(truncation)を行っていると思われますので、注文エラーは恐らく生じないでしょう。ただ、公式にそう明言されている訳でもない以上、値の正規化はなるべく行った方が良いでしょう

正規化にはNormalizeDouble関数を用います。第2引数に、変数「digits」を記述することによって、変数「stopLoss」に格納されているストップロス値を適切な形に整形できます。ちなみに、変数「digits」の前についている(int)はタイプキャストです。

stopLoss = NormalizeDouble(stopLoss,(int)digits);

変数「digits」のデータ型をSymbolInfoInteger関数戻り値に合わせてlong型にしている為、メタエディターコンパイルした際に警告が出なくするための処置です(なくても多分動作不良は生じないとは思います)

NormalizeDouble関数による正規化が終了したら、変数「stopLoss」に格納されている値をreturnで返して関数の処理は終了です。

取引銘柄ごとの桁数については→コチラをご覧ください。

NormalizeDouble関数については→コチラをご覧ください。

型変換(タイプキャスト)については→コチラをご覧ください。

CalBuyTP関数の処理実装記述

次は買いポジションにテイクプロフィットを設定する関数です。

とは言っても、CalBuySL関数と構造は同じです。

//買いのTPを設定する関数
double CalBuyTP(string parSymbol,int parProfitPoints, double parOpenPrice = 0)
{
	if(parProfitPoints <= 0) return(0);
	
	double openPrice;
	if(parOpenPrice > 0) openPrice = parOpenPrice;
	else openPrice = SymbolInfoDouble(parSymbol,SYMBOL_ASK);
	
	double point = SymbolInfoDouble(parSymbol,SYMBOL_POINT);
	double takeProfit = openPrice + (parProfitPoints * point);
	
	long digits = SymbolInfoInteger(parSymbol,SYMBOL_DIGITS);
	takeProfit = NormalizeDouble(takeProfit,(int)digits);
	return(takeProfit);
}

違いは、最終的に戻り値として返す、テイクプロフィットの計算式ぐらいです。

SLが損切り値なので、ポジションオープン値から指ポイント分マイナスさせていたのに対し、

TPは利益獲得値なので、ポジションオープン値から指定ポイント分プラスさせればいい、という訳です。

後の部分は、「CalBuySL関数の処理実装記述」を照合していただければ迷う事はないでしょう。

<参照>

SymbolInfoDouble

SymbolInfoInteger

NormalizeDouble

CalSellSL関数の処理実装記述

買いポジションのSLとTPについては終わったので、今度は売りポジションのSLとTPを計算する関数を実装していきます。

とは言っても、もう想像がつくと思いますが関数の構造自体は買いポジションと同じです。

  • 変数「openPrice」に代入する値が、SYMBOL_BIDになっている事
  • 買いポジションの時とストップロス・テイクプロフィットの計算式が逆になっている事

違いはそれだけです。説明が重複するので、他の記述で分からない部分があれば「CalBuySL関数の処理実装記述」を参考にしていただくのが良いかと思います

全体の構造はコチラ↓

//売りのSLを設定する関数
double CalSellSL(string parSymbol,int parStopPoints, double parOpenPrice = 0)
{
	if(parStopPoints <= 0) return(0);
	
	double openPrice;
	if(parOpenPrice > 0) openPrice = parOpenPrice;
	else openPrice = SymbolInfoDouble(parSymbol,SYMBOL_BID);
	
	double point = SymbolInfoDouble(parSymbol,SYMBOL_POINT);
	double stopLoss = openPrice + (parStopPoints * point);
	
	long digits = SymbolInfoInteger(parSymbol,SYMBOL_DIGITS);
	stopLoss = NormalizeDouble(stopLoss,(int)digits);
	
	return(stopLoss);
}

<参照>

SymbolInfoDouble

SymbolInfoInteger

NormalizeDouble

CalSellTP関数の処理実装記述

CalSellTP関数についても、構造は最初に書いたCalBuySL関数と同じなので、詳細は割愛させて頂きます。記述で不明なところがあれば「CalBuySL関数の処理実装記述」を参考にしていただければと思います。

全体の構造はコチラ↓

//売りのTPを設定する関数
double CalSellTP(string parSymbol,int parProfitPoints, double parOpenPrice = 0)
{
	if(parProfitPoints <= 0) return(0);
	
	double openPrice;
	if(parOpenPrice > 0) openPrice = parOpenPrice;
	else openPrice = SymbolInfoDouble(parSymbol,SYMBOL_BID);
	
	double point = SymbolInfoDouble(parSymbol,SYMBOL_POINT);
	double takeProfit = openPrice - (parProfitPoints * point);
	
	long digits = SymbolInfoInteger(parSymbol,SYMBOL_DIGITS);
	takeProfit = NormalizeDouble(takeProfit,(int)digits);
	return(takeProfit);
}

<参照>

SymbolInfoDouble

SymbolInfoInteger

NormalizeDouble

スポンサーリンク

これまでのOriginalTrade.mqhファイル全体の記述内容

これまでのOriginalTrade.mqhファイル全体の記述内容は以下の通りです

//+------------------------------------------------------------------+
//|                                                OriginalTrade.mqh |
//|                                                         MQL5ssei |
//|                                    https://mqlinvestmentlab.com/ |
//+------------------------------------------------------------------+
#property copyright "MQL5ssei"
#property link      "https://mqlinvestmentlab.com/"
#define RETRY_LIMIT 3//エラー時に再注文を出す上限回数
#define RETRY_MILLISECONDS 3000//再注文処理に移るまでの待機時間

#include <errordescription.mqh>

//トレード用のクラス「OriginalCTrade」を定義する
class OriginalCTrade
  {
protected:
   MqlTradeRequest   request;
   ulong             magicNumber;//マジックナンバーを格納する
   ulong             deviation;//スリッページを格納する
   ENUM_ORDER_TYPE_FILLING fillType;//フィルポリシーを格納する
   void TradeLog();//注文内容と結果をエキスパートログに残す

   //ポジションオープンクラスの実装
   ulong PositionOpen(string parSymbol, ENUM_ORDER_TYPE parType, double parVolume, double parStop = 0, double parProfit = 0, string parComment = NULL);


public:
   MqlTradeResult    result;
   //買い注文を出す関数
   ulong Buy(string parSymbol, double parVolume, double parStop = 0, double parProfit = 0, string parComment = NULL);
   //売り注文を出す関数
   ulong Sell(string parSymbol, double parVolume, double parStop = 0, double parProfit = 0, string parComment = NULL);
   //マジックナンバーを設定する関数
   void OriginalCTrade::SetMagicNumber(ulong parMagic);
   // スリッページを設定する
   void SetDeviation(ulong parDeviation);
   // フィルポリシーを設定する
  void SetFillType(ENUM_ORDER_TYPE_FILLING parFill);
  //ストップロスとテイクプロフィットを設定する
  bool SetSLTP(ulong parTicket, double parStop, double parProfit = 0);

  };//class OriginalCTrade
  


//PositionOpen関数の処理内容を実装
ulong OriginalCTrade::PositionOpen(string parSymbol, ENUM_ORDER_TYPE parType, double parVolume, double parStop = 0, double parProfit = 0, string parComment = NULL)
  {

//構造体インスタンスのリセット
   ZeroMemory(request);
   ZeroMemory(result);

   request.action = TRADE_ACTION_DEAL;//取引の種類を設定する
   request.symbol = parSymbol;//取引銘柄を設定する
   request.type = parType;//注文タイプを設定する
   request.sl = parStop;//ストップロスを設定する
   request.tp = parProfit;//テイクプロフィットを設定する
   request.comment = parComment;//コメントを設定する
   request.volume = parVolume;//ロット数を設定する
   request.deviation = deviation;//スリッページを設定する
   request.type_filling = fillType;//フィルポリシーを設定する
   request.magic = magicNumber;////マジックナンバーを設定する

// リトライ回数とリターンコードを格納する変数を宣言
   int retryCount = 0;
   int checkCode = 0;

//発注回路の記述
   do
     {
      //買いの場合の注文価格
      if(parType == ORDER_TYPE_BUY)
         request.price = SymbolInfoDouble(parSymbol,SYMBOL_ASK);
      //売りの場合の注文価格
      else
         if(parType == ORDER_TYPE_SELL)
            request.price = SymbolInfoDouble(parSymbol,SYMBOL_BID);

      //注文を出す
      bool sent = OrderSend(request,result);
      
      //リターンコードを変数checkCode に格納する
      checkCode = ReturnCodeCheck(result.retcode);
     
      if(checkCode == CHECK_RETCODE_OK) break;
		else if(checkCode == CHECK_RETCODE_ERROR)
		{
			string errDesc = TradeServerReturnCodeDescription(result.retcode);
			Alert("注文エラー: エラー内容 ",result.retcode," - ",errDesc);
			TradeLog();
			break;
		}
		else//CHECK_RETCODE_RETRYの場合
		{
			Print("サーバーエラーを検知。 再試行中...");
			Sleep(RETRY_MILLISECONDS);
			retryCount++;
		}//else
      
      
     }//do
   while(retryCount < RETRY_LIMIT);
   
   //再注文上限回数に達した時
   if(retryCount >= RETRY_LIMIT)
   {
		string errDesc = TradeServerReturnCodeDescription(result.retcode);
		Alert("再注文上限回数に達しました: エラー内容 ",result.retcode," - ",errDesc);
	}
	
	//注文種類を確認する関数を呼び出し戻り値を変数に格納
	string orderType = ConfirmOrderType(parType);
	string errDesc = TradeServerReturnCodeDescription(result.retcode);
	
	//ログ出力
	Print("注文種類",orderType,
	      "オーダー番号 #",result.order,
	      " リターンコード: ",result.retcode,
	      " - ",errDesc,
	      ", ロット数: ",result.volume,
	      ", 約定価格: ",result.price);

//戻り値を返す
if(checkCode == CHECK_RETCODE_OK) 
	{
		Comment("注文種類: ",orderType," オーダー番号 #",result.order," 約定価格 ",result.price);
		return(result.order);
	}
	else return(0);
   
  }//OriginalCTrade::PositionOpen

//+------------------------------------------------------------------+



// リターンコードによって、次の行動を決めるための列挙型
enum ENUM_CHECK_RETCODE
{
	CHECK_RETCODE_OK,
	CHECK_RETCODE_ERROR,
	CHECK_RETCODE_RETRY
};


// リターンコードのチェックをする関数
int ReturnCodeCheck(uint parRetCode)
{
	int status;
	switch(parRetCode)
	{
		case TRADE_RETCODE_REQUOTE:
		case TRADE_RETCODE_CONNECTION:
		case TRADE_RETCODE_PRICE_CHANGED:
		case TRADE_RETCODE_TIMEOUT:
		case TRADE_RETCODE_PRICE_OFF:
		case TRADE_RETCODE_REJECT:
		case TRADE_RETCODE_ERROR:
		
			status = CHECK_RETCODE_RETRY;
			break;
			
		case TRADE_RETCODE_DONE:
		case TRADE_RETCODE_DONE_PARTIAL:
		case TRADE_RETCODE_PLACED:
		case TRADE_RETCODE_NO_CHANGES:
		
			status = CHECK_RETCODE_OK;
			break;
			
		default: status = CHECK_RETCODE_ERROR;
	}
	
	return(status);
}

//注文内容と結果をエキスパートログに残す
void OriginalCTrade::TradeLog()
{
   Print("MqlTradeRequest - 取引の種類:",request.action,
         ", コメント:",request.comment,
         ",スリッページ:",request.deviation,
         ", 注文有効期限:",request.expiration,
         ", マジックナンバー:",request.magic,
         ", オーダー番号:",request.order,
         ", ポジション番号:",request.position,
         ", 反対ポジションの番号:",request.position_by,
         ", ポジション価格:",request.price,
         ", ストップロス:",request.sl,
         ", テイクプロフィット:",request.tp,
         ", ストップリミット:",request.stoplimit,
         ", 取引銘柄:",request.symbol,
         ", オーダー種類:",request.type,
         ", フィルポリシー:",request.type_filling,
         ", 有効期限の種類:",request.type_time,
         ", ロット数:",request.volume);
         
   Print("MqlTradeResult - ask:",result.ask,
         ", bid:",result.bid,
         ", コメント:",result.comment,
         ", 約定番号:",result.deal,
         ", オーダー番号:",result.order,
         ", ポジション価格:",result.price,
         ", リクエストID:",result.request_id,
         ", リターンコード:",result.retcode,
         ", リターンコード(外部):",result.retcode_external,
         ", ロット数:",result.volume);

}//void OriginalCTrade::TradeLog()

//注文種類を確認する関数
string ConfirmOrderType(ENUM_ORDER_TYPE parType)
{
	string orderType;
	if(parType == ORDER_TYPE_BUY) orderType = "buy";
	else if(parType == ORDER_TYPE_SELL) orderType = "sell";
	else if(parType == ORDER_TYPE_BUY_STOP) orderType = "buy stop";
	else if(parType == ORDER_TYPE_BUY_LIMIT) orderType = "buy limit";
	else if(parType == ORDER_TYPE_SELL_STOP) orderType = "sell stop";
	else if(parType == ORDER_TYPE_SELL_LIMIT) orderType = "sell limit";
	else if(parType == ORDER_TYPE_BUY_STOP_LIMIT) orderType = "buy stop limit";
	else if(parType == ORDER_TYPE_SELL_STOP_LIMIT) orderType = "sell stop limit";
	else orderType = "不適切な注文種類です。";
	return(orderType);
}

// 買い注文を出す
ulong OriginalCTrade::Buy(string parSymbol, double parVolume, double parStop = 0, double parProfit = 0, string parComment = NULL)
{
	ulong ticket = PositionOpen(parSymbol,ORDER_TYPE_BUY,parVolume,parStop,parProfit,parComment);
	return(ticket);
}

// 売り注文を出す
ulong OriginalCTrade::Sell(string parSymbol, double parVolume, double parStop = 0, double parProfit = 0, string parComment = NULL)
{
	ulong ticket = PositionOpen(parSymbol,ORDER_TYPE_SELL,parVolume,parStop,parProfit,parComment);
	return(ticket);
}

// マジックナンバーを設定する
void OriginalCTrade::SetMagicNumber(ulong parMagic)
{
	magicNumber = parMagic;
}

// スリッページを設定する
void OriginalCTrade::SetDeviation(ulong parDeviation)
{
	deviation = parDeviation;
}

// フィルポリシーを設定する
void OriginalCTrade::SetFillType(ENUM_ORDER_TYPE_FILLING parFill)
{
	fillType = parFill;
}

//+------------------------------------------------------------------+
//フィルポリシーを返す関数
ENUM_ORDER_TYPE_FILLING FillPolicy()
{
   long fillType = SymbolInfoInteger(_Symbol, SYMBOL_FILLING_MODE);
   if(fillType==SYMBOL_FILLING_IOC)return ORDER_FILLING_IOC;
   else if(fillType==SYMBOL_FILLING_FOK)return ORDER_FILLING_FOK;
   else return ORDER_FILLING_RETURN;

}

//ストップロスとテイクプロフィットを設定する
bool OriginalCTrade::SetSLTP(ulong parTicket,double parStop,double parProfit=0.000000)
{
	//インスタンスのリセット
	ZeroMemory(request);
	ZeroMemory(result);
	
	//ポジション番号を取得し、変数に格納
	bool select = PositionSelectByTicket(parTicket);
	//銘柄を取得し、変数に格納
	string symbol = PositionGetString(POSITION_SYMBOL);
	
	request.action = TRADE_ACTION_SLTP;//取引種別の設定
	request.sl = parStop;//ストップロスの設定
	request.tp = parProfit;//テイクプロフィットの設定
	request.position = parTicket;//ポジション番号の設定
	request.symbol = symbol;//銘柄情報の設定
	request.type_filling = fillType;//フィルポリシーを設定
   request.magic = magicNumber;////マジックナンバーを設定
   
	// リトライ回数とリターンコードを格納する変数を宣言
	int retryCount = 0;//再試行回数を格納する
	int checkCode = 0;//リターンコードを格納する
	
	do 
	{  //SLTP設定注文を出す。
		bool sent = OrderSend(request,result);
		
		//注文結果を返す
		checkCode = ReturnCodeCheck(result.retcode);
		
		//約定成功の場合do-whileループを抜ける
		if(checkCode == CHECK_RETCODE_OK) break;
		//再試行しても解決しないエラーの場合
		else if(checkCode == CHECK_RETCODE_ERROR)
		{  //リターンコードを取得
			string errDesc = TradeServerReturnCodeDescription(result.retcode);
			//アラートを発出
			Alert("SLTP設定エラー:エラー内容 ",result.retcode," - ",errDesc);
			//ログの出力
			TradeLog();
			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("SLTP設定ポジション番号 #",parTicket,
	      ": ",result.retcode," - ",errDesc,
	      ", SL: ",request.sl,", TP: ",request.tp,
	      ", Bid: ",SymbolInfoDouble(symbol,SYMBOL_BID),
	      ", Ask: ",SymbolInfoDouble(symbol,SYMBOL_ASK),
	      ", ストップレベル: ",SymbolInfoInteger(symbol,SYMBOL_TRADE_STOPS_LEVEL));
	
	//注文が成功した場合、trueを返す
	if(checkCode == CHECK_RETCODE_OK) 
	{
		Comment("ポジション番号 #",parTicket," SLTP設定した銘柄 ",symbol,", SL: ",request.sl,", TP: ",request.tp);
		return(true);
	}
	//注文が失敗した場合、falseを返す
	else return(false);
}

//+------------------------------------------------------------------+
//| ストップロスとテイクプロフィットを計算する関数                                                       
//+------------------------------------------------------------------+
//買いのSLを設定する関数
double CalBuySL(string parSymbol,int parStopPoints, double parOpenPrice = 0)
{
	if(parStopPoints <= 0) return(0);
	
	double openPrice;
	if(parOpenPrice > 0) openPrice = parOpenPrice;
	else openPrice = SymbolInfoDouble(parSymbol,SYMBOL_ASK);
	//指定があればその値、なければASKを基準値として採用
	
	double point = SymbolInfoDouble(parSymbol,SYMBOL_POINT);
	double stopLoss = openPrice - (parStopPoints * point);
	//現在値-pStopPoints * pointを損切りプライスとして代入
	
	long digits = SymbolInfoInteger(parSymbol,SYMBOL_DIGITS);
	stopLoss = NormalizeDouble(stopLoss,(int)digits);
	
	return(stopLoss);
}


//買いのTPを設定する関数
double CalBuyTP(string parSymbol,int parProfitPoints, double parOpenPrice = 0)
{
	if(parProfitPoints <= 0) return(0);
	
	double openPrice;
	if(parOpenPrice > 0) openPrice = parOpenPrice;
	else openPrice = SymbolInfoDouble(parSymbol,SYMBOL_ASK);
	
	double point = SymbolInfoDouble(parSymbol,SYMBOL_POINT);
	double takeProfit = openPrice + (parProfitPoints * point);
	
	long digits = SymbolInfoInteger(parSymbol,SYMBOL_DIGITS);
	takeProfit = NormalizeDouble(takeProfit,(int)digits);
	return(takeProfit);
}

//売りのSLを設定する関数
double CalSellSL(string parSymbol,int parStopPoints, double parOpenPrice = 0)
{
	if(parStopPoints <= 0) return(0);
	
	double openPrice;
	if(parOpenPrice > 0) openPrice = parOpenPrice;
	else openPrice = SymbolInfoDouble(parSymbol,SYMBOL_BID);
	
	double point = SymbolInfoDouble(parSymbol,SYMBOL_POINT);
	double stopLoss = openPrice + (parStopPoints * point);
	
	long digits = SymbolInfoInteger(parSymbol,SYMBOL_DIGITS);
	stopLoss = NormalizeDouble(stopLoss,(int)digits);
	
	return(stopLoss);
}

//売りのTPを設定する関数
double CalSellTP(string parSymbol,int parProfitPoints, double parOpenPrice = 0)
{
	if(parProfitPoints <= 0) return(0);
	
	double openPrice;
	if(parOpenPrice > 0) openPrice = parOpenPrice;
	else openPrice = SymbolInfoDouble(parSymbol,SYMBOL_BID);
	
	double point = SymbolInfoDouble(parSymbol,SYMBOL_POINT);
	double takeProfit = openPrice - (parProfitPoints * point);
	
	long digits = SymbolInfoInteger(parSymbol,SYMBOL_DIGITS);
	takeProfit = NormalizeDouble(takeProfit,(int)digits);
	return(takeProfit);
}

これまでにOriginalTrade.mqhファイルに、講座記事を通して追加してきた関数の解説ページへのリンクを↓に貼っておきますので、参考にしてください。

今回は以上になります。最後までお読みいただきありがとうございました。<m(__)m>

超入門】MQL5 EA講座 第76回「SLとTPを設定する関数をクラスに追加する」

    →MQL5 EA講座 第78回「ストップレベルについて」【MT5用EAの作り方】

関連用語リンク集

MQL5FX関連の用語リンク集です。
当サイトでは、元々わからない言葉や概念に出くわしたら、すぐその言葉に立ち戻れるよう、かなり細かく内部リンクを張り巡らせており、多様な用語を網羅しています。

興味のある内容に直接アクセスし、疑問の解決にお役立ていただければと思います。

スポンサーリンク
MQL5でEA作ろう講座
スポンサーリンク
シェアする
エムキューエルをフォローする
スポンサーリンク
【超入門】MQL5 でEAを作ろうブログ

コメント

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