——————
前回は、ブレイクイーブンストップの概要について解説しました。
改めて前回の内容をおさらいすると、
ブレイクイーブンストップはトレーリングストップと同様に、相場の変化に応じてストップロスを移動させる概念です。
ただ、トレーリングストップと違い、ブレイクイーブンストップはストップロスを移動させる回数は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);
ブレイクイーブンストップ処理が正常に行われた場合にはtrue,正常に行われなかった場合にはfalseを返す設計にするので、戻り値はbool型とします。
BreakEven関数の仮引数を設定する
BreakEven関数の仮引数は以下の通りです。
ulong型の第1仮引数「 parTicket」
ulong型の第1仮引数「parTicket」にはポジション番号が記述される想定です。
int型の第2仮引数「 parBreakEven」
int型の第2仮引数「 parBreakEven」はブレイクイーブンストップを発動させる損益ポイントを設定するのに使います。input変数で設定した値が記述される想定です。
※ブレイクイーブンストップを発動させる損益ポイントについては、前回99回の、
をご覧ください。
int型の第3仮引数「 parLockProfit」
int型の第3仮引数「 parLockProfit」は約定値に追加するポイントを設定するのに使います。
これもinput変数で設定した値が記述される想定です。
約定値に追加するポイントについての詳細は、これも前回第99回の、
をご覧ください。
初期値は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」を、
それぞれ代入をした上で、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」を、
それぞれ代入をした上で、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関数で確認し次の行動を規定します。発注結果は
1「発注が成功した場合」
2「再試行しても解決しないエラーの場合」
3「再試行すれば解決する可能性のあるエラーの場合」というの3つの場合を想定し、
<参考リンク>
- define命令で、再注文の上限回数を設定する。
- break演算子
- ReturnCodeCheck関数
- ErrorDescription.mqhファイルをインクルードする
- リターンコードのチェックをする関数を作成する
- TradeServerReturnCodeDescription関数
- 定数「RETRY_MILLISECONDS」
- 定数「RETRY_LIMIT」
- 「ENUM_CHECK_RETCODE」
- インクリメントとデクリメント
再注文試行が上限回数に達した場合の記述
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を返して終了
今回は以上とさせていただきます。
最後までお読みいただきありがとうございました。
※ブレイクイーブンストップについては以下の記事もご参照ください。
コメント