How to Delete an Object by Name in MQL4?

Managing graphical objects on a MetaTrader chart is a fundamental task for any MQL4 developer creating indicators, scripts, or Expert Advisors. Objects like lines, arrows, labels, rectangles, and text are essential for visual representation of analysis or trading activity.

Importance of Managing Objects in MQL4

Leaving unused or temporary objects on the chart can lead to clutter, making it difficult for users to interpret information. More importantly, failing to clean up objects, especially in frequently updating indicators or EAs running on multiple bars, can impact chart performance due to excessive rendering overhead.

Effective object management involves not only creating objects when needed but also deleting them when they are no longer necessary. This ensures a clean chart and optimized performance.

Brief Overview of Object Types in MQL4

MQL4 supports a wide array of graphical objects, each identified by a specific OBJ_... constant. These include:

  • Lines: OBJ_HLINE, OBJ_VLINE, OBJ_TREND, OBJ_FIBO, etc.
  • Shapes: OBJ_RECTANGLE, OBJ_ELLIPSE, OBJ_TRIANGLE
  • Text and Labels: OBJ_TEXT, OBJ_LABEL
  • Arrows and Symbols: OBJ_ARROW_BUY, OBJ_ARROW_SELL, OBJ_ARROW
  • Other: OBJ_EVENT, OBJ_BUTTON, OBJ_BITMAP

Each object on a chart is uniquely identified by its name within that chart.

Why Delete Objects by Name?

The primary method for managing individual objects in MQL4 is through their assigned name. When you create an object using ObjectCreate(), you provide it with a unique string name. This name then serves as the handle for all subsequent operations on that specific object, including modification (ObjectSet...(), ObjectMove()) and, crucially, deletion.

Deleting by name is the most direct and explicit way to remove a specific object you have previously created or identified.

The ObjectDelete() Function

In MQL4, the core function for removing a graphical object from a chart is ObjectDelete(). This function takes the object’s name as its primary argument.

Syntax and Parameters of ObjectDelete()

The syntax for ObjectDelete() is straightforward:

bool ObjectDelete(long chart_id, string name);
bool ObjectDelete(string name); // For MQL4

For MQL4, the most commonly used overload is bool ObjectDelete(string name);. It attempts to delete the object with the specified name from the current chart.

The chart_id parameter is relevant in MQL5 and also available in later builds of MQL4, allowing you to specify which chart to delete the object from. In typical MQL4 usage on the current chart, the version taking only the name is sufficient.

  • name: A string representing the unique name of the object to be deleted on the specified (or current) chart.

Return Value and Error Handling

The ObjectDelete() function returns a bool value:

  • true: If the object was successfully found and deleted.
  • false: If the object with the given name was not found on the chart, or if there was another error during the deletion process.

It is good practice to check the return value, especially when deleting objects that might not always exist. You can retrieve detailed error information using GetLastError() after a false return, although ObjectDelete errors are typically limited to the object not existing (error 4202 – ERROBJECTDOESNOTEXIST) or potentially chart-related issues.

How ObjectDelete() Works with Object Names

When ObjectDelete(name) is called, the MetaTrader terminal searches the list of objects on the relevant chart (current chart in MQL4’s single-argument version) for an object whose name exactly matches the provided name string. If a match is found, the object is removed from the chart and its associated resources are freed. If no match is found, the function returns false without doing anything.

The uniqueness of object names on a per-chart basis is crucial here. You cannot have two objects with the same name on the same chart.

Deleting Objects by Name: Practical Examples

Let’s look at common scenarios for using ObjectDelete().

Deleting a Single Object by Name

This is the most basic use case.

// Assume an object named "MyTemporaryLine" was previously created.
string objectName = "MyTemporaryLine";

// Attempt to delete the object
bool success = ObjectDelete(objectName);

if (success)
{
    Print("Object '" + objectName + "' deleted successfully.");
}
else
{
    Print("Failed to delete object '" + objectName + "'. Error: " + GetLastError());
}

This code snippet attempts to remove a single, specific object identified by its exact name.

Deleting Multiple Objects Using Loops and Name Patterns

Often, you create multiple objects with names following a specific pattern (e.g., “Arrow” + bar index, or “Level” + price). You can iterate through all objects on the chart and delete those matching the pattern.

// Example: Delete all objects whose names start with "TempArrow_"

int totalObjects = ObjectsTotal(0); // Get total objects on the current chart

// Iterate backwards because deleting an object changes the total count and indices
for (int i = totalObjects - 1; i >= 0; i--)
{
    string currentObjectName = ObjectName(0, i);

    // Check if the name starts with our pattern
    if (StringFind(currentObjectName, "TempArrow_", 0) == 0) // 0 means starts at index 0
    {
        // Delete the object
        bool success = ObjectDelete(currentObjectName);
        if (success)
        {
            Print("Deleted object: " + currentObjectName);
        } else {
            Print("Failed to delete object: " + currentObjectName + ", Error: " + GetLastError());
        }
    }
}

This pattern of iterating backwards using ObjectsTotal() and ObjectName(index) is standard practice for cleaning up multiple objects based on criteria.

Conditional Object Deletion Based on Name

You might want to delete objects based on information encoded within their names or in conjunction with other object properties (though accessing properties requires knowing the name first or iterating). The name itself can carry conditional information.

// Example: Delete temporary lines created on bars older than a certain index
// Assume lines are named like "TrendLine_" + bar_index

int currentBar = Bars - 1; // Index of the current completed bar
int barLimit = currentBar - 50; // Delete lines older than 50 bars

int totalObjects = ObjectsTotal(0);

for (int i = totalObjects - 1; i >= 0; i--)
{
    string currentObjectName = ObjectName(0, i);

    // Check if it's one of our trend line objects based on name pattern
    if (StringFind(currentObjectName, "TrendLine_", 0) == 0)
    {
        // Extract the bar index from the name
        int underscorePos = StringFind(currentObjectName, "_", 0);
        if (underscorePos > 0)
        {
            string barIndexStr = StringSubstr(currentObjectName, underscorePos + 1);
            int objectBarIndex = StringToInteger(barIndexStr);

            // Check if the object's bar index is older than our limit
            if (objectBarIndex < barLimit)
            {
                bool success = ObjectDelete(currentObjectName);
                if (success)
                {
                    Print("Deleted old trend line: " + currentObjectName);
                } else {
                    Print("Failed to delete old trend line: " + currentObjectName + ", Error: " + GetLastError());
                }
            }
        }
    }
}

This example demonstrates parsing information from the object name to apply a deletion condition.

Best Practices and Common Pitfalls

Properly managing object deletion prevents issues and improves code robustness.

Ensuring the Object Exists Before Deletion

Calling ObjectDelete() on a non-existent object is not a critical error (it just returns false), but it’s inefficient and the GetLastError() call after a false can be misleading if you didn’t intend the object to be missing. If you are unsure if an object exists, you can check first:

string objName = "MaybeExistsObject";

if (ObjectFind(0, objName) >= 0) // ObjectFind returns the object's index if found, -1 if not
{
    // Object exists, safe to delete
    ObjectDelete(objName);
}
else
{
    // Object does not exist
    Print("Object '" + objName + "' not found.");
}

Using ObjectFind() adds a check, but note that ObjectDelete() itself checking for existence internally is typically efficient enough that an explicit ObjectFind check isn’t strictly necessary unless you need to branch logic based on existence before attempting deletion.

Naming Conventions for Easy Object Management

Consistent and descriptive object naming is crucial, especially when you need to delete groups of objects. Include prefixes or suffixes that identify:

  • The script/indicator/EA that created it (e.g., MyEA_)
  • The object type (e.g., Line_, Arrow_)
  • Information related to its purpose or bar/time (e.g., _BarIndex, _SignalID)

Example: MyIndicator_Level_42_Bar123
This makes it easy to find and delete all objects created by your indicator, all level lines, or a specific line on a specific bar using name patterns with StringFind.

Avoiding Memory Leaks by Deleting Unused Objects

While MQL4 is relatively simple in terms of memory management compared to languages like C++, graphical objects do consume resources. Failing to delete temporary or old objects, especially in indicators that update frequently on every tick or new bar, can lead to:

  • Increased memory usage by the MetaTrader terminal.
  • Slower chart rendering as the terminal has to manage and draw more objects.

Ensure that when an object’s purpose is served (e.g., a signal arrow for a past bar, a temporary calculation line), it is promptly deleted. The OnDeinit function is the standard place to clean up all objects created by your program when the program is removed from the chart or the chart is closed.

// In your MQL4 program:

void OnDeinit(const int reason)
{
    // Loop and delete all objects created by THIS program
    // assuming a consistent naming convention, e.g., starting with MyEA_

    int totalObjects = ObjectsTotal(0);
    string myPrefix = "MyEA_";

    for (int i = totalObjects - 1; i >= 0; i--)
    {
        string currentObjectName = ObjectName(0, i);
        if (StringFind(currentObjectName, myPrefix, 0) == 0)
        {
            ObjectDelete(currentObjectName);
        }
    }
}

This OnDeinit cleanup is vital for preventing resource leaks when your program stops running.

Handling Errors During Object Deletion

As mentioned, the primary error is the object not being found. If ObjectDelete() returns false, you can check GetLastError(). However, for routine deletion where the object should exist, a false return often simply confirms it was already deleted or never created, which might be an acceptable state depending on your logic. For critical objects, logging the failure and GetLastError() can aid debugging.

Advanced Techniques and Considerations

Beyond basic deletion, there are nuances to consider.

Deleting Objects Created by Other Indicators/Scripts

By default, an MQL4 program can delete any object on the chart it is attached to, regardless of which other program created it. This can be powerful for utility scripts (e.g., a script to clean all lines or arrows) but can also be dangerous. Be cautious when deleting objects without checking their names or properties, as you could inadvertently remove objects from other indicators or EAs running on the same chart. Using specific naming prefixes (as discussed) is crucial if you only want to delete objects created by your program.

Impact of Object Deletion on Chart Performance

While creating and deleting objects has overhead, the rendering of objects on the chart is typically more performance-intensive than the deletion call itself. Deleting objects that are no longer needed improves performance by reducing the number of items the terminal has to draw and manage in its internal object tree. Efficient deletion is a key part of performance optimization, especially in indicators with many temporary graphical elements.

Alternatives to Object Deletion (e.g., ObjectHide)

In some scenarios, you might not want to permanently delete an object, but merely hide it temporarily. MQL4 (and MQL5) offers the ObjectSetInteger() function to set object properties, including OBJPROP_SELECTABLE and OBJPROP_HIDDEN (MQL5 only) or managing visibility via colors and styles. In MQL4, a common technique for


Leave a Reply