2017年5月1日月曜日

[MT4プログラミング]ダブルクリックで指定時間のチャートをテンプレート付きで開く


グリッドの部分をダブルクリックすると、チャートを開いてくれるインジケータです。

複数通貨と時間軸のインジケータ状態を一挙表示するインジケータは結構ありますが、ダブルクリックするとチャートを開いてくれるやつってあまりないですよね?普段は閉じて置いてハーモニックが出たらダブルクリックですぐにチャート表示とかできたら便利かな?と思いできるかどうかのテストも兼ねて作ってみました。

項目の部分がダブルクリックされると、その項目のチャートをテンプレート付きで開きます。

さて、MQLのチャートイベントにはダブルクリック判定はありません。
そこで、チャート更新のClickイベントの時間を保持しておき、ある一定数以下ならダブルクリックと判定するような処理にしています。

//------------------------------------------------------------------
//チャート更新イベント
void OnChartEvent(const int id,         // Event ID 
                  const long& lparam,   // Parameter of type long event 
                  const double& dparam, // Parameter of type double event 
                  const string& sparam  // Parameter of type string events 
){
   if( id == CHARTEVENT_CLICK )
   {
      static uint beforeClick = 0;
      if( GetTickCount() - beforeClick < ChartDoubleClick )
      {
            //ダブルクリック時の処理
      }
      beforeClick = GetTickCount();
   }
}

チャートのオープンとテンプレートの設定は
ChartOpen関数とChartApplyTemplate関数で割と簡単に行えます。

注意が必要なのは通貨名です。基本的に通貨名は6文字で表されますがブローカーによっては、6文字の後ろに文字列が付く場合があるようです。
EURUSD-small
みたいな感じです。

対策としてチャート通貨名が6文字以上なら7文字目以降を開きたいチャートのお尻につけるという処理を行っています。この部分です。
         string postFix = Symbol();
         if( StringLen(postFix) > 6 )
         {
            postFix = StringSubstr(postFix, 6);
         }
         else
         {
            postFix = "";
         }
         
         //チャートを開く
         long chartId = ChartOpen(m_currency.At(row) + postFix, m_period.At(column));


//------------------------------------------------------------------
// ダブルクリックでチャートを開く

#property copyright "Copyright 2017,  Daisuke"
#property link      "http://mt4program.blogspot.jp/"
#property version   "1.00"
#property strict
#property indicator_chart_window

#include <Canvas/Canvas.mqh>
#include <Arrays/ArrayString.mqh>
#include <Arrays/ArrayInt.mqh>
#include <Controls/Button.mqh>

input string sep00 = "";      //【監視対象通貨】
input string cerrency01 = "USDJPY";     // 通貨01
input string cerrency02 = "EURUSD";     // 通貨02
input string cerrency03 = "EURJPY";     // 通貨03
input string cerrency04 = "GBPUSD";     // 通貨04
input string cerrency05 = "EURGBP";     // 通貨05
input string cerrency06 = "GBPJPY";     // 通貨06
input string cerrency07 = "AUDUSD";     // 通貨07
input string cerrency08 = "EURAUD";     // 通貨08
input string cerrency09 = "AUDJPY";     // 通貨09
input string cerrency10 = "USDCAD";     // 通貨10
input string cerrency11 = "EURCAD";     // 通貨11
input string cerrency12 = "USDCHF";     // 通貨12
input string cerrency13 = "EURCHF";     // 通貨13
input string cerrency14 = "";     // 通貨14
input string cerrency15 = "";     // 通貨15
input string cerrency16 = "";     // 通貨16
input string cerrency17 = "";     // 通貨17
input string cerrency18 = "";     // 通貨18
input string cerrency19 = "";     // 通貨19
input string cerrency20 = "";     // 通貨20

input string sep10 = "";      //【監視対象時間軸】
input bool targetM1 = false;          // M1
input bool targetM5 = true;           // M5
input bool targetM15 = true;          // M15
input bool targetM30 = true;          // M30
input bool targetH1 = true;           // H1
input bool targetH4 = true;           // H4
input bool targetD1 = true;           // D1
input bool targetW1 = false;          // W1
input bool targetMN1 = false;         // MN1

input string sep30 = "";      //【描画設定】
input int FontSize = 16;            // フォントサイズ
input int LabelColor = clrWhite;    // ラベル色
input int BackColor = clrBlack;     // 背景色
input int LineColor = clrGray;      // ライン色

input string sep40 = "";      //【チャートオープン設定】
input bool OpenDoubleClick = true;  // ダブルクリックでチャートを開く
input uint ChartDoubleClick = 250;  // ダブルクリック判定時間(ms)
input string TemplateName = "ADX.tpl";     // 定型チャート名

//オブジェクト名
#define OBJECT_NAME "OBJ_OPEN_CHART_"

// グローバル名
string m_globalName = IntegerToString(ChartID()) + "_OPEN_CHART_";

// キャンバス
CCanvas m_canvas;

//通貨一覧
CArrayString m_currency;

//時間一覧
CArrayInt m_period;

//列幅(文字数)
#define COLUMN_CHAR_SIZE 4

//------------------------------------------------------------------
// 初期化
int OnInit()
{
   //2重起動防止
   if( GlobalVariableCheck(m_globalName) )
   {
      Print("open chart double run.");
      return INIT_FAILED;
   }
   GlobalVariableSet(m_globalName, 1);

   ObjectsDeleteAll(ChartID(), 0);
   
   int chartWidth = (int)ChartGetInteger(ChartID(), CHART_WIDTH_IN_PIXELS, 0 );
   int chartHeight = (int)ChartGetInteger(ChartID(), CHART_HEIGHT_IN_PIXELS, 0);
   
   //固定ビットマップを生成する。
   m_canvas.CreateBitmapLabel(0, 0, OBJECT_NAME + "_BACK", 0, 0, chartWidth, chartHeight);
   ObjectSetInteger(0,OBJECT_NAME,OBJPROP_BACK,false); 
   m_canvas.FontSizeSet(10);
   m_canvas.FontAngleSet(0);

   //背景
   m_canvas.FillRectangle(0, 0, chartWidth, chartHeight, COLOR2RGB(clrBlack));

   //設定から通貨一覧と時間一覧を生成する。
   if( cerrency01 != "" ) m_currency.Add(cerrency01);
   if( cerrency02 != "" ) m_currency.Add(cerrency02);
   if( cerrency03 != "" ) m_currency.Add(cerrency03);
   if( cerrency04 != "" ) m_currency.Add(cerrency04);
   if( cerrency05 != "" ) m_currency.Add(cerrency05);
   if( cerrency06 != "" ) m_currency.Add(cerrency06);
   if( cerrency07 != "" ) m_currency.Add(cerrency07);
   if( cerrency08 != "" ) m_currency.Add(cerrency08);
   if( cerrency09 != "" ) m_currency.Add(cerrency09);
   if( cerrency10 != "" ) m_currency.Add(cerrency10);
   if( cerrency11 != "" ) m_currency.Add(cerrency11);
   if( cerrency12 != "" ) m_currency.Add(cerrency12);
   if( cerrency13 != "" ) m_currency.Add(cerrency13);
   if( cerrency14 != "" ) m_currency.Add(cerrency14);
   if( cerrency15 != "" ) m_currency.Add(cerrency15);
   if( cerrency16 != "" ) m_currency.Add(cerrency16);
   if( cerrency17 != "" ) m_currency.Add(cerrency17);
   if( cerrency18 != "" ) m_currency.Add(cerrency18);
   if( cerrency19 != "" ) m_currency.Add(cerrency19);
   if( cerrency20 != "" ) m_currency.Add(cerrency20);

   if( targetM1 ) m_period.Add(PERIOD_M1);
   if( targetM5 ) m_period.Add(PERIOD_M5);
   if( targetM15 ) m_period.Add(PERIOD_M15);
   if( targetM30 ) m_period.Add(PERIOD_M30);
   if( targetH1 ) m_period.Add(PERIOD_H1);
   if( targetH4 ) m_period.Add(PERIOD_H4);
   if( targetD1 ) m_period.Add(PERIOD_D1);
   if( targetW1 ) m_period.Add(PERIOD_W1);
   if( targetMN1 ) m_period.Add(PERIOD_MN1);
   
   if( m_currency.Total() == 0 || m_period.Total() == 0 ) return INIT_PARAMETERS_INCORRECT;
   
   return INIT_SUCCEEDED;
}

//------------------------------------------------------------------
//終了処理
void OnDeinit(const int reason)
{
   ObjectsDeleteAll(ChartID(), 0);
   GlobalVariableDel(m_globalName);
}

//------------------------------------------------------------------
//チャート更新イベント
void OnChartEvent(const int id,         // Event ID 
                  const long& lparam,   // Parameter of type long event 
                  const double& dparam, // Parameter of type double event 
                  const string& sparam  // Parameter of type string events 
){
   if( OpenDoubleClick && id == CHARTEVENT_CLICK )
   {
      static uint beforeClick = 0;
      if( GetTickCount() - beforeClick < ChartDoubleClick )
      {
         int row, column;
         GetPointToCell((int)lparam, (int)dparam, row, column);
         
         string postFix = Symbol();
         if( StringLen(postFix) > 6 )
         {
            postFix = StringSubstr(postFix, 6);
         }
         else
         {
            postFix = "";
         }
         
         //チャートを開く
         long chartId = ChartOpen(m_currency.At(row) + postFix, m_period.At(column));
         
         //テンプレートを開く
         if(TemplateName != "" )
         {
            ChartApplyTemplate(chartId, TemplateName);
         } 
      }
      beforeClick = GetTickCount();
   }
   if( id == CHARTEVENT_CHART_CHANGE )
   {
      DrawCanvas();
   }
}

//------------------------------------------------------------------
//情報を描画する
void DrawCanvas()
{
   int chartWidth = (int)ChartGetInteger(ChartID(), CHART_WIDTH_IN_PIXELS, 0 );
   int chartHeight = (int)ChartGetInteger(ChartID(), CHART_HEIGHT_IN_PIXELS, 0);

   //固定ビットマップを生成する。
   m_canvas.CreateBitmapLabel(0, 0, OBJECT_NAME, 0, 0, chartWidth, chartHeight);
   ObjectSetInteger(0,OBJECT_NAME,OBJPROP_BACK, false); 
   m_canvas.FontSizeSet(FontSize);

   //背景
   m_canvas.FillRectangle(0, 0, chartWidth, chartHeight, COLOR2RGB(BackColor));

   int topMargin = FontSize;
   int leftMargin = FontSize / 2;
   int space = FontSize / 3;
   int fontHarf = FontSize / 2 + 1;
   int row = m_currency.Total();
   int column = m_period.Total();

   m_canvas.TextOut(leftMargin, topMargin, "Open chart " + TemplateName, COLOR2RGB(LabelColor));
   
   for( int i = 0 ; i < row; i++ )
   {
      int y = topMargin + (FontSize + space) * (i + 2);
      m_canvas.TextOut(leftMargin, y, m_currency.At(i), COLOR2RGB(LabelColor));
      m_canvas.Line(leftMargin, y - space / 2, leftMargin + fontHarf * 8 + column * fontHarf * COLUMN_CHAR_SIZE, y - space / 2, COLOR2RGB(LineColor));
   }

   for( int i = 0 ; i < column; i++ )
   {
      int x = leftMargin + fontHarf * 8 + fontHarf * COLUMN_CHAR_SIZE * i;
      m_canvas.TextOut(x, topMargin + (FontSize + space), PeriodToString(m_period.At(i)), COLOR2RGB(LabelColor));
      m_canvas.Line(x - space, topMargin + (FontSize + space), x - space, topMargin + (FontSize + space) * (row + 2), COLOR2RGB(LineColor));
   }
   
   m_canvas.Update();
}

//------------------------------------------------------------------
//座標をセルに変換する。
void GetPointToCell(
   int x,
   int y,
   int &row,
   int &column )
{
   row = -1;
   column = -1;

   int topMargin = FontSize;
   int leftMargin = FontSize / 2;
   int space = FontSize / 3;
   int fontHarf = FontSize / 2 + 1;
   int rowTotal = m_currency.Total();
   int columnTotal = m_period.Total();

   int top = topMargin + (FontSize + space) * 2;
   int bottom = topMargin + (FontSize + space) * (rowTotal + 3);
   int left = leftMargin + fontHarf * 8;
   int right = leftMargin + fontHarf * 8 + fontHarf * COLUMN_CHAR_SIZE * (columnTotal + 1);
   
   if( left <= x && x <= right && top <= y && y <= bottom )
   {
      //行列の計算
      row = (y - top) / (FontSize + space);
      column = (x - left ) / (fontHarf * 4);
   }
}

//------------------------------------------------------------------
//計算イベント
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[])            //スプレット
{

   return rates_total;
}

//------------------------------------------------------------------
//期間を文字列に変更する
string PeriodToString(int timeframe)
{
   if( timeframe == 0 )
   {
      timeframe = Period();
   }
   switch(timeframe)
   {
      case PERIOD_M1:
         return "M1";
      case PERIOD_M5:
         return "M5";
      case PERIOD_M15:
         return "M15";
      case PERIOD_M30:
         return "M30";
      case PERIOD_H1:
         return "H1";
      case PERIOD_H4:
         return "H4";
      case PERIOD_D1:
         return "D1";
      case PERIOD_W1:
         return "W1";
      case PERIOD_MN1:
         return "MN1";
   }
   return "";
}


「MT4でFXを勝ち抜く研究をするブログ」で公開している無料インジケータは、こちらの一覧から。
インジケータ一覧

Twitterもよろしくお願いします。
https://twitter.com/mt4program

ブログランキングにご協力よろしくお願いします。m(._.)m
にほんブログ村 為替ブログ FX テクニカルトレード派へ
にほんブログ村

お約束ですが、本ブログは、投資に対する利益を約束する物ではありません。最終的には自己責任によるご判断よろしくお願いいたします。