English Русский 中文 Español Deutsch Português
preview
MQL5のインタラクティブGUIで取引チャートを改善する(前編):移動可能なGUI (I)

MQL5のインタラクティブGUIで取引チャートを改善する(前編):移動可能なGUI (I)

MetaTrader 5トレーディング | 7 8月 2023, 11:18
292 0
Kailash Bai Mina
Kailash Bai Mina

はじめに

MQL5のエキサイティングな移動可能なGUIの世界へようこそ。このガイドは、取引戦略を向上させるダイナミックでインタラクティブなGUIを作成するための知識を提供します。まずは、GUIインタラクティビティの原動力であるチャートイベントの本質的なコンセプトを理解することから始めましょう。 この基礎をもとに、最初の移動可能なGUIを作ります。

そして次のパートでは、1つのチャートに複数のGUIを効率よく作成する方法(コピーペーストだけではない)に進み、さまざまな要素を追加したりカスタマイズしたりしてGUIを強化し、独自のニーズに合わせてカスタマイズしていきます。これはGUIを移動可能にするための簡単なステップを提供する合理化されたガイドで、今すぐ始めたい人にも対応しています。

この旅が終わる頃には、トレーダーにとって強力なツールであるMQL5で、移動可能なGUIを作成して操作するための貴重なスキルが身に付いていることでしょう。お急ぎの方には、GUIを移動可能にするためのクイックガイドセクションを用意しています。さあ、このエキサイティングな旅を始めましょう。

次のような形でさらに進めていきます。


チャートイベントを解読する:移動可能なGUIの構成要素

現在のところ、EAコードは完全に基本的です。

なぜEAなのか、なぜ指標ではないのかと思われるかもしれません。その理由は、EAが多くの人にとって理解しやすい一方、指標は一部の人を混乱させるかもしれないということです。でも、ご安心ください。指標でも同じ手順に従うことができます。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
   {
//---
    
//---
    return(INIT_SUCCEEDED);
   }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
   {
//---

   }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
   {
//---

   }
//+------------------------------------------------------------------+

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

次に、OnChartEventをよりよく理解するために、OnChartEvent()を使って、上記の完全に基本的なEAですでに知っている他の定義済み関数と比較してみましょう。

定義済み関数 それぞれの役割
OnInit()
初期化で実行:EAがチャート上で初期化(接続)されたときに、一度だけ実行
OnTick()
ティックで実行:チャート上の銘柄が証券会社からティックを受け取ったときに実行(ティックとは価格の更新)
OnDeinit() 初期化解除で実行:EAがチャートから初期化(削除)されると、一度だけ実行

同様にOnChartEvent()は、特定のイベントが発生したときに実行される関数です。さて、ここで話しているのはどんなイベントなのでしょうか。

9つの定義済みイベントがあります(2つのカスタムイベントを除く)

  1. CHARTEVENT_KEYDOWN
  2. CHARTEVENT_MOUSE_MOVE 
  3. CHARTEVENT_OBJECT_CREATE 
  4. CHARTEVENT_OBJECT_CHANGE
  5. CHARTEVENT_OBJECT_DELETE 
  6. CHARTEVENT_CLICK 
  7. CHARTEVENT_OBJECT_CLICK 
  8. CHARTEVENT_OBJECT_DRAG 
  9. CHARTEVENT_OBJECT_ENDEDIT

今回に限り、記事の後半で使用するものについて簡単にまとめます。

  1. CHARTEVENT_KEYDOWN

    チャートウィンドウがフォーカスされているとき(チャートウィンドウのどこかをクリックするだけでフォーカスされます)、OnChartEvent()関数はキーボードのキーがクリックされるたびに実行されます。

    押したままにすると、1秒間に30クリックの割合で何度もキーをクリックすることになります。

    そのキーが押されたとき、私たちにできることは何もありません。どのキーが押されたのかがわかるまでは役に立ちません。では、どのキーが押されたのかを知るにはどうすればよいでしょうか。そこでOnChartEvent()のパラメータが登場します。

    どのようなパラメータについて話しているのでしょうか。OnChartEvent()が実行されたときに得られるパラメータは4つあります。

    1. id -> integer
    2. lparam -> long
    3. dparam -> double
    4. sparam -> string

    これらは簡単に言えば、OnChartEvent()が呼び出されるイベントに関するいくつかのデータであり、OnChartEvent()関数内でこのデータを使用することができます。

    例えば、イベントCHARTEVENT_KEYDOWNの場合、次のようになります。

    • idはCHARTEVENT_KEYDOWNそのものを含むので、OnChartEvent()がどのイベントに対して呼び出されたかを識別し、それに応じて他のパラメータを処理することができます。
    • lparamは、押されたキーのキーコードを含みます。
    • dparamは、キーが押された状態で保持されている間に生成されたキー押下回数を含みますが、キーを保持すると、キーは押された状態にセットされず、代わりに1秒間に30回のクリックがおこなわれます。つまり、この値は常に1です。
    • sparamにはビットマスクが含まれており、簡単に言えば、特定のキーに対して2つの異なる値を表示することで、押された、またはクリックされたといったキーの状態を区別するものです(よりよく理解するために以下の例を参照)。


    キーボードの「A」キーをクリック/長押しすると、OnChartEvent()は次のように実行されます。

    • id = CHARTEVENT_KEYDOWN
    • lparam = 65
    • dparam = 1
    • 最初のクリックはsparam = 30、その後の連続クリックは16414で、毎秒30クリックの割合でAを押したままクリックする


    これで情報が得られたので、if文をいくつか使って、ユーザーがAキーを押したり長押ししたときに何かをすることができます。



  2. CHARTEVENT_MOUSE_MOVE

    まず、booleonチャートプロパティ名CHART_EVENT_MOUSE_MOVEをTrueに設定する必要があります。これは、単純なコード行を使用するだけで簡単に実行できます。

    //Set Chart property CHART_EVENT_MOUSE_DOWN to true 
    ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);

    通常、これは OnInit()で実行することをお勧めします。完了したらCHARTEVENT_MOUSE_MOVEを使用できます。

    マウスがチャートの上に移動するたびに、OnChartEvent()が実行され、paramsに以下の情報が格納されます。

    • id = CHARTEVENT_MOUSE_MOVE
    • lparam = x軸座標
    • dparam = y軸座標
    • sparam = マウスキーの状態を表すビットマスク

     ビットマスクは以下の値を保持します。 

    • マウス左→1
    • マウス右→2
    • マウス中央→16
    • マウス第1Xキー --> 32
    • マウス第2Xキー→64
    • Shiftキー→4
    • Controlキー --> 8

    チャートウィンドウは第4象限にあります。すなわち、X 軸座標(lparam)はチャートウィンドウの左から、Y 軸座標(dparam)はチャートウィンドウの上からです。これで、CHARTEVENT_MOUSE_MOVEを使用する準備が整いました。以下ではこれを使ってGUIを移動可能にしていきます。


  3. CHARTEVENT_CLICK

    特別なプロパティは必要ありません。直接使用できます。つまり、チャート上でマウスがクリックされるたびに、以下のパラメータでOnChartEvent()が実行されます。

    • id = CHARTEVENT_CLICK
    • lparam = x軸座標
    • dparam = y軸座標
    • sparam = "" (空文字列で、有益な情報を提供しない)


    以上の情報を得たので、if文をいくつか使って、ユーザーがチャート上のどこかをクリックしたときに何かをすることができます。


上記では、OnChartEvent()関数が実行する3つのイベント、CHARTEVENT_KEYDOWN、CHART_EVENT_MOUSE_MOVE、CHARTEVENT_CLICKについて説明しました。

OnChartEvent()関数を使ったことがない場合、このすべてが少しややこしく圧倒されるかもしれません。私もそうだったのですが、もっと学び、もっと練習することで、誰でもその段階から抜け出すことができます。GUIを移動可能にするために、以下の知識を実践していきます。ついてきてください。そうすれば、すぐに自信がつき、気分もよくなります。

OnChartEvent()を実行する他のイベントの詳細が必要な場合は、ドキュメントを読むか、下のコメントを参照してください。


初めての移動可能なGUIを作る:ステップバイステップガイド

退屈なことがすべて終わったので、「真の学習」、つまり、学んだ理論を口先だけでなく実際のことに応用することに集中することができます。

このセクションでは、私たちの目標は、見た目が非常にシンプルなGUI、つまり、空白の白い四角形のラベルを作成することです。複雑で見栄えのするGUIを作らないからといって、やる気をなくしてはいけません。物事は常に基本から始まり、そのレベルは指数関数的に上がっていきます。

頑張ってついてきてください。この記事の最後までお付き合いいただき、このすべてが簡単だったと言えるかどうか、試してみてください。ダッシュボードにするので、このGUIをダッシュボードと呼びましょう。では、早速始めましょう。

まず、左から100ピクセル(XDistance)、上から100ピクセル(YDistance)の位置に、200x200(XSize x YSize)の基本矩形ラベルを作成します。 

int OnInit()
   {
    //---
    //Set the name of the rectangle as "TestRectangle"
    string name = "TestRectangle";
    //Create a Rectangle Label Object at (time1, price1)=(0,0)
    ObjectCreate(0, name, OBJ_RECTANGLE_LABEL, 0, 0, 0);
    //Set XDistance to 100px i.e. Distance of Rectangle Label 100px from Left of the Chart Window
    ObjectSetInteger(0, name,OBJPROP_XDISTANCE, 100);
    //Set YDistance to 100px i.e. Distance of Rectangle Label 100px from Top of the Chart Window
    ObjectSetInteger(0, name,OBJPROP_YDISTANCE, 100);
    //Set XSize to 200px i.e. Width of Rectangle Label
    ObjectSetInteger(0, name,OBJPROP_XSIZE, 200);
    //Set YSize to 200px i.e. Height of Rectangle Label
    ObjectSetInteger(0, name,OBJPROP_YSIZE, 200);
    //---
    return(INIT_SUCCEEDED);
   }


EAをチャートに接続すると、作成したレクタングルラベルが次のように表示されるはずです。


図1:シンプルな四角形ラベルの画像

図1:シンプルな四角形ラベル



マウスドラッグでこの部分を移動できるようにすれば、非常に複雑な複数のダッシュボードをチャートウィンドウ上で自由に動かすことができるようになり、非常に優れたインタラクティブなEA/指標を作ることができます。これに最適なアプリケーションの 1 つは、取引アシスタントEAです。

では、移動可能にするためにはどうすればいいのでしょうか。まずは計画を立てましょう。

  • 動かす前の条件
    • マウスがダッシュボード上にある

    • マウスの左ボタンが押されている

  • マウスの左ボタンを押したままマウスを動かすと、ダッシュボードが動く。

  • マウスが両方の条件を満たした時点から、マウスが動いた分だけ動く。

    それでは、移動可能にする計画の基本的な概要を説明しましょう。

    最初の条件として、マウスがダッシュボード上になければなりません。


    マウスのx軸とy軸の座標について、OnChartEvent()を使う必要があります。 思い出してみてください。

    1. チャートプロパティのCHART_EVENT_MOUSE_MOVEをTrueに設定します。

      EAが初期化されたときに真になるように、OnInit()に以下のコードを記述します。

      //Set Chart property CHART_EVENT_MOUSE_DOWN to true
      ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);

    2. OnChartEvent()でマウスの座標を取得できるようになりました。
      void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam)
         {
          //Verify the event that triggered the OnChartEvent was CHARTEVENT_MOUSE_MOVE because we only want to execute out code when that is the case
          if(id == CHARTEVENT_MOUSE_MOVE)
             {
              //Comment the X and Y Axes Coordinates
              Comment("X: ", lparam, "\nY: ", dparam);
             }
         }

      OnChartEvent()では、まず、idが CHARTEVENT_MOUSE_MOVEと等しいかどうかを確認する単純なif文を使用して、OnChartEventをトリガーしたイベントがCHARTEVENT_MOUSE_MOVEであることを確認します。

      次に、X軸とY軸の座標(チャートウィンドウの左上隅に白色で少し小さなフォントで表示されます)を次のようにコメントします。 

      図2:X,Y座標コメントの画像

      図2:X,Y座標コメント

    次に、マウスがダッシュボード上にあるかどうかを調べるロジックについて以下の画像を参照してください: 

    図3:数式可視化の画像

    図3:数式の可視化





    マウスがダッシュボード上にあるかどうかを調べるには、次をおこないます。

    • X >= XDistance             --> X>=100
    • X <= XDIstance + XSize --> X<=300
    • Y >= YDistance             --> Y>=100
    • Y <= YDistance + YSize --> Y>=300

    コードに変換すると、次のようになります。

    void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam)
      {
       //Verify the event that triggered the OnChartEvent was CHARTEVENT_MOUSE_MOVE because we only want to execute out code when that is the case
       if(id == CHARTEVENT_MOUSE_MOVE)
         {
          //define X, Y, XDistance, YDistance, XSize, YSize
          int X = (int)lparam;
          int Y = (int)dparam;
    
          string name = "TestRectangle";
          int XDistance = ObjectGetInteger(0, name, OBJPROP_XDISTANCE); //Should be 100 initially as we set it in OnInit()
          int YDistance = ObjectGetInteger(0, name, OBJPROP_YDISTANCE); //Should be 100 initially as we set it in OnInit()
          int XSize = ObjectGetInteger(0, name, OBJPROP_XSIZE); //Should be 200 initially as we set it in OnInit()
          int YSize = ObjectGetInteger(0, name, OBJPROP_YSIZE); //Should be 200 initially as we set it in OnInit()
          
          //Check Mouse on Dashboard condition
          if(X >= XDistance && X <= XDistance + XSize && Y >= YDistance && Y <= YDistance + YSize)
            {
             //Comment the X and Y Axes Coordinates and Mouse is on the dashboard
             Comment("X: ", lparam, "\nY: ", dparam, "\nMouse is on the Dashboard");
            }
          else
            {
             //Comment the X and Y Axes Coordinates and Mouse is not on the dashboard
             Comment("X: ", lparam, "\nY: ", dparam, "\nMouse is NOT on the Dashboard");
            }
    
         }
      }

    変数X、Y、name、XDistance、YDistance、XSize、YSizeを定義しました。Xはlparamから、Yはdparamから、nameは上で設定した文字列名だけ、XDistance、YDistance、XSize、YSizeはObjectGetInteger()関数を使って取得しました。

    ここでの目標は、ダッシュボードをスムーズに動かすことです。他のことを心配するのはそれからです。

    結果:

    図4:マウスがダッシュボード上にあるGIF

    図4:ダッシュボードにあるマウス


    ダッシュボードにマウスが乗ると、コメントが変わるのがお分かりいただけるとおもいます。ロジックが機能し、マウスがダッシュボード上にあるかどうかがわかりました。

    マウスの左ボタンがクリックされた場合、sparamは1であるという理論を思い出してください。

    void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam)
      {
       //Verify the event that triggered the OnChartEvent was CHARTEVENT_MOUSE_MOVE because we only want to execute out code when that is the case
       if(id == CHARTEVENT_MOUSE_MOVE)
         {
          //define X, Y, XDistance, YDistance, XSize, YSize
          int X = (int)lparam;
          int Y = (int)dparam;
          int MouseState = (int)sparam;
    
          string name = "TestRectangle";
          int XDistance = ObjectGetInteger(0, name, OBJPROP_XDISTANCE); //Should be 100 initially as we set it in OnInit()
          int YDistance = ObjectGetInteger(0, name, OBJPROP_YDISTANCE); //Should be 100 initially as we set it in OnInit()
          int XSize = ObjectGetInteger(0, name, OBJPROP_XSIZE); //Should be 200 initially as we set it in OnInit()
          int YSize = ObjectGetInteger(0, name, OBJPROP_YSIZE); //Should be 200 initially as we set it in OnInit()
    
          //Check Dashboard move conditions
          if(X >= XDistance && X <= XDistance + XSize && Y >= YDistance && Y <= YDistance + YSize && MouseState == 1)
            {
             //Comment that the dashboard is ready to move
             Comment("Dashboard is ready to move.");
            }
          else
            {
             //Comment that the dashboard is not ready to move
             Comment("Dashboard is NOT ready to move.");
            }
          
         }
      }

    変数に

    int MouseState = (int)sparam; //To get the mouse state: 1 -> Mouse Left Button Down (You can check the other above)
    

    という条件を追加して、if文の中で、

    if(MouseState == 1) // This insures that Mouse Left button in pressed

    という条件を追加して、コメントを少し変更しました。

    これで、マウスの左ボタンがダッシュボード上で押された状態になるたびに、「Dashboard is ready to move」というコメントが表示され、そうでなければ 「Dashboard is NOT ready to move」というコメントが表示されるようになります。

    実際に見てみましょう。

    図5:ダッシュボードは移動可能GIF

    図5:ダッシュボードは移動可能


    マウス左ボタンを押したときのコメントの変化を見ましょう。


    これでダッシュボードを動かす準備は整いました。試してみましょう。

    ダッシュボードがマウスで移動することはわかっていますが、ダッシュボードの位置を変更するにはどうすればよいでしょうか。もちろん、XDistanceとYDistanceのプロパティを使用します。XDistanceとYDistanceを変更するのですが、どのくらい変更するのでしょうか。ダッシュボードはマウスと一緒に動くので、ダッシュボードもマウスと同じように動くはずです。

    では、マウスはどれくらい動いたのでしょうか。それは調べる必要がありますが、どうやってでしょうか。多数の質問がありますが、これらの質問から計画を立てましょう。

    計画 

    • MLB(マウスの左ボタン)を押した後、マウスがどれだけ動いたかを調べる。
    • マウスの移動量と同じだけダッシュボードを移動させる。
    • MLBが押し下げられるまでこれをおこない、その後ダッシュボードを動かすのを止める。

    一歩ずつ進んでいきましょう。

    現在のマウスの位置は常に正しく取得できるので、MLBが最初にクリックされたときのマウスの位置を保存したらどうでしょうか。

    MLBが押されたかどうかは、sparamを格納するMouseState変数から知ることができます。

    以下は、MLBの初回クリックを検出するコードです。 

    int previousMouseState = 0;
    //+------------------------------------------------------------------+
    //|                                                                  |
    //+------------------------------------------------------------------+
    void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam)
      {
       //Verify the event that triggered the OnChartEvent was CHARTEVENT_MOUSE_MOVE because we only want to execute out code when that is the case
       if(id == CHARTEVENT_MOUSE_MOVE)
         {
          int MouseState = (int)sparam;
          
          bool mblDownFirstTime = false;
          if(previousMouseState == 0 && MouseState == 1) {
             mblDownFirstTime = true;
          }
          
          previousMouseState = MouseState;
         }
      }
    //+------------------------------------------------------------------+

    見やすく、わかりやすくするために、他のものは取り除きました。このメソッドは、EAのトレーリング関数を作成したり、新しいバーを検出したりする際によく使用されます。

    それを分解してみましょう。

    1. int previousMouseState = 0;

      グローバル空間上でpreviousMouseStateという名前のint変数を宣言し、それを0に設定します。この変数には、前回CHARTEVENT_MOUSE_MOVEイベントが発生したときのMouseState値が格納されます。 辛抱すればすぐにわかります。


    2. int previousMouseState = 0;

      グローバル空間上でpreviousMouseStateという名前のint変数を宣言し、それを0に設定します。この変数には、前回CHARTEVENT_MOUSE_MOVEイベントが発生したときのMouseState値が格納されます。 辛抱すればすぐにわかります。

    3. int MouseState = (int)sparam;   
      bool mblDownFirstTime = false;
      if(previousMouseState == 0 && MouseState == 1) {
         mblDownFirstTime = true;
      }


      まず、MouseStateを1つ宣言し、それをマウスの状態を含むsparamと等しく設定します。次に、mblDownFirstTimeというbool変数を宣言し、そのデフォルト値をfalseに設定します。

      2つの条件が満たされているかどうかを確認します。1つはpreviousMouseStateが0(MLB Up、マウスボタンが押されていない)であること、かつ(&&) MouseStateが1(MLB Down)であることです。

      この条件は基本的に、MLBが初めて押下されたか否かを確認するもので、初めて押下されたことが分かれば、後でこの変数を使えるように、mblDownFirstTimeをtrueに設定します。


    これで最初のステップは完了したので、ステップ2とステップ3に移ります。

    さて、この先に進む方法はたくさんありますが、非常にスムーズで繊細な動きを得るために、以下のステップを踏みます。

    1. ユーザーがダッシュボードでMLBをクリックするとtrueに設定される、movingStateというブール値のグローバル変数を作成します。また、MLB Down X、 MLB Down Y、 MLB Down XDistance、 MLB Down YDistanceも宣言します(ここで、MLB Downとは、MLBが最初に押下されたことを意味します)。これらはダッシュボードの位置を変更するために必要になります。
    2. movingStateがtrueの間、マウスの初期位置(MLBが最初にクリックされた時)からのマウスの位置の変化に応じてダッシュボードの位置を更新します。
    3. movingStateがtrueの間、マウスの初期位置(MLBが最初にクリックされた時)からのマウスの位置の変化に応じてダッシュボードの位置を更新します。


    新しいコード

    int previousMouseState = 0;
    int mlbDownX = 0;
    int mlbDownY = 0;
    int mlbDownXDistance = 0;
    int mlbDownYDistance = 0;
    bool movingState = false;
    //+------------------------------------------------------------------+
    //|                                                                  |
    //+------------------------------------------------------------------+
    void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam)
      {
    //Verify the event that triggered the OnChartEvent was CHARTEVENT_MOUSE_MOVE because we only want to execute out code when that is the case
       if(id == CHARTEVENT_MOUSE_MOVE)
         {
          if(previousMouseState == 0 && MouseState == 1)
            {
             mlbDownX = X;
             mlbDownY = Y;
             mlbDownXDistance = XDistance;
             mlbDownYDistance = YDistance;
    
             if(X >= XDistance && X <= XDistance + XSize && Y >= YDistance && Y <= YDistance + YSize)
               {
                movingState = true;
               }
            }
    
          if(movingState)
            {
             ChartSetInteger(0, CHART_MOUSE_SCROLL, false);
             ObjectSetInteger(0, name, OBJPROP_XDISTANCE, mlbDownXDistance + X - mlbDownX);
             ObjectSetInteger(0, name, OBJPROP_YDISTANCE, mlbDownYDistance + Y - mlbDownY);
             ChartRedraw(0);
            }
    
          if(MouseState == 0)
            {
             movingState = false;
             ChartSetInteger(0, CHART_MOUSE_SCROLL, true);
            }
    
          previousMouseState = MouseState;
         }
      }
    //+------------------------------------------------------------------+

     もっと簡単に説明しましょう。

    1. int mlbDownX = 0;
      int mlbDownY = 0;
      int mlbDownXDistance = 0;
      int mlbDownYDistance = 0;
      bool movingState = false;

      グローバルスペースにいくつかの変数を作りましたが、それ以外のpreviousMouseStateについてはすでに話しました。

      • mlbDownX -> MLBが最初に押下されたときのX座標を保持する。
      • mlbDownY -> MLBが最初に押下された時のY座標を保持する。
      • mlbDownXDistance -> 最初にMLBが押された時のダッシュボードのXDistanceプロパティを保持する。
      • mlbDownYDistance -> 最初にMLBが押された時のダッシュボードのYDistanceプロパティを保持する。    
      • movingState -> ダッシュボードを動かしている場合はtrue、そうでない場合はfalseを保持する。

      if(previousMouseState == 0 && MouseState == 1)
        {
         mlbDownX = X;
         mlbDownY = Y;
         mlbDownXDistance = XDistance;
         mlbDownYDistance = YDistance;
      
         if(X >= XDistance && X <= XDistance + XSize && Y >= YDistance && Y <= YDistance + YSize)
          {
           movingState = true;
          }
        }



      まず、それが最初のMLBクリックであるかどうかを確認します。もしそうなら、mlbDownX, mlbDownY, mlbDownXDistance, mlbDownYDistanceをそれぞれ現在のX, Y, XDistance, YDistanceに更新します。これらは後で使用します。

      そして、MLBがダッシュボード上で押下されているかどうかをチェックし、ダッシュボード上で押下されていれば、movingStateをtrueに設定します。

    2. if(movingState)
        {
         ChartSetInteger(0, CHART_MOUSE_SCROLL, false);
         ObjectSetInteger(0, name, OBJPROP_XDISTANCE, mlbDownXDistance + X - mlbDownX);
         ObjectSetInteger(0, name, OBJPROP_YDISTANCE, mlbDownYDistance + Y - mlbDownY);
         ChartRedraw(0);
        }

      movingStateがtrueの場合、XDistanceとYDistanceを修正します。

      X - mlbDownX // Change in Mouse X Position form the initial click
      and 
      Y - mlbDownY // Change in Mouse X Position form the initial click

      上記は最初のクリックからのマウス位置の変化であり、それらをmlbDownXDistanceとmlbDownYDistanceに追加して新しいダッシュボードの位置を取得します。考えてみれば当然のことです。

      また、CHART_MOUSE_SCROLLチャートプロパティをfalseに設定し、グラフがダッシュボードと一緒に移動しないようにします。その後、非常に滑らかで微妙な動きを得るために、もちろんグラフを再描画します。

    3. if(MouseState == 0)
        {
         movingState = false;
         ChartSetInteger(0, CHART_MOUSE_SCROLL, true);
        }

      これでMLBを終了します。つまりMouseStateが0になります。

      次にmovingStateをfalseに設定し、CHART_MOUSE_SCROLLを再びtrueに設定してチャートの移動を許可します。



    これで、コードは完成しました。第1部はほぼ完了しです。ここまでついてきた方、お疲れさまでした。

    次が完全なコードです。

    //+------------------------------------------------------------------+ //| Expert initialization function                                   | //+------------------------------------------------------------------+ int OnInit()   { //---    //Set the name of the rectangle as "TestRectangle"    string name = "TestRectangle";    //Create a Rectangle Label Object at (time1, price1)=(0,0)    ObjectCreate(0, name, OBJ_RECTANGLE_LABEL, 0, 0, 0);    //Set XDistance to 100px i.e. Distance of Rectangle Label 100px from Left of the Chart Window    ObjectSetInteger(0, name, OBJPROP_XDISTANCE, 100);    //Set YDistance to 100px i.e. Distance of Rectangle Label 100px from Top of the Chart Window    ObjectSetInteger(0, name, OBJPROP_YDISTANCE, 100);    //Set XSize to 200px i.e. Width of Rectangle Label    ObjectSetInteger(0, name, OBJPROP_XSIZE, 200);    //Set YSize to 200px i.e. Height of Rectangle Label    ObjectSetInteger(0, name, OBJPROP_YSIZE, 200); //Set Chart property CHART_EVENT_MOUSE_DOWN to true    ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true); //---    return(INIT_SUCCEEDED);   } //+------------------------------------------------------------------+ //| Expert deinitialization function                                 | //+------------------------------------------------------------------+ void OnDeinit(const int reason)   { //---   } //+------------------------------------------------------------------+ //| Expert tick function                                             | //+------------------------------------------------------------------+ void OnTick()   { //---   } //+------------------------------------------------------------------+ //Declare some global variable that will be used in the OnChartEvent() function int previousMouseState = 0; int mlbDownX = 0; int mlbDownY = 0; int mlbDownXDistance = 0; int mlbDownYDistance = 0; bool movingState = false; //+------------------------------------------------------------------+ //|                                                                  | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam)   { //Verify the event that triggered the OnChartEvent was CHARTEVENT_MOUSE_MOVE because we only want to execute out code when that is the case    if(id == CHARTEVENT_MOUSE_MOVE)      {       //define X, Y, XDistance, YDistance, XSize, YSize       int X = (int)lparam;       int Y = (int)dparam;       int MouseState = (int)sparam;       string name = "TestRectangle";       int XDistance = (int)ObjectGetInteger(0, name, OBJPROP_XDISTANCE); //Should be 100 initially as we set it in OnInit()       int YDistance = (int)ObjectGetInteger(0, name, OBJPROP_YDISTANCE); //Should be 100 initially as we set it in OnInit()       int XSize = (int)ObjectGetInteger(0, name, OBJPROP_XSIZE); //Should be 200 initially as we set it in OnInit()       int YSize = (int)ObjectGetInteger(0, name, OBJPROP_YSIZE); //Should be 200 initially as we set it in OnInit()       if(previousMouseState == 0 && MouseState == 1) //Check if this was the MLB first click         {          mlbDownX = X; //Set mlbDownX (Variable that stores the initial MLB X location) equal to the current X          mlbDownY = Y; //Set mlbDownY (Variable that stores the initial MLB Y location) equal to the current Y          mlbDownXDistance = XDistance; //Set mlbDownXDistance (Variable that stores the initial XDistance i.e. Width of the dashboard) equal to the current XDistance          mlbDownYDistance = YDistance; //Set mlbDownYDistance (Variable that stores the initial YDistance i.e. Height of the dashboard) equal to the current YDistance          if(X >= XDistance && X <= XDistance + XSize && Y >= YDistance && Y <= YDistance + YSize) //Check if the click was on the dashboard            {             movingState = true; //If yes the set movingState to True            }         }       if(movingState)//if movingState is true, Update the Dashboard position         {          ChartSetInteger(0, CHART_MOUSE_SCROLL, false);//Restrict Chart to be moved by Mouse          ObjectSetInteger(0, name, OBJPROP_XDISTANCE, mlbDownXDistance + X - mlbDownX);//Update XDistance to: mlbDownXDistance + (X - mlbDownX)          ObjectSetInteger(0, name, OBJPROP_YDISTANCE, mlbDownYDistance + Y - mlbDownY);//Update YDistance to: mlbDownYDistance + (Y - mlbDownY)          ChartRedraw(0); //Redraw Chart         }       if(MouseState == 0)//Check if MLB is not pressed         {          movingState = false;//set movingState again to false          ChartSetInteger(0, CHART_MOUSE_SCROLL, true);//allow the cahrt to be moved again         }       previousMouseState = MouseState;//update the previousMouseState at the end so that we can use it next time and copare it with new value      }   } //+------------------------------------------------------------------+

    さて、このシンプルなコードが仕事をします。

    結果:

    図6:最終結果

    図6:最終結果


    これでこのセクションを終えることにします。


    結論

    まだあまりユニークなものができていないので、崖っぷちに立たされたようで本当に申し訳ありません。でも、数日後には次の回が始まるのでご安心ください。

    • 1つのチャート上に複数のGUIを効率よく作成できるようになります(コピーペーストだけでなく)。
    • GUIに様々な要素を追加したりカスタマイズしたりすることで、あなた独自のニーズに合わせてGUIを拡張していきます。これはGUIを移動可能にするための簡単なステップを提供する合理化されたガイドで、今すぐ始めたい人にも対応しています。

    この旅が終わる頃には、トレーダーにとって強力なツールであるMQL5で、移動可能なGUIを作成して操作するための貴重なスキルが身に付いていることでしょう。さあ、このエキサイティングな旅を始めましょう。


    気に入っていただけたなら、そして少しでもお役に立てたなら幸いです。次回またお会いできることを楽しみにしています。

    ハッピーコーディング



    MetaQuotes Ltdにより英語から翻訳されました。
    元の記事: https://www.mql5.com/en/articles/12751

    添付されたファイル |
    MQL5におけるARIMAモデルによる予測 MQL5におけるARIMAモデルによる予測
    この記事では、ARIMAモデルを構築するためのCArimaクラスの開発を継続し、予測を可能にする直感的な手法を追加します。
    MQL5の圏論(第10回):モノイド群 MQL5の圏論(第10回):モノイド群
    MQL5における圏論の実装についての連載を続けます。ここでは、モノイド集合を正規化して、より幅広いモノイド集合とデータ型にわたって比較しやすくする手段としてモノイド群を見ていきます。
    シンプルな平均回帰取引戦略 シンプルな平均回帰取引戦略
    平均回帰とは、トレーダーが価格が何らかの形の均衡に戻ることを期待する逆張り取引の一種で、通常は平均値または別の中心的傾向の統計によって測定されます。
    MQL5の圏論(第9回):モノイド作用 MQL5の圏論(第9回):モノイド作用
    MQL5における圏論の実装についての連載を続けます。ここでは、前の記事で説明したモノイドを変換する手段としてモノイド作用を継続し、応用の増加につなげます。