2014年6月4日水曜日

指定した時間からN分後までの高安をブレークしたらエントリーするブレークアウトEA

指定した期間の最高値/最安値を上抜く/下抜くというルールのEAはよく見かけるので、指定した時間(15時など)から指定した分数間(120分間など)の最高値/最安値を上抜く/下抜いたら、というルールでEAを作ってみました。
あくまでMQL4学習のためのサンプルコードです。今回はこのEAがどの通貨ペアやインターバルに最適なのかなど銘柄の推奨になるような、バックテストや最適化の検証結果には触れません。
サンプルをベースにご自身の好きなように変更してみてください。

■エントリールール

新規買
N時からY分間の最高値を計算。その最高値からZpips上に買いのストップ注文を発注
新規売
N時からY分間の最安値を計算。その最安値からZpips下に売りのストップ注文を発注

■エグジットルール

決済売
新規買価格よりMpips下に損切りのストップ注文を、Npips上に利益確定の指値注文を発注
決済買
新規買価格よりMpips上に損切りのストップ注文を、Npips下に利益確定の指値注文を発注

■コード説明

extern double Lots = 1;
extern int Break = 50;
extern int Stop = 300;
extern int Profit = 300;
extern int StartHour = 15;
extern int StattTime = 0;
extern int CalcMinutes = 120;


Lots - ロット数設定
Break - 最高値/最安値計算後、その上下に加算/減算するピップ数50は5pips
Stop - エントリー約定価格からの損切りpips数で300は30pips
Profit - エントリー約定価格からの利益確定pips数で300は30pips
StartHour - 最高値/最安値の計算開始時間で15は15時
StattTime - 最高値/最安値の計算開始時間で0は15時0分
CalcMinutes - 最高値/最安値の計算開始時間からの経過分数で、最高値/最安値の計算終了時間になる

sl = MarketInfo(Symbol(), MODE_STOPLEVEL)*p;
ブローカーのストップ注文や指値注文の最低幅(ストップレベル)を確認


positionInfo(longPos, shortPos, pendOrders, openPrice);
買いポジション数、売りポジション数、未約定注文、約定価格を計算


if (longPos == 0 && shortPos == 0 && pendOrders == 0){
買いポジション、売りポジション、未約定注文がない場合


if (breakCalcTime()){
ブレークアウト時間内であれば


hh = MathMax(hh,High[0]);
ll = MathMin(ll,Low[0]);

最高値と最安値を計算する


}else{
ブレークアウト時間外であれば


hh = MathMax(hh + breakPoint, Ask + sl);
最高値とストップレベルを比較して高い方を買いのストップ注文価格にする


longTicket = OrderSend(Symbol(), OP_BUYSTOP, Lots, hh , 0, 0, 0, "BBreak", MagicNumber,0,Green);
買いのストップ注文を発注する


ll = MathMin(ll - breakPoint, Bid - sl);
最安値とストップレベルを比較して安い方を売りのストップ注文価格にする


shortTicket = OrderSend(Symbol(), OP_SELLSTOP, Lots, ll , 0, 0, 0, "SBreak", MagicNumber,0,Red);
売りのストップ注文を発注する


if (longPos > 0){
買いのストップ注文が約定して買いポジションを持っている場合


cancelPendingOrders();
売りのストップ注文を取消す


stopPrice = openPrice - stopPoint;
profitPrice = openPrice + profitPoint;

エントリー価格からの損切りと利益確定注文価格の計算


ticketMod = OrderModify(longTicket, openPrice, stopPrice, profitPrice, 0, Blue);
買いポジションに対して、損切りと利益確定注文を発注


if (shortPos > 0){
売りのストップ注文が約定して売りポジションを持っている場合


cancelPendingOrders();
売りのストップ注文を取消す


stopPrice = openPrice + stopPoint;
profitPrice = openPrice - profitPoint;

エントリー価格からの損切りと利益確定注文価格の計算


ticketMod = OrderModify(shortTicket, openPrice, stopPrice, profitPrice, 0, Magenta);
売りポジションに対して、損切りと利益確定注文を発注




以下からはユーザー定義関数で、主に上のメインの計算で使用する
int timeToSeconds(datetime time){
   int tts = TimeHour(time)*60*60 + TimeMinute(time)*60;
   return(tts);
}

時間を分数に変える計算で次のbreakCalcTimeで使う



bool breakCalcTime(){
   datetime tc = TimeCurrent();
   if (timeToSeconds(tc) - (StartHour*60*60 + StattTime*60) >= 0){
      if (timeToSeconds(tc) >= (StartHour*60*60 + StattTime*60) && timeToSeconds(tc) <= StartHour*60*60 + StattTime*60 + CalcMinutes*60){
         return(true);
      }else
         return(false);
   }else{
      if ((timeToSeconds(tc) >= (StartHour*60*60 + StattTime*60) && timeToSeconds(tc) <= 86400) ||
      (timeToSeconds(tc) >= 0 && timeToSeconds(tc) <=  (StartHour*60*60 + StattTime*60 + CalcMinutes*60) - 86400)){
         return(true);
      }else
         return(false);
   }   
}

足の時間がブレークアウト時間内であることを計算して上で使う



void positionInfo(int &longPos, int &shortPos, int &pendOrders, double &openPrice){
   int i;
   for( i=0; i<OrdersTotal(); i++)
   {
     if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
     if(OrderSymbol() != Symbol() && OrderMagicNumber() != MagicNumber) continue;
     if(OrderType() == OP_BUY){
        longPos++;
        openPrice = OrderOpenPrice();
     }else
     if(OrderType() == OP_SELL){
        shortPos++;
        openPrice = OrderOpenPrice();
     }else
        pendOrders++;
   }
}

買いポジション数、売りポジション数、未約定注文、約定価格を計算して上で使う



void cancelPendingOrders(){
   int i;
   bool ticketDel;
   for( i=OrdersTotal()-1;i>=0;i--){
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
      if(OrderSymbol() != Symbol() && OrderMagicNumber() != MagicNumber) continue;
      ticketDel = false;
      if (OrderType() != OP_BUY && OrderType() != OP_SELL)
         ticketDel = OrderDelete( OrderTicket() );

   }
}

未約定注文を取消す関数で上で使う

■コード全体

#property copyright ""
#property link      ""
#property version   "1.00"
#property strict

extern double Lots = 1;
extern int Break = 50;
extern int Stop = 300;
extern int Profit = 300;
extern int StartHour = 15;
extern int StattTime = 0;
extern int CalcMinutes = 120;
extern int MagicNumber = 777;


int barsTotal, longTicket, shortTicket, ticketMod;
double hh = 0.1, ll = 9999.0, p = Point, breakPoint = Break*p, stopPoint = Stop*p, profitPoint = Profit*p, sl = 0;

void OnTick()
  {
  int longPos, shortPos, pendOrders;
  double openPrice, stopPrice, profitPrice;
//---
   sl = MarketInfo(Symbol(), MODE_STOPLEVEL)*p;
   positionInfo(longPos, shortPos, pendOrders, openPrice);
      if (longPos == 0 && shortPos == 0 && pendOrders == 0){
         ticketMod = false;
         if (breakCalcTime()){
            hh = MathMax(hh,High[0]);
            ll = MathMin(ll,Low[0]);
         }else{
            if (hh > 1){
               hh = MathMax(hh + breakPoint, Ask + sl);
               longTicket = OrderSend(Symbol(), OP_BUYSTOP, Lots, hh , 0, 0, 0, "BBreak", MagicNumber,0,Green);
            }
            if (ll < 9998.0){
               ll = MathMin(ll - breakPoint, Bid - sl);
               shortTicket = OrderSend(Symbol(), OP_SELLSTOP, Lots, ll , 0, 0, 0, "SBreak", MagicNumber,0,Red);
            }
         }
      }

      if (longPos > 0){
         cancelPendingOrders();
         stopPrice = openPrice - stopPoint;
         profitPrice = openPrice + profitPoint;
         if (!ticketMod)
            ticketMod = OrderModify(longTicket, openPrice, stopPrice, profitPrice, 0, Blue);
         hh = 0.1; ll = 9999.0;
      }else
      if (shortPos > 0){
         cancelPendingOrders();
         stopPrice = openPrice + stopPoint;
         profitPrice = openPrice - profitPoint;
         if (!ticketMod)  
            ticketMod = OrderModify(shortTicket, openPrice, stopPrice, profitPrice, 0, Magenta);
         hh = 0.1; ll = 9999.0; 
      }       
  }

int timeToSeconds(datetime time){
   int tts = TimeHour(time)*60*60 + TimeMinute(time)*60;
   return(tts);
}

bool breakCalcTime(){
   datetime tc = TimeCurrent();
   if (timeToSeconds(tc) - (StartHour*60*60 + StattTime*60) >= 0){
      if (timeToSeconds(tc) >= (StartHour*60*60 + StattTime*60) && timeToSeconds(tc) <= StartHour*60*60 + StattTime*60 + CalcMinutes*60){
         return(true);
      }else
         return(false);
   }else{
      if ((timeToSeconds(tc) >= (StartHour*60*60 + StattTime*60) && timeToSeconds(tc) <= 86400) ||
      (timeToSeconds(tc) >= 0 && timeToSeconds(tc) <=  (StartHour*60*60 + StattTime*60 + CalcMinutes*60) - 86400)){
         return(true);
      }else
         return(false);
   }   
}

void positionInfo(int &longPos, int &shortPos, int &pendOrders, double &openPrice){
   int i;
   for( i=0; i<OrdersTotal(); i++)
   {
     if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
     if(OrderSymbol() != Symbol() && OrderMagicNumber() != MagicNumber) continue;
     if(OrderType() == OP_BUY){
        longPos++;
        openPrice = OrderOpenPrice();
     }else
     if(OrderType() == OP_SELL){
        shortPos++;
        openPrice = OrderOpenPrice();
     }else
        pendOrders++;
   }
}

void cancelPendingOrders(){
   int i;
   bool ticketDel;
   for( i=OrdersTotal()-1;i>=0;i--){
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
      if(OrderSymbol() != Symbol() && OrderMagicNumber() != MagicNumber) continue;
      ticketDel = false;
      if (OrderType() != OP_BUY && OrderType() != OP_SELL)
         ticketDel = OrderDelete( OrderTicket() );

   }
}

0 件のコメント:

コメントを投稿