変更箇所はたったの2行
トレイリングストップ関数とブレイクイーブン関数はどちらも自作ライブラリに包含されていますが、両方を併用するとトレイリングストップが打ち消されて、ブレイクイーブンが常に適用されてしまう問題があることが分かりました。
トレイリングストップとブレイクイーブンを併用したいという声が複数ありましたので、併用できるようにコードを変更します。
// 変更前
if(NormalizeDouble(oStopLoss, digits) != NormalizeDouble(oPrice + stop, digits)){ // 買い
if(NormalizeDouble(oStopLoss, digits) != NormalizeDouble(oPrice - stop, digits)){ // 売り
// 変更後
if(oStopLoss == 0.0 || NormalizeDouble(oStopLoss, digits) < NormalizeDouble(oPrice + stop, digits)){ // 買い
if(oStopLoss == 0.0 || NormalizeDouble(oStopLoss, digits) > NormalizeDouble(oPrice - stop, digits)){ // 売り
変更前のコードは、現在の損切り価格とブレイクイーブン後の損切り価格が不一致ならば、ブレイクイーブン後の損切り価格に変更するロジックになっています。
この場合、トレイリングストップで損切り価格を随時変更すると、上記条件が成立してしまうので、ブレイクイーブン後の損切り価格に戻っちゃうというわけです。
これを避けるために、変更後のコードでは、現在の損切り価格がブレイクイーブン後の損切り価格よりマイナス方向にあるか、そもそも損切り設定していない(oStopLoss == 0.0)場合のみ、ブレイクイーブン後の損切り価格に変更するようにしています。
これで併用できるようになります。アップロードしているライブラリも近いうちに最新化しますね。
なお、コードの抜粋だけだと分かりにくいでしょうから、変更前後の関数もそれぞれ載せておきます。
//+------------------------------------------------------------------+
//|【関数】ブレイクイーブン(トレイリングストップ関数と併用NG) |
//| |
//|【引数】 IN OUT 引数名 説明 |
//| --------------------------------------------------------- |
//| ○ aMagic マジックナンバー |
//| ○ aMoveExecPips ストップ変更開始位置(pips) |
//| ○ aMoveStopPips ストップ変更幅(pips) |
//| |
//|【戻値】なし |
//| |
//|【備考】なし |
//+------------------------------------------------------------------+
void breakeven(int aMagic, double aMoveExecPips, double aMoveStopPips)
{
for(int i = 0; i < OrdersTotal(); i++){
// オーダーが1つもなければ処理終了
if(OrderSelect(i, SELECT_BY_POS) == false){
break;
}
string oSymbol = OrderSymbol();
// 別EAのオーダーはスキップ
if(oSymbol != Symbol() || OrderMagicNumber() != aMagic){
continue;
}
int oType = OrderType();
// 待機オーダーはスキップ
if(oType != OP_BUY && oType != OP_SELL){
continue;
}
int digits = (int)MarketInfo(oSymbol, MODE_DIGITS);
double oPrice = NormalizeDouble(OrderOpenPrice(), digits);
double oStopLoss = NormalizeDouble(OrderStopLoss(), digits);
double oTakeProfit = NormalizeDouble(OrderTakeProfit(), digits);
int oTicket = OrderTicket();
double exec = NormalizeDouble(aMoveExecPips * gPipsPoint, digits);
double stop = NormalizeDouble(aMoveStopPips * gPipsPoint, digits);
double price;
if(oType == OP_BUY){
price = MarketInfo(oSymbol, MODE_BID);
if(price >= oPrice + exec){
// 何度もmodifyしないためのif文
if(NormalizeDouble(oStopLoss, digits) != NormalizeDouble(oPrice + stop, digits)){
PrintFormatLog(__FILE__, __FUNCTION__, " Attempted to change the stoploss price of the LONG opend order. " + DoubleToStr(oStopLoss, digits) + " -> " + DoubleToStr(oPrice + stop, digits));
orderModifyReliable(oTicket, 0.0, NormalizeDouble(oPrice + stop, digits), oTakeProfit, 0, gArrowColor[oType]);
}
}
}else if(oType == OP_SELL){
price = MarketInfo(oSymbol, MODE_ASK);
if(price <= oPrice - exec){
// 何度もmodifyしないためのif文
if(NormalizeDouble(oStopLoss, digits) != NormalizeDouble(oPrice - stop, digits)){
PrintFormatLog(__FILE__, __FUNCTION__, " Attempted to change the stoploss price of the SHORT opend order. " + DoubleToStr(oStopLoss, digits) + " -> " + DoubleToStr(oPrice - stop, digits));
orderModifyReliable(oTicket, 0.0, NormalizeDouble(oPrice - stop, digits), oTakeProfit, 0, gArrowColor[oType]);
}
}
}
}
}
//+------------------------------------------------------------------+
//|【関数】ブレイクイーブン(トレイリングストップ関数と併用OK) |
//| |
//|【引数】 IN OUT 引数名 説明 |
//| --------------------------------------------------------- |
//| ○ aMagic マジックナンバー |
//| ○ aMoveExecPips ストップ変更開始位置(pips) |
//| ○ aMoveStopPips ストップ変更幅(pips) |
//| |
//|【戻値】なし |
//| |
//|【備考】なし |
//+------------------------------------------------------------------+
void breakeven2(int aMagic, double aMoveExecPips, double aMoveStopPips)
{
for(int i = 0; i < OrdersTotal(); i++){
// オーダーが1つもなければ処理終了
if(OrderSelect(i, SELECT_BY_POS) == false){
break;
}
string oSymbol = OrderSymbol();
// 別EAのオーダーはスキップ
if(oSymbol != Symbol() || OrderMagicNumber() != aMagic){
continue;
}
int oType = OrderType();
// 待機オーダーはスキップ
if(oType != OP_BUY && oType != OP_SELL){
continue;
}
int digits = (int)MarketInfo(oSymbol, MODE_DIGITS);
double oPrice = NormalizeDouble(OrderOpenPrice(), digits);
double oStopLoss = NormalizeDouble(OrderStopLoss(), digits);
double oTakeProfit = NormalizeDouble(OrderTakeProfit(), digits);
int oTicket = OrderTicket();
double exec = NormalizeDouble(aMoveExecPips * gPipsPoint, digits);
double stop = NormalizeDouble(aMoveStopPips * gPipsPoint, digits);
double price;
if(oType == OP_BUY){
price = MarketInfo(oSymbol, MODE_BID);
if(price >= oPrice + exec){
// 何度もmodifyしないためのif文
if(oStopLoss == 0.0 || NormalizeDouble(oStopLoss, digits) < NormalizeDouble(oPrice + stop, digits)){
PrintFormatLog(__FILE__, __FUNCTION__, " Attempted to change the stoploss price of the LONG opend order. " + DoubleToStr(oStopLoss, digits) + " -> " + DoubleToStr(oPrice + stop, digits));
orderModifyReliable(oTicket, 0.0, NormalizeDouble(oPrice + stop, digits), oTakeProfit, 0, gArrowColor[oType]);
}
}
}else if(oType == OP_SELL){
price = MarketInfo(oSymbol, MODE_ASK);
if(price <= oPrice - exec){
// 何度もmodifyしないためのif文
if(oStopLoss == 0.0 || NormalizeDouble(oStopLoss, digits) > NormalizeDouble(oPrice - stop, digits)){
PrintFormatLog(__FILE__, __FUNCTION__, " Attempted to change the stoploss price of the SHORT opend order. " + DoubleToStr(oStopLoss, digits) + " -> " + DoubleToStr(oPrice - stop, digits));
orderModifyReliable(oTicket, 0.0, NormalizeDouble(oPrice - stop, digits), oTakeProfit, 0, gArrowColor[oType]);
}
}
}
}
}
