ブログタイトルを「FX自動売買システム開発部」から「autoFX」に変更しました!

ブレイクイーブン関数

ブレイクイーブンで損失ゼロに

ある程度利益が出たら、損切りラインを仕掛け価格に移動して、損失ゼロにするブレイクイーブン機能を読者の方から作って欲しいと頼まれましたので早速作ってみました。

一般的なトレイリングストップ関数をベースに作ることができます。

//+------------------------------------------------------------------+
//|【関数】ブレイクイーブン                                          |
//|                                                                  |
//|【引数】 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;
    }

    double digits = 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);

    if(oType == OP_BUY){
      double price = MarketInfo(oSymbol, MODE_BID);

      if(price >= oPrice + exec){
        // 何度もmodifyしないためのif文
        if(NormalizeDouble(oStopLoss, digits) != NormalizeDouble(oPrice + stop, digits)){
          Print("ロングポジションの損切りライン変更:", 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)){
          Print("ショートポジションの損切りライン変更:", DoubleToStr(oStopLoss, digits), " ⇒ ", DoubleToStr(oPrice - stop, digits));
          orderModifyReliable(oTicket, 0.0, NormalizeDouble(oPrice - stop, digits), oTakeProfit, 0, gArrowColor[oType]);
        }
      }
    }
  }
}

最初に、オーダーの有無をチェックした上で、別EAの注文や待機注文は対象外なのでスキップするようにしています。

aMoveExecPipsだけ順行したら(利益が出たら)、仕掛け価格からaMoveStopPipsだけ順行した価格に損切り価格を変更します。aMoveStopPips=0にすれば、ブレイクイーブンになります。汎用性を持たせるために、パラメータ化しています。

ポイントは、何度もmodifyしないように、現在の損切り価格と変更しようとしている損切り価格が同じ場合はmodifyしないようにif文で制御することです。oStopLossとoPriceの比較の部分ですね。これを入れておかないと、「OrderModify error 1」が大量発生することになります。

OrderModify error 1

私の環境ではこれで問題なく動作するのですが、人によっては(FX業者によっては)、このコードでもOrderModify error 1が発生することがあるようです。NormalizeDoubleでMQL4内部の浮動小数点数の丸め誤差を排除しているはずなのに、なぜ発生するのか理由がよく分かっていません。

よく分かりません。
吹き出し

サンプルEA

関数だけではイメージが沸きづらいと思いますので、サンプルEAを載せておきます。1本の足で1回だけエントリーする機能も混ざっていますが、ティックごとにエントリーするのを避けるためだけに入れていますので、無視してください。

//+------------------------------------------------------------------+
//|                                                       Sample.mq4 |
//|                                     Copyright (c) 2015, りゅーき |
//|                                            https://autofx100.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright (c) 2015, りゅーき"
#property link      "https://autofx100.com/"
#property version   "1.00"

//+------------------------------------------------------------------+
//| ライブラリ                                                       |
//+------------------------------------------------------------------+
#include <stderror.mqh>
#include <stdlib.mqh>
#include <WinUser32.mqh>
#include <Original/Basic.mqh>
#include <Original/DateAndTime.mqh>
#include <Original/LotSizing.mqh>
#include <Original/OrderHandle.mqh>
#include <Original/OrderReliable.mqh>

//+------------------------------------------------------------------+
//| EAパラメータ設定情報                                             |
//+------------------------------------------------------------------+
extern string Note01          = "=== General ==================================================";
extern int    MagicNumber     = 7777777;
extern int    SlippagePips    = 5;
extern string Comments        = "";
extern double FixLotSize      = 0.01;

extern string Note02          = "=== Entry ====================================================";
extern string Note02_1        = "--- entry only once per 1 bar --------------------------------";
extern bool   UseEntryPer1Bar = true;

extern string Note03          = "=== Exit =====================================================";
extern string Note03_1        = "--- BreakEven ------------------------------------------------";
extern double MoveExecPips    = 10.0;
extern double MoveStopPips    = 0.0;

//+------------------------------------------------------------------+
//| グローバル変数                                                   |
//+------------------------------------------------------------------+
// 共通
double gPipsPoint     = 0.0;
int    gSlippage      = 0;
color  gArrowColor[6] = {Blue, Red, Blue, Red, Blue, Red}; //BUY: Blue, SELL: Red
int    gPrvBars       = 0;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
  gPipsPoint = currencyUnitPerPips(Symbol());
  gSlippage = getSlippage(Symbol(), SlippagePips);

  gPrvBars = Bars;

  return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
  int currentBars = Bars;

  // -----------------------------------------------------------------
  // 仕切り
  // -----------------------------------------------------------------
  // エントリー位置からMoveExecPips順行したら、エントリー位置から
  // MoveStopPips順行した位置にストップを移動し、それ以降変更しない
  breakeven(MagicNumber, MoveExecPips, MoveStopPips);<br />

  // -----------------------------------------------------------------
  // 仕掛けフィルター(1本の足で1回だけ仕掛ける)
  // -----------------------------------------------------------------
  if(UseEntryPer1Bar){
    // 新しい足を生成した時ではない場合は、仕掛けない
    if(currentBars == gPrvBars){
      gPrvBars = currentBars;
      return;
    }
  }

  // -----------------------------------------------------------------
  // 仕掛け
  // -----------------------------------------------------------------
  // 成行注文
  int ticket = orderSendReliable(Symbol(), OP_BUY, FixLotSize, Ask, gSlippage, 0.0, 0.0, Comments, MagicNumber, 0, gArrowColor[OP_BUY]);

  // 本来はticketの値によって後続の処理を制御する必要があるが、簡単のため、ここでは無視

  gPrvBars = currentBars;
}

MQL4プログラミングの最新記事8件

>完全放ったらかしEA 「AutoEndlessCatchRange」

完全放ったらかしEA 「AutoEndlessCatchRange」

「本業が忙しい!」「でも資産運用したい!」そんなあなたに最適なEAです。兼業トレーダーの方はチャートを毎日みて分析してトレードする時間はなかなか確保できないものです。トレードは本EAに任せて、本業やプライベートの時間をもっと増やしませんか?元々は自分自身のために開発したEAですので、手抜き無しのガチものです。

CTR IMG