発注自動化EA 修正版

この記事書いてるの実は12/23なんですけど、10月で公開しとります。

単にカレンダー埋めしたいだけです。

ども、とのです。
Rocksmithでもとりあえず全曲既プレイ埋めしてます。

忙しい忙しいと言って資金を減らす。

年末となると仕事が忙しくなるのが何故かうちの会社のお決まりで、
この3連休も1日潰れてしまっております。

そんなわけでトレードの記録とかは書いていないわけですが、
簡単に結論をまとめると、FXでは勝っててCFDで大幅に負けてトータルマイナスです。

(あかん)

この手法、自動化しているとは言えエリオット波動とタイムサイクルの判断を自分でやらなければならず、
それを仕事中に3年半落ちのiPhone4でリモートデスクトップから確認するという作業に無理があるんですよね~。

でも、まぁ株の方はけっこう利益出てるし…(白目)

もっと自動化したいとなるともはや完全EA化しかないのですが、
うまくいかなかったので詰んでます。

仕事が落ち着くのを待つしかないですかねぇ。

ただ、発注EAはバグ取りとかしてちょっとだけ変わってるので、
それだけ載せておきます。

ただ、最近大幅に変更を加えてその動作がほぼ未検証なので、
もうちょっと後で修正加えますので使用はその後にするか、
自己責任で修正しつつ使ってみてください。

変わったところ

AllowAutoTradeの有効回数を一回こっきりに

一度トレードが終了してから次のシグナルが出るまでの間にAllowAutoTradeをfalseにしておかないと、
シグナルが出た途端にポジションを取ってしまいます。

それはいかんのでポジションが閉じたらAllowAutoTradeを自動でfalseにしてしまっています。

extern bool AllowAutoTradeExt = False;
bool AllowAutoTrade = False;
   // チケットが無くなった場合
   if (IsTrading && !IsTrade) {
      MailOrPrint("Order closed: " + Symbol(), "Order closed: " + Symbol());
      AllowAutoTrade = false;
   }

StopLossLevelにSlippage考慮を追加

直近のトレードなんですが、EUR/USDの売りが1pip差でストップロスに引っかかってから下落しました(;´Д`)
だからというわけではないのですが、デフォルト5pipsのSlippageを追加しております。
OpenLevelにSlippage考慮が入っているのにStopLossに入っていないのも変ですしね。

あと、地味に売りOpenLevelのSlippage考慮が逆になっていたのでそれも修正しました。

        OpenLevel = Low[1] - (Slippage * Point);
        StopLossLevel = High[iHighest(NULL, ShortTimeFrameInt, MODE_HIGH, FirstStopLossBarCount, 1)] + (Ask - Bid) + (Slippage * Point);

画面に手動注文用のデータを表示

この部分さっき動いていないことが分かって修正したばかりなので未検証です。

が、動いていたバージョンで何をやっていたかというと、
たまにAllowAutoTrade時にロット数が足りているのにロット数足りないエラーが出る現象が発生していて、
対処法がわからないのでとりあえず手動で注文していました。

手動注文するのにOP,SL,Lotの情報が必要なので画面に表示していました。

そんなところでしょうか。
あとインデント変えたり?

またちょくちょく修正します。

ソース全文

#property copyright "Tono"

#define SIGNAL_NONE 0
#define SIGNAL_BUY   1
#define SIGNAL_SELL  2
#define SIGNAL_CLOSEBUY 3
#define SIGNAL_CLOSESELL 4

#define DTO_SK 0
#define DTO_SD 1

extern bool AllowAutoTradeExt = False;
bool AllowAutoTrade = False;

extern int FirstStopLossBarCount = 34;

extern string LongTimeFrame  = "D1";
extern int    LongPattern   = 1;

int    LongPeriodRSI  =8;
int    LongPeriodStoch= 5;
int    LongPeriodSK   = 3;
int    LongPeriodSD   = 3;
int    LongMAMode   = 0;

extern string ShortTimeFrame  = "H4";
extern int    ShortPattern   = 1;

int    ShortPeriodRSI  =8;
int    ShortPeriodStoch= 5;
int    ShortPeriodSK   = 3;
int    ShortPeriodSD   = 3;
int    ShortMAMode   = 0;

extern int MagicNumber = 12345;
extern double Risk = 1;
extern int Slippage = 5;

int BarCount;
int Current;
bool TickCheck = False;
bool SignalMail = True;
bool EachTickMode = False;
int LongTimeFrameInt  = 1440;
int ShortTimeFrameInt  =240;
int Order = 0;
int LotDigits;
bool IsTrading = False;

string title;
string message;

double LeastOrderGap;
double LongSK;
double LongSD;
double ShortSK_now;
double ShortSD_now;
double ShortSK_before;
double ShortSD_before;

int SendOrderType,ArrowColor;
double OpenLevel,  StopLossLevel, StopLossValue, Lots;

int i = 0;
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init() {
   BarCount = Bars - 1;

   if (EachTickMode) Current = 0; else Current = 1;
   
   AllowAutoTrade = AllowAutoTradeExt;
   
   LongPeriodRSI  =8;
   LongPeriodStoch= 5;
   LongPeriodSK   = 3;
   LongPeriodSD   = 3;
   ShortPeriodRSI  =8;
   ShortPeriodStoch= 5;
   ShortPeriodSK   = 3;
   ShortPeriodSD   = 3;
   
   for (int i = 0; i < LongPattern; i++) {
      int LongNewRSI = LongPeriodRSI + LongPeriodStoch;
      LongPeriodSD = LongPeriodStoch;
      LongPeriodSK = LongPeriodStoch;
      LongPeriodStoch = LongPeriodRSI;
      LongPeriodRSI = LongNewRSI;
   }  
   
   for (i = 0; i < ShortPattern; i++) {
      int ShortNewRSI = ShortPeriodRSI + ShortPeriodStoch;
      ShortPeriodSD = ShortPeriodStoch;
      ShortPeriodSK = ShortPeriodStoch;
      ShortPeriodStoch = ShortPeriodRSI;
      ShortPeriodRSI = ShortNewRSI;
   }
   
   if (LongTimeFrame=="M1" || LongTimeFrame=="1")     LongTimeFrameInt=PERIOD_M1;
   if (LongTimeFrame=="M5" || LongTimeFrame=="5")     LongTimeFrameInt=PERIOD_M5;
   if (LongTimeFrame=="M15"|| LongTimeFrame=="15")    LongTimeFrameInt=PERIOD_M15;
   if (LongTimeFrame=="M30"|| LongTimeFrame=="30")    LongTimeFrameInt=PERIOD_M30;
   if (LongTimeFrame=="H1" || LongTimeFrame=="60")    LongTimeFrameInt=PERIOD_H1;
   if (LongTimeFrame=="H4" || LongTimeFrame=="240")   LongTimeFrameInt=PERIOD_H4;
   if (LongTimeFrame=="D1" || LongTimeFrame=="1440")  LongTimeFrameInt=PERIOD_D1;
   if (LongTimeFrame=="W1" || LongTimeFrame=="10080") LongTimeFrameInt=PERIOD_W1;
   if (LongTimeFrame=="MN" || LongTimeFrame=="43200") LongTimeFrameInt=PERIOD_MN1;
   if (LongTimeFrameInt= 2) {
            MailOrPrint("Error: " + Symbol() + " too many tickets ", "ticket count : " + TicketCount);
            break;
         }
         Tickets[TicketCount] = OrderTicket();
         TicketCount = TicketCount + 1;
      }
   }
   if (TicketCount == 1) {
       modifyLongTicket(Tickets[0]);
   } else if (TicketCount == 2) {
       modifyWhenTwoTicket(Tickets);
   }
   // チケットが無くなった場合
   if (IsTrading && !IsTrade) {
      MailOrPrint("Order closed: " + Symbol(), "Order closed: " + Symbol());
      AllowAutoTrade = false;
   }
   return(IsTrade);
}

/**
 * 2つのチケットがある場合(注文中もしくは短期ポジ持ち)に注文を修正します。
 */
void modifyWhenTwoTicket(int Tickets[]) {
    double StopLossLevel, OpenLevel;
    for (int i = 0; i < 2; i++) {
        if (modifyLongTicket(Tickets[i])) {
            // 長期ポジションのクローズ条件が成立していたらそちらを優先
            continue;
        }
        OrderSelect(Tickets[i], SELECT_BY_TICKET, MODE_TRADES);
        if(OrderType() == OP_BUY) {
            if(isTrailShortTimeFramePosition(Tickets,  i)) {
                StopLossLevel = Low[1] - Point * Slippage;  
                // ストップロスが近すぎる場合は設置可能な最低限の場所へ移動
                if ((Bid - StopLossLevel) < LeastOrderGap) {
                StopLossLevel = NormalizeDouble(Bid - LeastOrderGap, Digits);
                }
                if(OrderStopLoss() < StopLossLevel) {
                OrderModify(OrderTicket(), OrderOpenPrice(), StopLossLevel, OrderTakeProfit(), 0, MediumSeaGreen);
                }
                // 1つだけ
                break;
            }
        } else if (OrderType() == OP_SELL)  {
            if(isTrailShortTimeFramePosition(Tickets, i)) {
            StopLossLevel = High[1] + Point * Slippage;         
            // ストップロスが近すぎる場合は設置可能な最低限の場所へ移動
            if ((StopLossLevel - Ask) < LeastOrderGap) {
                StopLossLevel = NormalizeDouble(Ask + LeastOrderGap, Digits);
            }
            if(OrderStopLoss() > StopLossLevel) {
                OrderModify(OrderTicket(), OrderOpenPrice(), StopLossLevel , OrderTakeProfit(), 0, DarkOrange);
            }
            // 1つだけ
            break;
            }
        } else if (OrderType() == OP_BUYSTOP)  {
            if(LongSK > LongSD && ShortSK_now > ShortSD_now) {
            OpenLevel = High[1] + Point;    
            StopLossLevel = Low[iLowest(NULL, ShortTimeFrameInt, MODE_LOW, FirstStopLossBarCount, 1)] - Point;
            if(OrderOpenPrice() > OpenLevel) {
                OrderModify(OrderTicket(), OpenLevel, StopLossLevel , OrderTakeProfit(), 0, MediumSeaGreen);
            }
            } else {
            OrderDelete(OrderTicket()); 
            }
        } else if (OrderType() == OP_SELLSTOP)  {
            if(LongSK < LongSD && ShortSK_now < ShortSD_now) {
            OpenLevel = Low[1] - (Slippage * Point);
            StopLossLevel = High[iHighest(NULL, ShortTimeFrameInt, MODE_HIGH, FirstStopLossBarCount, 1)] + (Ask - Bid) + (Slippage * Point);
            if(OrderOpenPrice() < OpenLevel) {
                OrderModify(OrderTicket(), OpenLevel, StopLossLevel, OrderTakeProfit(), 0, DarkOrange);
            }
            } else {
            OrderDelete(OrderTicket());
            }
        }
    }
}

/**
 * 短期ポジションのストップを動かすべきかを調べます。
 * 短期DTオシレーターが2回逆方向へクロスしたかどうかで判定します。(ABC調整パターン形成完了後の反転)
 */
bool isTrailShortTimeFramePosition(int Tickets[], int index){
    if (index == 0) {
        // 1つ目なら2つ目と比べてLotの小さい方を閉じる。
        double OperatingLots = OrderLots();
        OrderSelect(Tickets[0], SELECT_BY_TICKET, MODE_TRADES);
        if (OperatingLots > OrderLots()) {
            return(false);
        } else {
            OrderSelect(Tickets[0], SELECT_BY_TICKET, MODE_TRADES);
        }
    }
    int OpenBar = iBarShift(NULL, ShortTimeFrameInt, OrderOpenTime());
    int ClossCount = 0;
    bool Res = False;
    double SK_now, SD_now, SK_before, SD_before = 0.0;
    for (int i = OpenBar; i >= 0; i--) {
        SK_before = SK_now;
        SD_before = SD_now;
        SK_now = iCustom(NULL, 0, "DT Oscillator", ShortTimeFrame, ShortPeriodRSI, ShortPeriodStoch, ShortPeriodSK, ShortPeriodSD, ShortMAMode,0, i);
        SD_now = iCustom(NULL, 0, "DT Oscillator", ShortTimeFrame, ShortPeriodRSI, ShortPeriodStoch, ShortPeriodSK, ShortPeriodSD, ShortMAMode, 1, i);
        if ((OrderType() == OP_BUY && SK_before > SD_before && SK_now < SD_now) ||
            (OrderType() == OP_SELL && SK_before < SD_before && SK_now > SD_now)) {
            ClossCount = ClossCount + 1;
        }
        if (ClossCount >= 2) {
            Res = True;
            break;
        }
    }
    return(Res);  
}

/**
 * 長期ポジションのストップを移動します。
 * 移動した場合trueを返します。
 */
bool modifyLongTicket(int TicketNo) {
    double StopLossLevel, OpenLevel;
    OrderSelect(TicketNo, SELECT_BY_TICKET, MODE_TRADES);
    if(OrderType() == OP_BUY) {
        if((LongSK > 75 && LongSD > 75) || ((LongSK < LongSD) && !(LongSK < 25 && LongSD < 25))) {
                StopLossLevel = Low[1] - (Slippage * Point);
            // ストップロスが近すぎる場合は設置可能な最低限の場所へ移動
            if ((Bid - StopLossLevel) < LeastOrderGap) {
                StopLossLevel = NormalizeDouble(Bid - LeastOrderGap, Digits);
            }
            if(OrderStopLoss() < StopLossLevel) {
            OrderModify(OrderTicket(), OrderOpenPrice(), StopLossLevel, OrderTakeProfit(), 0, MediumSeaGreen);
            return(True);
            }
        } else {
            // 建値からある程度離れたら建値上にストップを移動して損失を限定する。
            if(OrderStopLoss() < OrderOpenPrice() && OrderOpenPrice() + (iATR(NULL, ShortTimeFrameInt, 14, Current) * 3) < Bid) {
                StopLossLevel = NormalizeDouble(OrderOpenPrice() + Slippage * Point, Digits);
                OrderModify(OrderTicket(), OrderOpenPrice(), StopLossLevel, OrderTakeProfit(), 0, MediumSeaGreen);
                return(True);
            }
        }
    } else if (OrderType() == OP_SELL)  {
        if((LongSK < 25 && LongSD < 25) || ((LongSK > LongSD) && !(LongSK > 75 && LongSD > 75))) {
            StopLossLevel = High[1] + (Slippage * Point);
            // ストップロスが近すぎる場合は設置可能な最低限の場所へ移動
            if ((StopLossLevel - Ask) < LeastOrderGap) {
            StopLossLevel = NormalizeDouble(Ask + LeastOrderGap, Digits);
            }
            if(OrderStopLoss() > StopLossLevel) {
            OrderModify(OrderTicket(), OrderOpenPrice(), StopLossLevel , OrderTakeProfit(), 0, DarkOrange);
            return(True);
            }
        } else {
            // 建値からある程度離れたら建値上にストップを移動して損失を限定する。
            if(OrderStopLoss() > OrderOpenPrice() && OrderOpenPrice() - (iATR(NULL, ShortTimeFrameInt, 14, Current) * 3) > Ask) {
                StopLossLevel = NormalizeDouble(OrderOpenPrice() - Slippage * Point, Digits);
                OrderModify(OrderTicket(), OrderOpenPrice(), StopLossLevel, OrderTakeProfit(), 0, MediumSeaGreen);
                return(True);
            }
        }
    }
    return(False);
}

/**
 * 新規のポジションを建てます。
 */
void checkNewTrade() {
   double OneLot;
   int Ticket;
   if (EachTickMode) TickCheck = True;
      
   OneLot = NormalizeDouble((Lots / 2.0), LotDigits);
   //四捨五入されてしまうので、残りと比較して小さい方を選ぶ
   if (OneLot > (Lots - OneLot)) {
      OneLot = Lots - OneLot;
   }
   if (OneLot <  MarketInfo(Symbol(),MODE_MINLOT)) {
      MailOrPrint("Error: " + Symbol() + " Lots is under minlot", "Lots:" + DoubleToStr(Lots, LotDigits) + "\nMinLot:" +  MarketInfo(Symbol(),MODE_MINLOT));
      return(0);
   }
   Ticket = OrderSend(Symbol(), SendOrderType, OneLot,          OpenLevel, Slippage, StopLossLevel, 0, "New Order:" + MagicNumber, MagicNumber, 0, ArrowColor);
   checkSendOrder(Ticket);
   Ticket = OrderSend(Symbol(), SendOrderType, (Lots - OneLot), OpenLevel, Slippage, StopLossLevel, 0, "New Oorder:" + MagicNumber, MagicNumber, 0, ArrowColor);
   checkSendOrder(Ticket);
   return(0);
}

/**
 * シグナルを生成します。
 */
void makeSignal() {
    //+------------------------------------------------------------------+
    //| Signal Begin(Entry)                                              |
    //+------------------------------------------------------------------+
    
    if (   LongSK > LongSD && !(LongSK > 75 && LongSD > 75)
        && !(ShortSK_now > 75 && ShortSD_now > 75)
        && ShortSK_now > ShortSD_now
        && ShortSK_before< ShortSD_before) {
        Order = SIGNAL_BUY;
    }
    
    if (   LongSK < LongSD && !(LongSK < 25 && LongSD < 25)
        && !(ShortSK_now < 25 && ShortSD_now < 25)
        && ShortSK_now < ShortSD_now
        && ShortSK_before> ShortSD_before) {
        Order = SIGNAL_SELL;
    }
}

/**
 * 注文に関係する価格、ロット情報を計算します。
 */
void calcOrderInfo() {
   
    //+------------------------------------------------------------------+
    //| Signal End                                                       |
    //+------------------------------------------------------------------+
    if (Order == SIGNAL_BUY) {
        OpenLevel = High[1] + (Slippage * Point);
        StopLossLevel = Low[iLowest(NULL, ShortTimeFrameInt, MODE_LOW, FirstStopLossBarCount, 1)] - (Ask - Bid) - (Slippage * Point);
        // ストップロスが近すぎる場合は設置可能な最低限の場所へ移動
        if ((Bid - StopLossLevel) < LeastOrderGap) {
            StopLossLevel = NormalizeDouble(Bid - LeastOrderGap, Digits);
        }
        // 逆指値が近すぎる場合は設置可能な最低限の場所へ移動
        if (OpenLevel - Ask < LeastOrderGap) {
            OpenLevel = NormalizeDouble(Ask + LeastOrderGap, Digits);
        }
        StopLossValue = OpenLevel - StopLossLevel;
        SendOrderType = OP_BUYSTOP;
        ArrowColor = DodgerBlue;
    } else if (Order == SIGNAL_SELL) {
        OpenLevel = Low[1] - (Slippage * Point);
        StopLossLevel = High[iHighest(NULL, ShortTimeFrameInt, MODE_HIGH, FirstStopLossBarCount, 1)] + (Ask - Bid) + (Slippage * Point);
        // ストップロスが近すぎる場合は設置可能な最低限の場所へ移動
        if ((StopLossLevel - Ask)  0) {
     if (OrderSelect(Ticket, SELECT_BY_TICKET, MODE_TRADES)) {
        string type;
        if (OrderType() == OP_BUYSTOP) type = "Buy"; else type = "Sell"; 
        Print(type + " order opened : ", OrderOpenPrice());
        if (SignalMail) MailOrPrint("[Signal Alert]", "[" + Symbol() + "] " + DoubleToStr(Ask, Digits) + " Open " + type);
     }
  } else {
     Print("Error: " + Symbol() + " opening order : ", GetLastError());
  }
}

/**
 * シグナル発生を確認してメールを送信します。
 */
int checkMail(){
   if (Order == SIGNAL_BUY) {
     MakeMessageBuy();
     MailAndArrow(SIGNAL_BUY, "B");
   } else if (Order == SIGNAL_SELL) { 
     MakeMessageSell();
     MailAndArrow(SIGNAL_SELL, "S");
   }   
   return(0);
}

/**
 * 買いシグナルのメッセージを作成します。
 */
void MakeMessageBuy() {
     title = "Buy Signal " + Symbol() + " " + Period();
     message =   "[Buy Signal]\n"
                      + "[" + Symbol() + "] \n"
                      + "Price:" + DoubleToStr(Ask, Digits) + "\n"
                      + MakeHighLow();
}

/**
 * 売りシグナルのメッセージを作成します。
 */
void MakeMessageSell() {
     title = "Sell Signal " + Symbol() + " " + Period();
     message =   "[Sell Signal]\n"
                      + "[" + Symbol() + "] \n"
                      + "Price:" + DoubleToStr(Ask, Digits) + "\n"
                      + MakeHighLow();
}

string MakeHighLow() {
    string highLow = "";
//    for (int i = 1; i < 11; i++) {
//        highLow = (highLow + "high" + i + ":" + High[i] + " low" + i + ":" + Low[i] + "\n");
//    }
    highLow = "OL " + DoubleToStr(OpenLevel, Digits) + "\n SL " + DoubleToStr(StopLossLevel, Digits) + "\n SV " + DoubleToStr(StopLossValue, Digits);
    return (highLow);
}

/**
 * メールを送信し、直近のバーに矢印を置きます。
 */
void MailAndArrow(int signal, string str) {
  MailOrPrint(title, message);
  string name = "arrow" + i;
  ObjectCreate(name, OBJ_TEXT, 0, Time[1], Close[1]);

  if (signal == SIGNAL_BUY) {
     ObjectSetText(name, str , 14, "Verdana", Black);
     ObjectSet(name, OBJPROP_COLOR, Magenta);
  } else {
     ObjectSetText(name, str , 14   , "Verdana", Black);
     ObjectSet(name,  OBJPROP_COLOR, Turquoise);
  }
  i = i + 1;
}

/**
 * メールを送信します。
 * テストモードの時にはPrintを行います。
 */
void MailOrPrint(string ttl, string msg) {
  if (IsTesting()) {
    Print("Mailed. title:" + ttl + " message:" + msg);
  } else {
    SendMail(ttl, msg);
  }
}


void showDebug() {
  string str = "";
  int height = 0;
  
  if (AllowAutoTrade) {
   str = "Auto Trading!";
  } else {
   str = "";
  }
   ObjectCreate("AllowAutoTrade", OBJ_LABEL, 0, 0, 0);
   ObjectSetText("AllowAutoTrade", str, 10, "Verdana", Red);
   ObjectSet("AllowAutoTrade", OBJPROP_CORNER, 0);
   ObjectSet("AllowAutoTrade", OBJPROP_XDISTANCE, 20);
   ObjectSet("AllowAutoTrade", OBJPROP_YDISTANCE, height);

  height += 20;

  str = "OL " + DoubleToStr(OpenLevel, Digits) + " SL " + DoubleToStr(StopLossLevel, Digits) + " SV " + DoubleToStr(StopLossValue, Digits);

  ObjectCreate("LossValue", OBJ_LABEL, 0, 0, 0);
  ObjectSetText("LossValue", str, 10, "Verdana", Black);
  ObjectSet("LossValue", OBJPROP_CORNER, 0);
  ObjectSet("LossValue", OBJPROP_XDISTANCE, 20);
  ObjectSet("LossValue", OBJPROP_YDISTANCE, height);
  
  height += 20;
  str = "Lots:" + DoubleToStr(Lots, 4);

  ObjectCreate("Lots", OBJ_LABEL, 0, 0, 0);
  ObjectSetText("Lots", str, 10, "Verdana", Black);
  ObjectSet("Lots", OBJPROP_CORNER, 0);
  ObjectSet("Lots", OBJPROP_XDISTANCE, 20);
  ObjectSet("Lots", OBJPROP_YDISTANCE, height);
  }
//+------------------------------------------------------------------+

コメント

タイトルとURLをコピーしました