MQL4: How to Handle Object Move Events?

Understanding Chart Objects in MQL4

MQL4 provides a rich set of functions for creating and manipulating graphical objects directly on the chart. These objects can range from simple trend lines and rectangles to more complex shapes and text labels. Understanding how to effectively manage and respond to changes in these objects is crucial for building interactive and dynamic trading tools.

The Significance of Detecting Object Movement

Detecting object movement allows you to create functionalities such as:

  • Interactive order management: Dragging a trendline to modify stop-loss or take-profit levels.
  • Dynamic alerts: Triggering alerts when a price level (represented by a line) is crossed.
  • Custom drawing tools: Enabling users to draw shapes and patterns directly on the chart, which can then be used for analysis or automated trading.

Overview of the OBJPROP_XDISTANCE and OBJPROP_YDISTANCE Properties

In MQL4, the ObjectGetInteger() function, combined with the OBJPROP_XDISTANCE and OBJPROP_YDISTANCE properties, is the primary way to track the movement of chart objects. These properties return the X and Y coordinates of a specified object relative to the chart’s origin. By monitoring changes in these values, you can detect when an object has been moved by the user or programmatically.

Implementing Object Move Event Handling

Using OnChartEvent() Function to Capture Object Events

MQL4 uses the OnChartEvent() function to handle various chart events, including object-related events. This function acts as the central hub for capturing user interactions and system events occurring on the chart.

Identifying OBJEVENT_OBJECT Events

Within the OnChartEvent() function, you need to specifically identify OBJEVENT_OBJECT events. This event is triggered whenever an object on the chart is created, deleted, or its properties are modified, including its position.

Extracting Object Name and Type from Event Parameters

When an OBJEVENT_OBJECT event occurs, the OnChartEvent() function receives several parameters:

  • id: The event identifier (in this case, OBJEVENT_OBJECT).
  • lparam: Depends on the event. For OBJEVENT_OBJECT, it contains the object’s name as a string.
  • dparam: Not typically used for object move events.
  • sparam: Not typically used for object move events.

The lparam variable is especially useful, as it provides the name of the object that triggered the event.

Detecting Object Movement Using Object Properties

Retrieving Initial Object Coordinates

To detect movement, you first need to store the initial X and Y coordinates of the object. This can be done when the object is created or when the program starts.

Monitoring OBJPROP_XDISTANCE and OBJPROP_YDISTANCE

Inside the OnChartEvent() function (specifically when id == OBJEVENT_OBJECT), retrieve the current X and Y coordinates of the object using ObjectGetInteger(object_name, OBJPROP_XDISTANCE) and ObjectGetInteger(object_name, OBJPROP_YDISTANCE). Compare these values to the previously stored coordinates.

Calculating Distance Moved

Calculate the difference between the current and initial coordinates to determine the distance moved in the X and Y directions.

Implementing Thresholds for Movement Detection

To avoid triggering actions on minor, unintended movements, implement thresholds. Only trigger an action if the object has moved a certain distance in either the X or Y direction.

Practical Examples and Code Snippets

Example: Triggering an Alert on Object Drag

int OnInit()
  {
   ObjectCreate("MyLine", OBJ_TREND, 0, TimeCurrent(), 1.2345);
   ObjectSetInteger("MyLine", OBJPROP_SELECTABLE, true);
   ObjectSetInteger("MyLine", OBJPROP_SELECTED, false);
   return(INIT_SUCCEEDED);
  }

void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam)
  {
   static int initial_x, initial_y;
   string object_name;

   if (id == OBJEVENT_OBJECT)
     {
      object_name = (string)lparam;
      if(object_name == "MyLine")
        {
         int current_x = ObjectGetInteger(object_name, OBJPROP_XDISTANCE);
         int current_y = ObjectGetInteger(object_name, OBJPROP_YDISTANCE);

         if(initial_x == 0 && initial_y == 0)
           {
            initial_x = current_x;
            initial_y = current_y;
           }

         if(MathAbs(current_x - initial_x) > 5 || MathAbs(current_y - initial_y) > 5)
           {
            Alert("Object '", object_name, "' was moved!");
            initial_x = current_x;
            initial_y = current_y;
           }
        }
     }
  }

Example: Adjusting Stop Loss/Take Profit Based on Object Movement

(Illustrative Example – requires order management functions)

// Assuming you have a trade open and a trendline named "StopLossLine"
void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam)
{
    if (id == OBJEVENT_OBJECT)
    {
        string object_name = (string)lparam;
        if (object_name == "StopLossLine")
        {
            double new_stoploss_price = ObjectGetDouble(object_name, OBJPROP_PRICE1);
            // Modify the trade's stop loss using OrderModify() function (requires error handling)
            bool modified = OrderModify(OrderTicket(), OrderOpenPrice(), new_stoploss_price, OrderTakeProfit(), OrderExpiration(),CLR_NONE);
            if(!modified)
            {
              Print("OrderModify failed: ",GetLastError());
            }
        }
    }
}

Handling Multiple Objects Simultaneously

To handle multiple objects, use a switch statement or a series of if statements to differentiate between the objects based on their names (object_name). Store the initial coordinates for each object in separate variables or arrays.

Best Practices and Considerations

Optimizing Performance for Frequent Object Updates

Avoid performing computationally intensive operations within the OnChartEvent() function, as it can impact the responsiveness of the chart. If complex calculations are required, consider offloading them to a separate function or using asynchronous processing techniques.

Handling User Interactions and Potential Conflicts

Be mindful of potential conflicts between user interactions and programmatically controlled object movements. For example, if the user is dragging an object while the program is simultaneously attempting to reposition it, unexpected behavior may occur. Implement mechanisms to prevent such conflicts, such as disabling user interaction during critical operations.

Debugging Object Move Event Handling

Use the Print() or Comment() functions to display the values of relevant variables, such as the object name, X and Y coordinates, and calculated distances. This can help you identify issues and debug your code more effectively. Using GetLastError() after function calls is also a great practice to find out the root of the problem.


Leave a Reply