トレーリングイメージ

ここでは、値幅を全て%(パーセンテージ)で算出して決済するEAを作成していきます。

EAでの取引の概要

決済条件

決済条件は、下記の3つです。

・損切り(ストップロス)は、エントリー価格の〇%
・利益確定(テイクプロフィット)はエントリー価格の〇%
・最大含み益の〇%でトレーリングストップ

上昇率と下落率の違い

100円の物の価格が1日10%ずつ上昇した場合、元の価格から100%上昇(200円)になるのにかかる日数は次の通りです。

当日 100円
1日後 110円
2日後 121円
3日後 133.1円
4日後 146.41円
5日後 161.051円
6日後 177.1561円
7日後 194.87171円
8日後 214.358881円

100円の物の価格が1日10%ずつ下落した場合、元の価格から100%下落(0円)になるのにかかる日数は次の通りです。

当日 100円
1日後 90円
2日後 81円
3日後 72.9円
4日後 65.61円
5日後 59.049円
6日後 53.1441円
7日後 47.82969円
8日後 43.046721円
9日後 38.7420489円
10日後 34.86784401円
11日後 31.38105961円
12日後 28.24295365円

1日10%ずつ変動した場合、上昇方向は8日後に100%上昇に到達しますが、下落方向は永久に100%下落には到達しません。

以上のことから、買い取引と売り取引を別々に検証する必要があるので、今回のEAは買いエントリーのみのEAとします。

エントリー条件

決済ロジックの優位性を判断するために、エントリータイミングは、ローソク足の始値時点で〇分の1の確率で買いエントリーとします。

EAを作成

今回のEAの完成形を確認

Dr.EADr.EA

今回作成するEAのコードがこちら。解説はその後するぞい!

extern double  StopLossPer       = 2.0;
extern double  TakeProfitPer     = 5.0;
extern double  TrailingStartPer  = 2.0;
extern double  TrailingStopPer   = 50;

extern double  Lots              = 0.1;
extern int     MagicNumber       = 20191113;

extern int     Probability       = 100;

int OnInit()
{
   MathSrand(GetTickCount()); // 乱数のシード設定
   return(INIT_SUCCEEDED);
}

void OnTick()
{
   int i, ticket;
   double sl, tp, ts;
   
   // 保有ポジションを確認 -------------------------------
   
   int pos_ticket = 0;
   
   for (i=0; i<OrdersTotal(); i++)
   {
      if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false) return;
      if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue;
      
      pos_ticket = OrderTicket();
      break;
   }
   
   // ポジション保有時の処理 -----------------------------
   
   if (pos_ticket > 0)
   {
      if (OrderSelect(pos_ticket, SELECT_BY_TICKET) == false) return;
      
      // トレーリングストップ
      sl = NormalizeDouble(OrderStopLoss(), Digits);
      
      if (Bid >= OrderOpenPrice() * (100 + TrailingStartPer) * 0.01)
      {
         ts = NormalizeDouble(OrderOpenPrice() + (Bid - OrderOpenPrice()) * TrailingStopPer * 0.01, Digits);
         
         if (sl == 0 || sl < ts)
            if (OrderModify(OrderTicket(), 0, ts, OrderTakeProfit(), 0, clrRed) == false)
               Print("OrderModify error.");
      }
   }
   
   // エントリーシグナル生成 -----------------------------
   
   int sign = -1;
   static datetime sign_check_time = 0;
   if (sign_check_time != Time[0])
   {
      sign = MathRand() % Probability;
      sign_check_time = Time[0];
   }
   
   // ポジション無しの時の処理 ---------------------------
   
   if (pos_ticket == 0)
   {
      // エントリー
      if (sign == 0)
      {
         sl = 0;
         tp = 0;
         if (StopLossPer > 0) sl = NormalizeDouble(Ask - Ask * StopLossPer * 0.01, Digits);
         if (TakeProfitPer > 0) tp = NormalizeDouble(Ask +  Ask * TakeProfitPer * 0.01, Digits);
         
         ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask, 0, sl, tp, NULL, MagicNumber, 0, clrBlue);
      }
   }
}

今回のEA【Sample_PercentClose_EA.mq4】をダウンロード

パラメーター設置

必要パラメーターのコードをOnInit()関数の上あたりに追加します。

extern double  StopLossPer       = 2.0;
extern double  TakeProfitPer     = 5.0;
extern double  TrailingStartPer  = 2.0;
extern double  TrailingStopPer   = 50;

extern double  Lots              = 0.1;
extern int     MagicNumber       = 20191113;

extern int     Probability       = 100;
StopLossPer 損切幅 %
TakeProfitPer 利食い幅 %
TrailingStartPer トレーリング開始幅 %
TrailingStopPer トレーリング幅 %
Lots, MagicNumber ロット数, マジックナンバー
Probability エントリー確率 1/〇

OnInit()関数内

OnInit()関数内には、次のように乱数のシードを設定しておきます。

   MathSrand(GetTickCount()); // 乱数のシード設定

OnTick()関数内

OnTick()関数内では、次のような構成にします。

・よく使う変数を宣言
・保有ポジションを確認
・ポジション保有時の処理
・エントリーシグナル生成
・ポジション無しの時の処理

保有ポジションを確認

今回は、買いポジションしか保有しないので次のコードのように、OrderType()関数で取引種別を判定せずに保有ポジションを確認しています。

   int pos_ticket = 0;
   
   for (i=0; i<OrdersTotal(); i++)
   {
      if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false) return;
      if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue;
      
      pos_ticket = OrderTicket();
      break;
   }

ポジション保有時の処理

ポジション保有時の処理として、次のコードのように、トレーリングストップの処理を行います。

   if (pos_ticket > 0)
   {
      if (OrderSelect(pos_ticket, SELECT_BY_TICKET) == false) return;
      
      // トレーリングストップ
      sl = NormalizeDouble(OrderStopLoss(), Digits);
      
      if (Bid >= OrderOpenPrice() * (100 + TrailingStartPer) * 0.01)
      {
         ts = NormalizeDouble(OrderOpenPrice() + (Bid - OrderOpenPrice()) * TrailingStopPer * 0.01, Digits);
         
         if (sl == 0 || sl < ts)
            if (OrderModify(OrderTicket(), 0, ts, OrderTakeProfit(), 0, clrRed) == false)
               Print("OrderModify error.");
      }
   }

エントリーシグナル生成

ポジションの有無にかかわらず、次のコードのように、ローソク足の始値時点でエントリーシグナルを生成させます。

   int sign = -1;
   static datetime sign_check_time = 0;
   if (sign_check_time != Time[0])
   {
      sign = MathRand() % Probability;
      sign_check_time = Time[0];
   }

ローソク足の始値時点で、変数signが0~Probability-1の値になるようにしています。

ポジション無しの時の処理

ポジション無しの時の処理として、シグナル判定からのエントリー注文をしています。

   if (pos_ticket == 0)
   {
      // エントリー
      if (sign == 0)
      {
         sl = 0;
         tp = 0;
         if (StopLossPer > 0) sl = NormalizeDouble(Ask - Ask * StopLossPer * 0.01, Digits);
         if (TakeProfitPer > 0) tp = NormalizeDouble(Ask +  Ask * TakeProfitPer * 0.01, Digits);
         
         ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask, 0, sl, tp, NULL, MagicNumber, 0, clrBlue);
      }
   }

あとがき

価格に対するパーセンテージや、利益幅に対するパーセンテージの算出方法を解説しながらEAを作成しましたが、参考になりましたでしょうか?
不明な点などがあったらお気軽にコメントください^^

次回は、今回のEAにトレーリングストップ発動条件を追加します。