MT4 チャート上にボタンを作る、シダの葉を作る、動画を作る

     

公開日: : 初心者EA自作 , ,

(MQL4)MT4のチャート上にボタンを作るやり方[EA自作]

現在のMT4は比較的いろいろな機能が追加されていて、DLLや拡張ファイルを使わずに、EA単体でボタンやフォームを作ることが可能です。

昔はオブジェクト表示の専用のdllとかが必要で、高額で販売されていたんですけどね~(それだけをやっている会社とかあったんですけど、どうなったことやら…)

 

MT4のチャートのボタン

ボタンをただ表示するだけでなく、
「ボタンを押したら××を実行する」
などのようなインタラクティブな機能を実装することができます。

void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)

ボタン操作は、OnChartEvent内に記述します。

逆に言うとこれまでスルーされていたOnChartEventの唯一と言っても過言ではない出番です。

OnChartEventはティック更新のイベントとは別で、チャート内でイベントが発生した際に呼び出されます。

ボタンは、
色、大きさ、文字、位置など
すべて自由に変更できます。

また、複数のオブジェクト(ボタン)同時に表示させることもできるので、
EAを稼働させつつ、裁量トレードボタンを表示する、
なんていうことも可能になります。

bandicam-2016-12-28-15-47-06-958

オブジェクトの操作は、作る作業と設定する作業に分かれます。

オブジェクトを作る

ObjectCreate(0,buttonID,OBJ_BUTTON,0,100,100);

これはラベルや矢印やテキストと同じなので問題ないと思います。OBJ_BUTTONを指定するだけです。

(現在のチャートにbuttonIDという名前のオブジェクトを作る。オブジェクトの種類はボタン)

オブジェクトのプロパティを設定する

ObjectSetInteger(0,buttonID,OBJPROP_COLOR,clrWhite);

オブジェクトの色を指定する

ObjectSetInteger(0,buttonID,OBJPROP_BGCOLOR,clrGray);

オブジェクトの背景を指定する

ObjectSetInteger(0,buttonID,OBJPROP_XDISTANCE,100); ObjectSetInteger(0,buttonID,OBJPROP_YDISTANCE,100);

オブジェクトの座標を指定する

ObjectSetInteger(0,buttonID,OBJPROP_XSIZE,200); ObjectSetInteger(0,buttonID,OBJPROP_YSIZE,50);

オブジェクトのサイズを指定する

ObjectSetString(0,buttonID,OBJPROP_FONT,"Arial");

オブジェクトにテキストがある場合、フォントを指定する

ObjectSetString(0,buttonID,OBJPROP_TEXT,"Button");

オブジェクトにテキストがある場合、テキストを決める

ObjectSetInteger(0,buttonID,OBJPROP_FONTSIZE,10);

オブジェクトにテキストがある場合のフォントサイズを指定する

ってな感じで一個一個関数を呼び出して設定する必要があります。めんどくさいですね。しかし、これも他のオブジェクトと同じなので特に引っ掛かる要素はないと思います。

 

ボタンが押されている状態

string buttonID="Button";
void OnChartEvent(const int id, 
                  const long &lparam, 
                  const double &dparam, 
                  const string &sparam) 
{
 if(id==CHARTEVENT_OBJECT_CLICK) 
 { 
   string clickedChartObject=sparam; 
   if(clickedChartObject==buttonID) 
   { 
      //ボタンの状態
      bool selected=ObjectGetInteger(0,buttonID,OBJPROP_STATE); 
      Print("ボタンが押されている"); 
      int customEventID; 
      //--- ボタンが押されたら 
      if(selected) 
      {
         //ボタンが押された時の処理
      }
   }
 }
}

id, lparam, dparam, sparamはOnChartEvent上で使える変数です。

ObjectGetInteger(0,buttonID,OBJPROP_STATE)でボタンの状態を取得することができます。押されている場合はif文の中で処理を書けばOkです。

 

 

押したボタンを押してない状態にするには

ボタンが押されているかどうかを判定するにはOnChartEvent内で記述を行います。

先に言っておくと、MQLでのボタンの挙動は押すと勝手に押してない状態に戻る訳ではなく、

「”押された状態”から”押されていない状態”に戻す記述」が必要です。

(ちょっとややこしくなってきましたね。)

つまり、そもそもボタンというものには

押された場合に”押された状態”を維持し続けるタイプのボタンと

押されたら押されていない状態に勝手に戻るボタン

の二種類があるという前提があります。

MQLでは後者がデフォルトになっているので、

押したら”押されていない状態”に戻るボタンを作るには、押されたら1秒後に押されていない状態に勝手に戻る記述を別途しなくてはなりません。

ObjectGetInteger(0,buttonID,OBJPROP_STATE)がtrueの時がボタンが押されている状態です。

 

ボタンが押されていない状態に戻す

ObjectSetInteger(ChartID(),"オブジェクト名",OBJPROP_STATE,0);

これでオブジェクトの状態を元に戻せます。ボタンが押されてすぐにこの状態に戻してしまうと、押されたかどうかユーザーが分からないくらいすぐに戻ってしまうので、少し時間をおいてから(0.5秒とか1秒とか)、ボタンの状態を戻すのが良いと思います。

 

応用版:外部ソフトなしでチャート上に操作パネルを表示する

//+------------------------------------------------------------------+
//|                                            ButtonClickExpert.mq5 |
//|                        Copyright 2009, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2009, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
 
string buttonID="Button";
string labelID="Info";
int broadcastEventID=5000;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Create a button to send custom events
   ObjectCreate(0,buttonID,OBJ_BUTTON,0,100,100);
   ObjectSetInteger(0,buttonID,OBJPROP_COLOR,clrWhite);
   ObjectSetInteger(0,buttonID,OBJPROP_BGCOLOR,clrGray);
   ObjectSetInteger(0,buttonID,OBJPROP_XDISTANCE,100);
   ObjectSetInteger(0,buttonID,OBJPROP_YDISTANCE,100);
   ObjectSetInteger(0,buttonID,OBJPROP_XSIZE,200);
   ObjectSetInteger(0,buttonID,OBJPROP_YSIZE,50);
   ObjectSetString(0,buttonID,OBJPROP_FONT,"Arial");
   ObjectSetString(0,buttonID,OBJPROP_TEXT,"Button");
   ObjectSetInteger(0,buttonID,OBJPROP_FONTSIZE,10);
   ObjectSetInteger(0,buttonID,OBJPROP_SELECTABLE,0);
 
//--- Create a label for displaying information
   ObjectCreate(0,labelID,OBJ_LABEL,0,100,100);
   ObjectSetInteger(0,labelID,OBJPROP_COLOR,clrRed);
   ObjectSetInteger(0,labelID,OBJPROP_XDISTANCE,100);
   ObjectSetInteger(0,labelID,OBJPROP_YDISTANCE,50);
   ObjectSetString(0,labelID,OBJPROP_FONT,"Trebuchet MS");
   ObjectSetString(0,labelID,OBJPROP_TEXT,"No information");
   ObjectSetInteger(0,labelID,OBJPROP_FONTSIZE,20);
   ObjectSetInteger(0,labelID,OBJPROP_SELECTABLE,0);
 
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   ObjectDelete(0,buttonID);
   ObjectDelete(0,labelID);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
 
  }
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Check the event by pressing a mouse button
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      string clickedChartObject=sparam;
      //--- If you click on the object with the name buttonID
      if(clickedChartObject==buttonID)
        {
         //--- State of the button - pressed or not
         bool selected=ObjectGetInteger(0,buttonID,OBJPROP_STATE);
         //--- log a debug message
         Print("Button pressed = ",selected);
         int customEventID; // Number of the custom event to send
         string message;    // Message to be sent in the event
         //--- If the button is pressed
         if(selected)
           {
            message="Button pressed";
            customEventID=CHARTEVENT_CUSTOM+1;
           }
         else // Button is not pressed
           {
            message="Button in not pressed";
            customEventID=CHARTEVENT_CUSTOM+999;
           }
         //--- Send a custom event "our" chart
         EventChartCustom(0,customEventID-CHARTEVENT_CUSTOM,0,0,message);
         ///--- Send a message to all open charts
         BroadcastEvent(ChartID(),0,"Broadcast Message");
         //--- Debug message
         Print("Sent an event with ID = ",customEventID);
        }
      ChartRedraw();// Forced redraw all chart objects
     }
 
//--- Check the event belongs to the user events
   if(id>CHARTEVENT_CUSTOM)
     {
      if(id==broadcastEventID)
        {
         Print("Got broadcast message from a chart with id = "+lparam);
        }
      else
        {
         //--- We read a text message in the event
         string info=sparam;
         Print("Handle the user event with the ID = ",id);
         //--- Display a message in a label
         ObjectSetString(0,labelID,OBJPROP_TEXT,sparam);
         ChartRedraw();// Forced redraw all chart objects
        }
     }
  }
//+------------------------------------------------------------------+
//| sends broadcast event to all open charts                         |
//+------------------------------------------------------------------+
void BroadcastEvent(long lparam,double dparam,string sparam)
  {
   int eventID=broadcastEventID-CHARTEVENT_CUSTOM;
   long currChart=ChartFirst();
   int i=0;
   while(i<CHARTS_MAX)                 // We have certainly no more than CHARTS_MAX open charts
     {
      EventChartCustom(currChart,eventID,lparam,dparam,sparam);
      currChart=ChartNext(currChart); // We have received a new chart from the previous
      if(currChart==-1) break;        // Reached the end of the charts list
      i++;// Do not forget to increase the counter
     }
  }
//+------------------------------------------------------------------+

 

[Q&A]チャート上に複数のボタンオブジェクトを設置して…(MQL4)

Q.

ラベルの上に複数のボタンオブジェクトを設置して、ラベルを選択状態にして、ドラックしたら上に乗っているオブジェクトも移動するようなことは可能でしょうか

A.

チャートオブジェクトの関数群を使えば可能だと思います。build610以降のMT4ではオブジェクト関数群が追加されているので、従来と比較して簡単に実装することができます。

ただ、ちょっと気になることとして、ドラッグというのが ”マウスの左クリックを押し続けた状態で、マウスカーソルを移動させること”を意味していると思うのですが、これはUIを変えた方がよさそうな雰囲気はしています。

 

最近のITの世界ではリアルタイムGUIによる操作が標準になりつつありますが、MQL4はそもそもCをベースにした低級言語のため、GUIにはあまり向いていないという性質があります。

そのため、ちょっと古臭いUI(入力ボックスと)決定ボタンのようなUIにした方がいいんじゃないかな~とは思います。

 

ただ、グラフィカルオブジェクトをいじるということはMQL4の経験がそこそこある方だと思いますので、ドキュメントがあればなんとかなると思います。

 

チャートイベントに関するドキュメントはこちら

https://docs.mql4.com/eventfunctions/eventchartcustom

 

チャート上にシダの葉を出力する(理工系あるある)

今回のフラクタルはインジケーターとしてのフラクタルではなく、理工系で使われるフラクタルの話です。

 

トレードの世界のフラクタルしか知らない人にとっては、フラクタルがそもそも何なのかというところから入るべきですが、要するに自己相似形のことを指します。図で見るとわかりやすいです。

forex-mt4-mt5-ea

リアス式海岸とか、カリフラワーとかシダの葉っぱとかそういうやつです。

相場もフラクタルなところがあって、どの時間枠で見ても同じような形になることがあります。

 

話は変わりますが、筆者が大学に入りたてのときにコンピュータサイエンスの授業がありました。

講義が始まるまでは、てっきりパソコンの基本的な使い方から入るような ”下のレベルの人に合わせた内容”かな、と予想していたのですが、

初日の課題が「じゃあ、TeXでアフィン変換を使ってフラクタルの例としてシダの葉っぱを出力してください」というものでした。

 

当時はできなかったんですよね、これが。友達に手伝ってもらって何とか提出しました。そもそもTeXを触ったことがなかったんですよね。

 

という訳で、今回はたまたまシダの葉っぱを出力するというコラムを見つけたので、乗っかってみようと思います。

 

最終結果は下記のような感じです。

forex-mt4-mt5-ea

#include <cIntBMP.mqh>
double Matrix_a[4] = {0.00,  0.80,  0.20,  -0.25};
double Matrix_b[4] = {0.00,  0.04, -0.26,   0.28};
double Matrix_c[4] = {0.00, -0.04,  0.23,   0.26};
double Matrix_d[4] = {0.26,  0.80,  0.22,   0.24};
double Matrix_e[4] = {0.00,  0.00,  0.00,   0.00};
double Matrix_f[4] = {0.00,  1.60,  1.60,   0.00};
double Matrix_p[4] = {10,     850,    70,     70};

double Probs[4];
cIntBMP bmp;
int scale=100;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   double m=0;
   for(int i=0; i<ArraySize(Matrix_p); i++)
     {
      Probs[i]=Matrix_p[i]+m;
      m=m+Matrix_p[i];
     }

   int XSize=600;
   int YSize=600;

   bmp.Create(XSize,YSize,clrSeashell);

   bmp.DrawRectangle(0,0,XSize-1,YSize-1,clrBlack);

   double x0=0;
   double y0=0;
   double x,y;

   int points=250000;

   for(int i=0; i<points; i++)
     {
      double prb=1000*(rand()/32767.0);
      for(int k=0; k<ArraySize(Matrix_p); k++)
        {
         if(prb<=Probs[k])
           {
            x = Matrix_a[k] * x0 + Matrix_b[k] * y0 + Matrix_e[k];
            y = Matrix_c[k] * x0 + Matrix_d[k] * y0 + Matrix_f[k];
            x0 = x;
            y0 = y;
            int scX = int (MathRound(XSize/2 + (x)*scale));
            int scY = int (MathRound(YSize/2 + (y-5)*scale));
            if(scX>=0 && scX<XSize && scY>=0 && scY<YSize) { bmp.DrawDot(scX,scY,clrForestGreen); }
            break;
           }
        }
     }
   bmp.Save("bmpimg",true);
   bmp.Show(0,0,"bmpimg","Matrix");
//---
   return(INIT_SUCCEEDED);
  }

こちらのmqhファイルのインクルードが必要です。

 

だから何だと言われると、別にこれ以上のことはありません。

これでチャートのフラクタルの分析ができる訳でもなければ、カオスの判定ができる訳でもありません。

 

(MQL4)MT4チャート上で動画を表示するやり方[EA自作]

MT4にはチャート上に画像を表示させる機能があります。
しかし、動画を表示させる機能はありません。

今回は無理やりMT4のチャート上にルーレットを表示し、
そのルーレットを回転させてみます。

アイディアは簡単で、
中心から1度ずつずらした画像を360枚用意し、
それぞれの画像をコマ送りで表示させるだけです。

チャートに表示させる画像のファイル形式はbmpだけなので、
jpg, png, gifの場合は、bmpに変換が必要です。

bmpということは、透明化も無効なので、
ルーレットだけが動いているように見せるには、

ルーレットの背景と、チャートの背景を同色にする必要があります。

今回は、たまたま拾った画像の背景が白だったので、
白背景に統一しました。

360枚の画像を用意する途中で、
数十枚で試したところ、360枚なくても回って見えることが判明したので、
今回は36枚で妥協しました。

画像の保存先は、
データフォルダ¥MQL4¥Images
の中です。

bandicam-2016-12-28-15-37-50-426

画像を何度も呼び出すのは面倒なので、
連番の名前にし、for文で呼び出します。

bandicam-2016-12-28-15-25-20-547

パソコン上で見ると、比較的きれいに回っていたのですが、
gifにする際にコマ割りのタイミングの関係で

少しイビツになってしまいました。

現在のMT4では標準でボタンを設置したりすることもできるので、
これを応用すれば、

チャート上で疑似カジノなんかを作ることも不可能ではないですね。

//+------------------------------------------------------------------+
//|                                                     roulette.mq4 |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
//---
   if( ObjectFind(ChartID(),"BackGround") == -1 ) 
   {
      ObjectCreate(ChartID(),"BackGround",OBJ_RECTANGLE_LABEL,0,0,0);
      ObjectSetInteger(ChartID(),"BackGround",OBJPROP_BGCOLOR,clrWhite ); 
      ObjectSet("BackGround",OBJPROP_CORNER,CORNER_LEFT_UPPER);  
      ObjectSet("BackGround",OBJPROP_XDISTANCE, 0);
      ObjectSet("BackGround",OBJPROP_YDISTANCE, 0);  
      ObjectSetInteger(ChartID(),"BackGround",OBJPROP_XSIZE,3000); 
      ObjectSetInteger(ChartID(),"BackGround",OBJPROP_YSIZE,3000); 
   }
   
   ObjectCreate(ChartID(),"roulette",OBJ_BITMAP_LABEL,0,0,0);
   ObjectSetInteger(ChartID(),"roulette",OBJPROP_CORNER,CORNER_LEFT_UPPER); 
   ObjectSetInteger(ChartID(),"roulette",OBJPROP_XDISTANCE,0);
   ObjectSetInteger(ChartID(),"roulette",OBJPROP_YDISTANCE,0); 
   ObjectSetInteger(ChartID(),"roulette",OBJPROP_XSIZE,300); 
   ObjectSetInteger(ChartID(),"roulette",OBJPROP_YSIZE,300); 
         
   int Count;
   while(true)
   {
      for(int i=1;i<36;i++)
      {
         ObjectSetString(ChartID(),"roulette",OBJPROP_BMPFILE,0,i+".bmp"); 
         WindowRedraw();
         Sleep(5);
      }
      Count++;
      if( Count > 1000 ) break;
   }
   
   
//---
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   ObjectsDeleteAll();
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   //ObjectsDeleteAll();

   
   
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
   
  }
//+------------------------------------------------------------------+

 

 

チャート上にバイナリーオプションのようなボタンパネルを作ってみた

注:これは、MT4のチャート上でバイナリーオプションのような操作パネルを表示させているだけで、実際にバイナリーオプションそのものができる訳ではありません。

以前の記事で、チャート上にボタンを表示するというテーマを扱いました。

今回は、その応用編のサンプルとして、
チャート上に操作パネルを表示しました。

完成版は、
bandicam-2016-12-28-15-54-28-991

こんな感じです。

プットボタン、コールボタン
ロット変更ボタン
時間設定ボタン
を作成しました。

指定時間後に勝手に決済します。

コーディングした当初はOnTimerがありませんでしたが、今はあるので、OnTickではなくOnTimerに書き換えた方が良いかもしれません。

 

(トレードを実行するので、インジケーターではなく、EAです。)

このファイル単体で稼働します。

 

EAのダウンロード

ソースコードのダウンロード

 

 

コメント

  1. 山崎 より:

    ボタンスイッチすごく重宝しています
    しかしスイッチを複数同時に表示させる方法がどうしてもわからなく
    初めてメールさせていただきました

    お手数だとは思いますがどのように作ればいいのか教えてはいただけないでしょうか?
    よろしくお願いします

  2. 管理人 より:

    ボタンオブジェクトはオブジェクトの名前でそれぞれ区別することができます。
    http://fxantenna.com/post-1417/
    を例にすると、
    BUYボタン、SELLボタン、△、▽、各種時間足ボタンがありますが、
    それぞれ名前と座標を変えれば別物として扱えます。


    CreateButton("▲ CALL/BUY",200,70,30*1,30*10,clrRed,20);
    CreateButton("▼ PUT/SELL",200,70,30*1,30*6,clrBlue,20);

    CreateButton("1min", 40,20,20, 30*1+10,clrNavy,8);
    CreateButton("3min", 40,20,20+45*1,30*1+10,clrNavy,8);
    CreateButton("5min", 40,20,20+45*2,30*1+10,clrNavy,8);
    CreateButton("10min",40,20,20+45*3,30*1+10,clrNavy,8);
    CreateButton("60min",40,20,20+45*4,30*1+10,clrNavy,8);

    CreateButton("▲",15,15,110,80,clrNavy,5);
    CreateButton("▼",15,15,110,64,clrNavy,5);
    //CreateButtonはオリジナル関数

    あとはOnChartEvent内で

    if(id==CHARTEVENT_OBJECT_CLICK)
    {
    if(clickedChartObject==IntegerToString(30*1,3)+IntegerToString(30*10,3))
    {
    selected=ObjectGetInteger(ChartID(),IntegerToString(30*1,3)+IntegerToString(30*10,3),OBJPROP_STATE);
    if(selected)
    {
    //ボタン(BUY)が押された時の処理
    }
    }
    if(clickedChartObject==IntegerToString(30*1,3)+IntegerToString(30*6,3))
    {
    selected=ObjectGetInteger(ChartID(),IntegerToString(30*1,3)+IntegerToString(30*6,3),OBJPROP_STATE);
    if(selected)
    {
    //ボタン(SELL)が押された時の処理
    }
    }

    のときのようにifで分けて処理すればOKです。

  3. シホウ より:

    横瀬 様
    お世話になります。シホウと申します。
    ボタンを元に戻す記事が大変参考になりました。

    ここで、もう一つご教授頂ければ有難く存じます。

    市販のあるIndicator(MT4)で、ユーザーに操作ボタンがあります。そのボタンのクリック操作をEAに取り込みたい。ボタンのObjectNameやPropertiesなどの取得はできていますが、力不足でそのボタンに対してEAコードでクリックや押下といった操作の実現はできておりません。

    何かヒントを教えていただけないでしょうか?

Message

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA


関連記事

短いコードでも右肩上がりのグラフにできることの証明(MT4EA)非実用

バックテスト結果   ソースコードはこちら input double L

記事を読む

no image

プログラマ向け自動売買開発アイディア

「MQL4/MQL5は扱えるようになったけど、プログラミングのアイディアがない」というプログラマは比

記事を読む

日経アメリカ株式市場アービトラージ プログラミングで説検証

よく「日本の株式市場は前日のニューヨーク市場の後追いをする」と言われています。実際に裁量トレードする

記事を読む

(MQL4)インジケーターをEA化するやり方[EA自作]

iCustomでZigZagをEA化する(初歩編) インジケーターとiCustom 今回はインジ

記事を読む

株価指数両建て裁定取引のやり方と検証

日経225やダウ、SP500のチャートには強い相関関係があります。かつては「日経はニューヨークの後追

記事を読む

 

上に戻る