2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

MetaTraderAdvent Calendar 2022

Day 3

ラインタッチでアラートを鳴らす方法(MQL4

Posted at

目的

MetaTraderで,水平線を引いたとき,現在価格が水平線にタッチしたときアラートを鳴らしたい。

アラートを出す際の考え方

image.png
図のようにNOWという現在価格に対して,上の破線や下の破線と同価格になったときに,アラートを出したいと思います。
上の破線は,下から同価格になったときのみに反応し,下の破線はその逆になるようにしたいため,方向性という考え方を持たせています(ソースコード中のdirection)。

また,アラート制御用のボタンとしてラベルを水平線の近くに配置します。
このラベルは,水平線と紐づけするため,水平線の価格をラベルの説明文に付与してタグ付けしておきます。

例としては,

//水平線を探した後は,水平線にラベルがセットされてるか探す。
if(StringFind(ObjectDescription(ownObjName),objName,0) > -1)

といった具合に,ラベルをチェックし,水平線と紐づけされているか見ています。

基本的には

  1. 水平線を探す
  2. ラベルが水平線と紐づけされているか調べる
  3. ラベルがアラートをオンするか調べる

というのを,価格が更新される都度実施しています。

全ソースコード

#property strict
#property indicator_chart_window

input string msg = "目標価格に到達しました!";//価格到達時のメッセージ
string objName = "HLineTouch";
color backGroundDark = clrYellow;
color backGroundWhite = clrDeepSkyBlue;
extern bool debugMode = false;//サポートモード
string dmsg;
color fontColor;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   dmsg = "\r\n" +msg+" :" + "\r\n";

   ChartSetInteger(0,CHART_EVENT_OBJECT_CREATE, true);

   if(ChartGetInteger(0,CHART_COLOR_BACKGROUND,0) > 800000)
     {
      fontColor = backGroundWhite;
     }
   else
     {
      fontColor = backGroundDark;
     }
   int objNum = ObjectsTotal();
   int i;
   if(objNum > 0)
     {

      //水平線を探す処理
      for(i = 0; i < objNum; i++)
        {
         string ownObjName = ObjectName(i);
         if(ObjectType(ownObjName) == OBJ_HLINE)
           {
            if(debugMode)
               Print("object no setsumei :"+ObjectDescription(ownObjName));
            //水平線を探した後は,水平線にラベルがセットされてるか探す。
            if(StringFind(ObjectDescription(ownObjName),objName,0) > -1)
              {
               float value = (float)ObjectGetDouble(0, ownObjName, OBJPROP_PRICE,0);  //自分の価格を取得
               //long dateTime = ObjectGetInteger(0,ownObjName,OBJPROP_TIME,0);
               moveLabel(ObjectDescription(ownObjName),value,fontColor);
              }



           }
        }
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---

//水平線を探してから,labelを探して,Alert ONを探す
   int objNum = ObjectsTotal();
   int i;
   if(objNum > 0)
     {
      //水平線を探す処理
      for(i = 0; i < objNum; i++)
        {
         string ownObjName = ObjectName(i);
         if(ObjectType(ownObjName) == OBJ_HLINE)
           {
            //説明欄が空白であることが条件
            if(StringFind(ObjectDescription(ownObjName),objName,0)>-1)
              {

               for(int j = 0; j< objNum; j++)
                 {
                  string ownObjName2 = ObjectName(j);
                  if(ObjectType(ownObjName2) == OBJ_LABEL)
                    {
                     if(StringFind(ownObjName2,ObjectDescription(ownObjName),0) > -1)
                       {

                        string srcStr = ObjectGetString(0,ownObjName2,OBJPROP_TEXT,0);
                        double value = ObjectGetDouble(0, ownObjName, OBJPROP_PRICE,0);  //自分の価格を取得
                        moveLabel(ownObjName2,(float)value,fontColor);
                        if(srcStr == "Alert ON")
                          {
                           double nowValue = close[0];
                           string name[];
                           int    sep_num = StringSplit(ownObjName2,',',name);
                           int direction = StrToInteger(name[2]);
                           if(direction * (nowValue - value) <= 0)
                             {
                              Alert("Line Touch!!!");

                              ObjectSetString(0,ownObjName2,OBJPROP_TEXT,"Alert OFF");    // 表示するテキスト
                             }
                          }


                       }


                    }
                 }
              }


           }
        }
     }


//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---


   if(ChartGetInteger(0,CHART_COLOR_BACKGROUND,0) > 800000)
     {
      fontColor = backGroundWhite;
     }
   else
     {
      fontColor = backGroundDark;
     }

   int objNum = ObjectsTotal();
   int i;


//新たにオブジェクトが作成された
   if(id == CHARTEVENT_OBJECT_CREATE)
     {

      if(objNum > 0)
        {
         //水平線を探す処理
         for(i = 0; i < objNum; i++)
           {
            string ownObjName = ObjectName(i);
            if(ObjectType(ownObjName) == OBJ_HLINE)
              {
               //説明欄が空白であることが条件
               if(StringFind(ObjectDescription(ownObjName),objName,0)<0)
                 {
                  //水平線にフラグをセットしてラベルを立てる。
                  datetime time = TimeLocal();
                  float value = (float)ObjectGetDouble(0, ownObjName, OBJPROP_PRICE,0);  //自分の価格を取得
                  string lblName = objName+" "+ TimeToStr(time)+ IntegerToString(TimeSeconds(time)) ;

                  int selectBar = iBarShift(NULL,PERIOD_CURRENT,iTime(NULL,PERIOD_CURRENT,0),false);
                  if(debugMode)
                     Print("時間足制御 バー:"+IntegerToString(selectBar));
                  double selectClose;
                  selectClose = iClose(NULL,PERIOD_CURRENT,selectBar);
                  int q = value < selectClose  ? 1:-1;
                  ObjectSetText(ownObjName,lblName,0,NULL,clrNONE);

                  lblName = lblName+","+DoubleToStr(selectClose ) +","+IntegerToString(q);
                  labelCreate(lblName,value,fontColor);
                 }

              }
           }
        }

     }

   if(id == CHARTEVENT_OBJECT_CLICK)
     {
      if(ObjectType(sparam) == OBJ_LABEL)
        {

         //if(debugMode)
         //   Print(sparam);
         string srcStr = ObjectGetString(0,sparam,OBJPROP_TEXT,0);

         //if(debugMode)
         // Print(srcStr);
         if(srcStr == "Alert OFF")
           {
            ObjectSetString(0,sparam,OBJPROP_TEXT,"Alert ON");    // 表示するテキスト
           }
         else
           {
            ObjectSetString(0,sparam,OBJPROP_TEXT,"Alert OFF");    // 表示するテキスト
           }
        }

     }

   if(id == CHARTEVENT_OBJECT_DRAG || id == CHARTEVENT_CHART_CHANGE)
     {
      if(objNum > 0)
        {
         //水平線を探す処理
         for(i = 0; i < objNum; i++)
           {
            string ownObjName = ObjectName(i);
            if(ObjectType(ownObjName) == OBJ_HLINE)
              {
               //水平線を探した後は,水平線にラベルがセットされてるか探す。
               if(StringFind(ObjectDescription(ownObjName),objName,0) > -1)
                 {
                  float value = (float)ObjectGetDouble(0, ownObjName, OBJPROP_PRICE,0);  //自分の価格を取得
                  //long dateTime = ObjectGetInteger(0,ownObjName,OBJPROP_TIME,0);
                  for(int j = 0; j< objNum; j++)
                    {
                     string ownObjName2 = ObjectName(j);
                     if(ObjectType(ownObjName2) == OBJ_LABEL)
                       {
                        if(StringFind(ownObjName2,ObjectDescription(ownObjName),0) > -1)
                          {

                           int selectBar = iBarShift(NULL,PERIOD_CURRENT,iTime(NULL,PERIOD_CURRENT,0),false);
                           if(debugMode)
                              Print("時間足制御 バー:"+IntegerToString(selectBar));
                           double selectClose;
                           selectClose = iClose(NULL,PERIOD_CURRENT,selectBar);

                           moveLabels(ownObjName2,value,fontColor,(float)selectClose);
                           //ObjectDescription(ownObjName)っていう名前のラベルがあるはず
                          }
                       }
                    }
                 }
              }
           }
        }
     }


  }


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int labelCreate(string myObjName,float value,color col)
  {

   int x,y;
   int chartId = 0;
   ChartTimePriceToXY(0,0,TimeCurrent(),value,x,y);
   ObjectCreate(0,myObjName, // オブジェクト作成
                OBJ_LABEL,                                             // オブジェクトタイプ
                0,                                                       // サブウインドウ番号
                0,                                                       // 1番目の時間のアンカーポイント
                0                                                        // 1番目の価格のアンカーポイント
               );

   ObjectSetInteger(chartId,myObjName,OBJPROP_COLOR,col);    // 色設定

   ObjectSetInteger(chartId,myObjName,OBJPROP_BACK,false);           // オブジェクトの背景表示設定
   ObjectSetInteger(chartId,myObjName,OBJPROP_SELECTABLE,false);     // オブジェクトの選択可否設定
   ObjectSetInteger(chartId,myObjName,OBJPROP_SELECTED,false);      // オブジェクトの選択状態
   ObjectSetInteger(chartId,myObjName,OBJPROP_HIDDEN,true);         // オブジェクトリスト表示設定
   ObjectSetInteger(chartId,myObjName,OBJPROP_ZORDER,0);     // オブジェクトのチャートクリックイベント優先順位


   ObjectSetString(chartId,myObjName,OBJPROP_TEXT,"Alert OFF");    // 表示するテキスト
   ObjectSetString(chartId,myObjName,OBJPROP_FONT,"MS ゴシック");  // フォント

   ObjectSetInteger(chartId,myObjName,OBJPROP_FONTSIZE,14);                   // フォントサイズ
   ObjectSetInteger(chartId,myObjName,OBJPROP_CORNER,CORNER_RIGHT_UPPER);  // コーナーアンカー設定
   ObjectSetInteger(chartId,myObjName,OBJPROP_XDISTANCE,0);                // X座標
   ObjectSetInteger(chartId,myObjName,OBJPROP_YDISTANCE,y+14+10);                 // Y座標

// オブジェクトバインディングのアンカーポイント設定
   ObjectSetInteger(chartId,myObjName,OBJPROP_ANCHOR,ANCHOR_RIGHT_LOWER);

   return 0;

  }
//+------------------------------------------------------------------+
int moveLabel(string myObjName,float value,color col)
  {
   int x,y;
   int chartId = 0;
   ChartTimePriceToXY(0,0,TimeCurrent(),value,x,y);
   ObjectSetInteger(chartId,myObjName,OBJPROP_COLOR,col);    // 色設定
   ObjectSetInteger(chartId,myObjName,OBJPROP_YDISTANCE,y+14+5);                 // Y座標

   return 0;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int moveLabels(string myObjName,float value,color col,float myClose)
  {
   int x,y;
   int chartId = 0;
   string name[];
   int    sep_num = StringSplit(myObjName,',',name);
   string myNewObjName;
   ChartTimePriceToXY(0,0,TimeCurrent(),value,x,y);
   string alertStatus = ObjectGetString(chartId,myObjName,OBJPROP_TEXT);
   int q = value < myClose ? 1:-1;
   myNewObjName = name[0] +","+DoubleToStr(myClose) +","+IntegerToString(q);



   ObjectDelete(0,myObjName);
   labelCreate(myNewObjName,value,col);
   ObjectSetString(chartId,myNewObjName,OBJPROP_TEXT,alertStatus);
   return 0;
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int moveChangeBackColor(string myObjName)
  {

   return 0;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {


   /*
   REASON_PROGRAM      0  EAがExpertRemove関数を呼び出して操作を終了しました。
   REASON_REMOVE       1  プログラムがチャートから削除されました。
   REASON_RECOMPILE    2  プログラムが再コンパイルされました。
   REASON_CHARTCHANGE  3  通貨ペアか時間足が変更されました。
   REASON_CHARTCLOSE   4  チャートが閉じられました。
   REASON_PARAMETERS   5  パラメータがユーザ—によって変更されました。
   REASON_ACCOUNT      6  別のアカウントが有効化されるか、アカウントの設定変更によってサーバへの再接続が発生しました。
   REASON_TEMPLATE     7  新しいテンプレートが適用されました。
   REASON_INITFAILED   8  OnInit関数がゼロ以外の値を返しました。
   REASON_CLOSE        9  MT4のターミナルが閉じられた。
   */
   if(reason == REASON_REMOVE || reason == REASON_CHARTCLOSE)
     {
      int objNum = ObjectsTotal();
      int i;
      if(objNum > 0)
        {
         //水平線を探す処理
         for(i = 0; i < objNum; i++)
           {
            string ownObjName = ObjectName(i);
            if(ObjectType(ownObjName) == OBJ_HLINE)
              {
               //水平線を探した後は,水平線にラベルがセットされてるか探す。
               if(StringFind(ObjectDescription(ownObjName),objName,0) > -1)
                 {
                  float value = (float)ObjectGetDouble(0, ownObjName, OBJPROP_PRICE,0);  //自分の価格を取得
                  //long dateTime = ObjectGetInteger(0,ownObjName,OBJPROP_TIME,0);
                  for(int j = 0; j< objNum; j++)
                    {
                     string ownObjName2 = ObjectName(j);
                     if(ObjectType(ownObjName2) == OBJ_LABEL)
                       {
                        if(StringFind(ownObjName2,ObjectDescription(ownObjName),0) > -1)
                          {

                           ObjectDelete(0,ownObjName2);
                          }
                       }
                    }
                 }
              }
           }
        }
     }

  }


//+------------------------------------------------------------------+

REFERENCEs

なし

さいごに

投資は自己責任!

カレンダー参加者募集してます!

Have a good MQL Life!!!

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?