前回は動的トレーリングストップとは何か?という事を説明した上で、EA(自動売買プログラム)を作る際に、動的トレーリングストップを導入する記述に関する解説を行いました。
改めて前回の内容をおさらいすると、
動的トレーリングストップとは、移動平均線やパラボリック、直近高安値などの指標を利用して、SL値を変更していこうとする戦略、及び(MQL5においては)それを実現する為のコード記述を指します。
今回はブレイクイーブンストップについて解説していこうと思います。
今回も引き続き、ストップロスに関するお話です。
トレーリングストップと似た概念にはなりますが、若干異なる点もあります。
ブレイクイーブンストップとは?
ブレイクイーブンストップも、トレーリングストップと同様に、ストップロスを移動させる時に使う概念です。
注文したポジションが、想定する方向(利益を生み出す方向)にある程度向かったら、当初設定していたストップロスを移動させます。ここまではトレーリングストップと一緒です。
トレーリングストップとブレイクイーブンストップの違い
トレーリングストップと違う点は、ブレイクイーブンストップはストップロスを移動させる回数は1回のみという事です。
ストップロス値はポジションを取った約定価格付近に移動させることが多いので、ブレイクイーブンストップと呼んでいます(記述によっては、約定価格よりもっと離れた価格にすることも可能です)
トレーリングストップの場合、固定トレーリングストップであれ、動的トレーリングストップであれ、ストップロスは相場の変動に応じて複数回移動する可能性があります。
その場合、相場が逆行した際にも、小まめに移動したストップロスのおかげで利益を確保できるというメリットがある一方で、一時的な逆行にポジションが絡めとられて決済されてしまい、もっと大きな利益が取れる機会を逸してしまう可能性をはらんでいます。
一方、ブレイクイーブンストップの場合、ストップロスの移動は建値付近への1回だけで、その後は移動したストップロスか、テイクプロフィット(あるいは独自に設定した決済条件)に達するまでストップロス変更は行いません。
従って、仮にテイクプロフィットに到達する前に相場が逆行しても、ほぼプラマイゼロでその取引を終えることができますし、逆に利益方向に価格が伸びていった時に、一時的な相場の揺り戻しにポジションが絡めとられずに、大きな利益を確定させることができる可能性が高まります。
いろいろと書いてきましたが、トレーリングストップとブレイクイーブンストップ、どちらの方が戦略として優れているという優越はありません。あくまでトレード戦略における1要素でしかありません。
ただ、どちらもEA(自動売買プログラム)制作における手札の1つとして、自由に実装できるようになることには、EA(自動売買プログラム)開発の幅を広められる、という点で大きな意味があるでしょう。
EAにブレイクイーブンストップを導入する為のロードマップ
EA(自動売買プログラム)にブレイクイーブンストップを導入する為には、以下の手順を踏んで実現させます。
・ブレイクイーブンストップに必要なinput変数を宣言する。
・MqlTradeRequest構造体のメンバ変数への値代入と必要な値の取得
一つ一つ順を追って見ていきましょう
※ブレイクイーブンストップに関する解説にフォーカスする為に、ブレイクイーブンストップ以外の細かい記述(売買条件等)は省略させていただきます。
ブレイクイーブンストップに必要なinput変数を宣言する
まずはブレイクイーブンストップに必要なinput変数を宣言します。
//インプット変数の宣言
input bool AllowBreakEvenStop=false;//ブレイクイーブンストップのON/OFF
input int BreakEven=0;//ブレイクイーブンを発動させる損益ポイント
input int LockProfit=0;//約定値に追加するポイント
bool型のinput変数「AllowBreakEvenStop」
bool型のinput変数「AllowBreakEvenStop」は、ブレイクイーブンストップのON/OFFを切り替えるために使います。
初期値はfalseとしておきます。
この値がfalseの時は、そもそもブレイクイーブンストップを発動しないようにOnTick関数内に記述します。
int型のinput変数「BreakEven」
int型のinput変数「BreakEven」は、ブレイクイーブンストップを発動させる損益ポイントを設定するのに使います。ブレイクイーブンストップを発動させる損益ポイント、というのは「ポジションがどれくらいの利益が出たらブレイクイーブンストップを発動させるか?」という意味合いになります。
詳しくはこの後、具体的な処理実装記述の所で解説します。
初期値は0としておきます。
int型のinput変数「LockProfit」
int型のinput変数「LockProfit」は約定値に追加するポイントを設定するのに使います。
初期値は0としておきます。
この変数についても、詳しくはこの後具体的な処理実装記述の所で解説するのですが、この変数の値が0の時はストップロスを約定値と同じ価格に移動させます。
ストップロスにかかった場合は、プラスマイナスゼロで取引を終了します。この値を大きくするとストップロスにかかった時も設定したポイント分利益を確保して取引を終了します。
input変数の宣言が終わったので、次はイベントハンドラーであるOnTick関数内の記述に移ります。
※input変数については下記の記事をご覧ください。
ブレイクイーブンストップ発動に必要な条件文を記述する
ブレイクイーブンストップ発動に必要な条件文をif文で記述します。
記述箇所は売買条件の記述が終わった後、OnTick関数の終わり付近にて行います
MqlTradeRequest request;
MqlTradeCheckResult result;
ZeroMemory(request);
//ブレイクイーブンストップの発動条件を記述
if(AllowBreakEvenStop==true
&&
PositionSelectByTicket(1234)==true
&&
BreakEven>0
)
{
}//if(AllowBreakEvenStop==true
最初のAllowBreakEvenStop==trueについてですが、変数「AllowBreakEvenStop」はbool型のinput変数「AllowBreakEvenStop」セクションで解説したinput変数です。
EA(自動売買プログラム)稼働前の設定で「AllowBreakEvenStop」の値がfalseだった場合は、そもそもブレイクイーブンストップを発動させない、という意味合いになります。
これは前回98回の動的トレーリングストップ発動条件文で使ったbool型の変数「AllowTrailingStop」と役割的には同じですね。
※詳しくは前回の「動的トレーリングストップの発動タイミングに関する記述を行う」セクションをご覧ください。
論理積 &&に続く記述、
PositionSelectByTicket(1234)==true
はポジションの選択が正常に行われたことを意味します。
※引数(1234)は適当な数字です。
条件文の最後、
BreakEven>0
についてですが、変数「BreakEven」は int型のinput変数「BreakEven」セクションで解説したinput変数です。
この変数「BreakEven」はブレイクイーブンストップを発動させる損益ポイント、即ち「ポジションがどれくらいの利益が出たらブレイクイーブンストップを発動させるか?」を設定する変数です。
この値が0の場合は、発動させる利益ポイントが設定されていないという事になります。
よって、この変数「BreakEven」の値が0じゃない時、というのを発動条件に加えた形です。
※論理積 については以下の記事をご覧ください。
条件文の中1:MqlTradeRequest構造体のメンバ変数への値代入と必要な値の取得
続いて、MqlTradeRequest構造体のメンバ変数への値代入と必要な値の取得を記述していきます。
request.action=TRADE_ACTION_SLTP;
request.symbol=_Symbol;
request.tp=0;
long posType=PositionGetInteger(POSITION_TYPE);
double currentStop=PositionGetDouble(POSITION_SL);
double openPrice=PositionGetDouble(POSITION_PRICE_OPEN);
メンバ変数.actionには、ストップロス変更を行う「TRADE_ACTION_SLTP」を代入します。
※この時、まだ指値価格に到達しておらず、ポジション保有に至っていない待機注文の変更をしたい時に使うTRADE_ACTION_MODIFYを用いないよう注意しましょう。
.symbolには定義済み変数「_Symbol」を代入します。
long型のローカル変数「posType」にはポジションタイプを格納します。
ポジションタイプ情報はPositionGetInteger関数の引数に定数「POSITION_TYPE」を記述して取得します。
double型のローカル変数「currentStop」には現在のストップロス値を格納します。
現在のストップロス値はPositionGetDouble関数の引数に定数「POSITION_SL」を記述して取得します。
double型のローカル変数「openPrice」にはポジションの約定価格を格納します。
ポジションの約定価格はPositionGetDouble関数の引数に定数「POSITION_PRICE_OPEN」を記述して取得します。
条件文の中2:ポジションタイプが「買い」の場合の記述を行う
次はポジションタイプが買いの場合の記述を行います。
//買いの場合
if(posType==POSITION_TYPE_BUY)
{
double currentPrice=SymbolInfoDouble(_Symbol,SYMBOL_BID);
double breakEvenPrice=openPrice+(LockProfit*_Point);
double currentProfit=currentPrice-openPrice;
if(currentStop<breakEvenPrice
&&
currentProfit>=BreakEven*_Point
)
{
request.sl=breakEvenPrice;
OrderSend(request,result);
}//if(currentStop<breakEvenPrice
}//if(posType==POSITION_TYPE_BUY)
変数「posType」にはポジションタイプが格納されているので、その値が定数値「POSITION_TYPE_BUY」だった場合はポジションタイプが「買い」という事になります。
if(posType==POSITION_TYPE_BUY)の中1:必要な値取得を行う
if(posType==POSITION_TYPE_BUY)の条件がtrueだった場合の{}内執行文を記述します。
double型のローカル変数「currentPrice」
double currentPrice=SymbolInfoDouble(_Symbol,SYMBOL_BID);
double型のローカル変数「currentPrice」には現在値情報を格納します。買いポジションにおける現在値の取得にはSymbolInfoDouble関数の第2引数に「SYMBOL_BID」を記述する事によって実現します。
double型のローカル変数「breakEvenPrice」
double breakEvenPrice=openPrice+(LockProfit*_Point);
double型のローカル変数「breakEvenPrice」にはブレイクイーブンストップを発動させる際に移動するべきストップロス価格を格納します。
この値は変数「openPrice」即ち約定価格に、input変数「LockProfit」と定義済み変数「_Point」を掛け算したものを足して求めます。
※「LockProfit」の値が0の場合は「breakEvenPrice」には約定価格の値が入る事になります。
double型のローカル変数「currentProfit」
double currentProfit=currentPrice-openPrice;
double型のローカル変数「currentProfit」にはポジションの損益情報を格納します。
ポジションの損益情報は、変数「currentPrice」即ち現在値から、変数「openPrice」即ち約定価格を引き算する事によって求まります。
if(posType==POSITION_TYPE_BUY)の中2:ブレイクイーブンストップを発動させる条件文を記述する
必要な値取得の記述が終わったので、次はブレイクイーブンストップを発動させる条件文を記述します。
if(currentStop<breakEvenPrice
&&
currentProfit>=BreakEven*_Point
)
{
request.sl=breakEvenPrice;
OrderSend(request,result);
}//if(currentStop<breakEvenPrice
if文()の中の最初の条件文
currentStop<breakEvenPrice
についてですが、変数「currentStop」は現在のストップロス価格が格納されています。
、変数「breakEvenPrice」は、
「if(posType==POSITION_TYPE_BUY)の中1:必要な値取得を行う」 セクションで解説したように約定価格にinput変数「LockProfit」を価格ベースに計算した値がプラスされた値が入っています。
つまり、
現在のストップロスより約定価格(に任意の値をプラスした価格)の方が大きい場合
と読み解く事ができます。
この条件式を入れることによって、現在のストップロス価格が約定価格(に任意の値をプラスした価格)と等しくなった時点でそれ以上ストップロス価格を移動できなくします。
論理積 で繋いだもう一つの条件式
currentProfit>=BreakEven*_Point
ですが、変数「currentProfit」にはポジションの損益情報が格納されています。
BreakEvenは「int型のinput変数「BreakEven」セクションで設定したinput変数です。
定義済み変数「_Point」と掛け算を行い、価格ベースに直した値を、変数「currentProfit」と比較します。
変数「currentProfit」の値の方が大きければ、ブレイクイーブンストップを発動させる条件のもう一方を満たしている事になります。
二つの条件式がtrueである場合、{}内の発注処理記述に移ります。
{
request.sl=breakEvenPrice;
OrderSend(request,result);
}//if(currentStop<breakEvenPrice
メンバ変数.sl に変数「breakEvenPrice」を代入をした上で、OrderSend関数の引数にMqlTradeRequest構造体のインスタンス「request」、MqlTradeResult構造体のインスタンス「result」を記述して終了です。
以上が、ポジションタイプが「買い」だった場合の記述です。
※MqlTradeRequest構造体についてはコチラをご覧ください。
※MqlTradeResult構造体についてはコチラをご覧ください。
条件文の中3:ポジションタイプが「売り」の場合の記述を行う
続いてポジションタイプが「売り」の場合の記述に移ります。
//売りの場合
else if(posType==POSITION_TYPE_SELL)
{
double currentPrice=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
double breakEvenPrice=openPrice-(LockProfit*_Point);
double currentProfit=openPrice-currentPrice;
if(currentStop>breakEvenPrice
&&
currentProfit>=BreakEven*_Point
)
{
request.sl=breakEvenPrice;
OrderSend(request,result);
}//if(currentStop<breakEvenPrice
}//else if(posType==POSITION_TYPE_SELL)
}//if(AllowBreakEvenStop==true
}
変数「posType」にはポジションタイプが格納されているので、その値が定数値「POSITION_TYPE_SELL」だった場合はポジションタイプが「売り」という事になります。
if(posType==POSITION_TYPE_SELL)の中1:必要な値取得を行う
if(posType==POSITION_TYPE_SELL)の条件がtrueだった場合の執行文を{}内に記述します。
double型のローカル変数「currentPrice」
double currentPrice=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
double型のローカル変数「currentPrice」には現在値情報を格納します。売りポジションにおける現在値の取得にはSymbolInfoDouble関数の第2引数に「SYMBOL_ASK」を記述する事によって実現します。
double型のローカル変数「breakEvenPrice」
double breakEvenPrice=openPrice-(LockProfit*_Point);
double型のローカル変数「breakEvenPrice」にはブレイクイーブンストップを発動させる際に移動するべきストップロス価格を格納します。
この値は変数「openPrice」即ち約定価格に、input変数「LockProfit」と定義済み変数「_Point」を掛け算したものをマイナスして求めます。
「LockProfit」の値が0の場合は「breakEvenPrice」には約定価格の値が入る事になります。
double型のローカル変数「currentProfit」
double currentProfit=openPrice-currentPrice;
double型のローカル変数「currentProfit」にはポジションの損益情報を格納します。
買いポジションとは逆に、売りポジションの損益情報は、現在値が下がっていくほどに利益が増していくわけですから、計算式は変数「openPrice」即ち約定価格から、変数「currentPrice」即ち現在値を引き算する事によって求めます。
if(posType==POSITION_TYPE_SELL)の中2:ブレイクイーブンストップを発動させる条件文を記述する
次はブレイクイーブンストップを発動させる条件文の記述です。
if(currentStop>breakEvenPrice
&&
currentProfit>=BreakEven*_Point
)
{
request.sl=breakEvenPrice;
OrderSend(request,result);
}//if(currentStop<breakEvenPrice
}//else if(posType==POSITION_TYPE_SELL)
}//if(AllowBreakEvenStop==true
}
if文()の中の最初の条件文
currentStop>breakEvenPrice
についてですが、変数「currentStop」は現在のストップロス価格が格納されています。
変数「breakEvenPrice」は、「if(posType==POSITION_TYPE_SELL)の中1:必要な値取得を行う」セクションで解説したように約定価格にinput変数「LockProfit」を価格ベースに計算した値をマイナスされた値が入っています。
つまり、
現在のストップロスより約定価格(に任意の値をマイナスした価格)の方が小さい場合
と読み解く事ができます。買いポジションとは不等号が逆になった訳ですね。
この条件式を入れることによって、現在のストップロス価格が約定価格(に任意の値をマイナスした価格)と等しくなった時点でそれ以上ストップロス価格を移動できなくします。
論理積 で繋いだもう一つの条件式
currentProfit>=BreakEven*_Point については買いポジションの時と同じです。
二つの条件式がtrueである場合、{}内の発注処理記述に移ります。
{
request.sl=breakEvenPrice;
OrderSend(request,result);
}//if(currentStop<breakEvenPrice
}//else if(posType==POSITION_TYPE_SELL)
}//if(AllowBreakEvenStop==true
}
メンバ変数 .sl に変数「breakEvenPrice」を代入をした上で、OrderSend関数の引数にMqlTradeRequest構造体のインスタンス「request」、MqlTradeResult構造体のインスタンス「result」を記述して終了です。
この部分は買いポジションも売りポジションも記述は同じですね。
これで売りポジションの場合の記述は以上です。
同時に、ブレイクイーブンストップを発動させるための記述も終了となります。
まとめ
今回はブレイクイーブンストップについて解説しました。
ブレイクイーブンストップはトレーリングストップと同様に、相場の変化に応じてストップロスを移動させる概念です。
トレーリングストップと違い、ブレイクイーブンストップはストップロスを移動させる回数は1回のみです。
建値付近にストップロスを移動させる事によって、損失を被る可能性をなくしつつ大きい利益を狙っていく戦略のEA(自動売買プログラム)とは相性が良いかもしれません。
売買条件等は省略してはいますが、今回の解説したサンプルコードの全体は以下のようになります。
//+------------------------------------------------------------------+
//| ブレイクイーブンをブログで説明する用のコード.mq5 |
//| MQL5ssei |
//| https://mqlinvestmentlab.com/ |
//+------------------------------------------------------------------+
#property copyright "MQL5ssei"
#property link "https://mqlinvestmentlab.com/"
#property version "1.00"
//インプット変数の宣言
input bool AllowBreakEvenStop=false;//ブレイクイーブンストップのON/OFF
input int BreakEven=0;//ブレイクイーブンを発動させる損益ポイント
input int LockProfit=0;//約定値に追加するポイント
void OnTick()
{
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
//ブレイクイーブンストップの発動条件を記述
if(AllowBreakEvenStop==true
&&
PositionSelectByTicket(1234)==true
&&
BreakEven>0
)
{
request.action=TRADE_ACTION_SLTP;
request.symbol=_Symbol;
request.tp=0;
long posType=PositionGetInteger(POSITION_TYPE);
double currentStop=PositionGetDouble(POSITION_SL);
double openPrice=PositionGetDouble(POSITION_PRICE_OPEN);
//買いの場合
if(posType==POSITION_TYPE_BUY)
{
double currentPrice=SymbolInfoDouble(_Symbol,SYMBOL_BID);
double breakEvenPrice=openPrice+(LockProfit*_Point);
double currentProfit=currentPrice-openPrice;
if(currentStop<breakEvenPrice
&&
currentProfit>=BreakEven*_Point
)
{
request.sl=breakEvenPrice;
OrderSend(request,result);
}//if(currentStop<breakEvenPrice
}//if(posType==POSITION_TYPE_BUY)
//売りの場合
else if(posType==POSITION_TYPE_SELL)
{
double currentPrice=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
double breakEvenPrice=openPrice-(LockProfit*_Point);
double currentProfit=openPrice-currentPrice;
if(currentStop>breakEvenPrice
&&
currentProfit>=BreakEven*_Point
)
{
request.sl=breakEvenPrice;
OrderSend(request,result);
}//if(currentStop<breakEvenPrice
}//else if(posType==POSITION_TYPE_SELL)
}//if(AllowBreakEvenStop==true
}
//+------------------------------------------------------------------+
今回は以上になります。
次回はブレイクイーブンストップを実装させる為の関数を作っていこうと思います。
※ブレイクイーブンストップについては以下の記事もご参照ください。↓
最後までお読みいただきありがとうございました。
コメント