Custom Drawing Tools

 

Hi folks! 

I was wondering if there's a way to create a custom Drawing Tool for Metatrader 4 (or 5); concretely something like R:R ratios, Harmonic Patterns, etc.

I know that reading in depth the documentation something will come up but I also wanted to know if someone already tried and succeeded.


Clarification: I'm not looking for someone to do the homework for me. Just curious about the subject.


Kind regards,

Xpip.

 
Xpip:

I was wondering if there's a way to create a custom Drawing Tool for Metatrader 4 (or 5); concretely something like R:R ratios, Harmonic Patterns, etc.

As you doubtless know already, there's no interface for adding to MT4's list of drawing tools in a sense comparable to creating a new indicator. However, there is potentially a kludgy workaround. It helps if it's possible to synthesise the drawing you want out of existing shapes such as lines, rectangles etc. But, failing that, anything should ultimately be possible because you can always use canvas to draw anything you want on the chart.

One way of doing it is as follows:

  • You have an indicator which uses OnChartEvent to record clicks on the chart
  • You start the "drawing tool" by adding the indicator to a chart
  • Once the indicator has received the number of clicks it needs (e.g. 4), you draw your custom shape, and then get the indicator to remove itself

As a very simple example, the following indicator waits for you to click twice on the chart and then draws a line between those points:

#property strict
#property indicator_chart_window

// Temporary ID which the indicator assigns to itself on start-up, so that
// it can then remove itself
string glbIndicatorTemporaryId;

// Definition of a click on the chart
struct ClickHistory {
   // x-y coords of click
   int x;  int y;
   // Equivalent time-price coords of click
   datetime atTime;  double atPrice;
   // Time when click happend (UTC)
   datetime clickTimestamp;
};

// History of clicks
int glbClickCount;
ClickHistory glbClicks[];


int OnInit()
{
   // Assign a hopefully-unique ID to the indicator so that it can later remove itself
   glbIndicatorTemporaryId = IntegerToString(GetMicrosecondCount());
   IndicatorSetString(INDICATOR_SHORTNAME, glbIndicatorTemporaryId);

   glbClickCount = 0;
   return(INIT_SUCCEEDED);
}

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);
}

void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   if (id == CHARTEVENT_KEYDOWN) {
      // Cancel the drawing if Esc is pressed
      if (lparam == 27) RemoveIndicator();
      
   } else if (id == CHARTEVENT_CLICK) {
      // Get the x-y coords of the click and convert them to time-price coords
      int subwindow, x = (int)lparam, y = (int)dparam;
      datetime atTime;
      double atPrice;
      ChartXYToTimePrice(0, x, y, subwindow, atTime, atPrice);
      
      if (subwindow != 0) {
         // Ignore clicks in subsidiary indicator windows, and treat
         // this as cancellation of the drawing tool
         RemoveIndicator();

      } else {
         // Store a record of the click, including its x-y coords and also its time-price coords
         glbClickCount++;
         ArrayResize(glbClicks, glbClickCount);
         glbClicks[glbClickCount - 1].clickTimestamp = TimeGMT();
         glbClicks[glbClickCount - 1].x = x;
         glbClicks[glbClickCount - 1].y = y;
         glbClicks[glbClickCount - 1].atTime = atTime;
         glbClicks[glbClickCount - 1].atPrice = atPrice;
         
         // Do we now have the number of clicks required by this drawing tool?      
         if (glbClickCount < 2) {
            // Wait for more clicks. Could look for delays between clicks, and 
            // cancel the operation (removing the indicator) if it exceeds
            // a threshold
   
         } else {
            // Got the required two clicks. Process the history, creating a line
            // between the two specified points
            string strObjectName = "line" + IntegerToString(GetMicrosecondCount());
            
            ObjectCreate(0, strObjectName, OBJ_TREND, 0, glbClicks[0].atTime,  glbClicks[0].atPrice,  glbClicks[1].atTime,  glbClicks[1].atPrice);
            ObjectSetInteger(0, strObjectName, OBJPROP_RAY, 0);
   
            // Remove the indicator
            RemoveIndicator();
         }
      }
   }
}

void RemoveIndicator()
{
   ChartIndicatorDelete(0, 0, glbIndicatorTemporaryId);
}
 

JC:

[...] and then get the indicator to remove itself

... If you want to get really complicated, you could have a different life-cycle where the indicator remains on the chart; listens for further clicks; detects clicks on its object(s); and lets you edit/re-position the object by moving its grab-points etc.
 
JC:

As you doubtless know already, there's no interface for adding to MT4's list of drawing tools in a sense comparable to creating a new indicator. However, there is potentially a kludgy workaround. It helps if it's possible to synthesise the drawing you want out of existing shapes such as lines, rectangles etc. But, failing that, anything should ultimately be possible because you can always use canvas to draw anything you want on the chart.

One way of doing it is as follows:

  • You have an indicator which uses OnChartEvent to record clicks on the chart
  • You start the "drawing tool" by adding the indicator to a chart
  • Once the indicator has received the number of clicks it needs (e.g. 4), you draw your custom shape, and then get the indicator to remove itself

As a very simple example, the following indicator waits for you to click twice on the chart and then draws a line between those points:


Thank you very much, JC! For your reply and example. I was thinking in using a C-coded DLL to create some kind of bridge... I know, sometimes I overcomplicate things, haha. Your way will do just fine and save some time in the process.

 
JC:

As you doubtless know already, there's no interface for adding to MT4's list of drawing tools in a sense comparable to creating a new indicator. However, there is potentially a kludgy workaround. It helps if it's possible to synthesise the drawing you want out of existing shapes such as lines, rectangles etc. But, failing that, anything should ultimately be possible because you can always use canvas to draw anything you want on the chart.

One way of doing it is as follows:

  • You have an indicator which uses OnChartEvent to record clicks on the chart
  • You start the "drawing tool" by adding the indicator to a chart
  • Once the indicator has received the number of clicks it needs (e.g. 4), you draw your custom shape, and then get the indicator to remove itself

As a very simple example, the following indicator waits for you to click twice on the chart and then draws a line between those points:


Usefull.

Thank you veeery much!