Complete MQL5 guide & code

MQL5 ObjectCreate & OnChartEvent Guide: UI Buttons & Event Handling

Learn how to create chart objects in MQL5 using ObjectCreate and ObjectFind, handle click events with OnChartEvent, and understand why scripts cannot process chart events.

What this MQL5 guide covers

ObjectCreate creates visual and interactive elements including OBJ_BUTTON, OBJ_LABEL, and OBJ_RECTANGLE_LABEL on MetaTrader 5 charts.

Always verify existence with ObjectFind(chart_id, name) before calling ObjectCreate to prevent duplicate creation errors and property resets.

The OnChartEvent handler captures user interactions such as CHARTEVENT_OBJECT_CLICK and CHARTEVENT_KEYDOWN in Expert Advisors and indicators.

OnChartEvent does not function in MQL5 scripts because scripts run synchronously inside OnStart and exit without an event message pump.

ObjectCreate Syntax, Object Types and ObjectFind

The ObjectCreate function instantiates graphical objects on a specified chart window. Parameters define the chart identifier, unique object name, object type enum, target subwindow, and anchor time/price coordinates.

Calling ObjectFind(chart_id, name) checks whether an object already exists. If the object exists, ObjectFind returns the subwindow number (0 for main chart); if not found, it returns a negative value. Always test ObjectFind < 0 before creating objects to avoid overwriting user states.

Object TypeCoordinate ModeCommon Trading Use Case
OBJ_BUTTONPixels (X, Y from corner)One-click trading panels, buy/sell buttons
OBJ_LABELPixels (X, Y from corner)Static text overlays, account info readouts
OBJ_RECTANGLE_LABELPixels (X, Y, width, height)Background container panels for custom GUIs
OBJ_HLINEPrice (single price level)Support, resistance, breakeven thresholds
OBJ_TRENDTime & Price (two points)Trend lines, channel boundaries, breakout alerts

Handling User Interaction with OnChartEvent

Expert Advisors and custom indicators process chart events through the OnChartEvent callback. When a trader clicks a chart button, MetaTrader 5 triggers this function with event ID CHARTEVENT_OBJECT_CLICK.

The sparam argument contains the string name of the clicked object. Match sparam against your known button names to execute corresponding trading actions, then reset button click states with ObjectSetInteger.

Event ConstantTrigger DescriptionKey Parameters
CHARTEVENT_OBJECT_CLICKMouse click on a chart graphical objectsparam = object name
CHARTEVENT_CLICKMouse click on an empty chart areadparam = price, lparam = time
CHARTEVENT_KEYDOWNKeyboard key pressed while chart has focuslparam = key code
CHARTEVENT_CHART_CHANGEChart scale, size, or timeframe alteredlparam, dparam, sparam

Why OnChartEvent Does Not Work for Scripts

A common source of confusion in MQL5 is placing an OnChartEvent handler inside a script program and finding that clicks are completely ignored.

Scripts operate on a synchronous execution model. When attached, a script runs its OnStart() function from start to finish on its own thread, then terminates and unloads. Scripts do not possess an active event loop and cannot receive asynchronous chart events.

  • Scripts execute sequentially and terminate; they cannot listen for clicks.
  • If your trading tool requires interactive buttons, write it as an Expert Advisor.
  • If visual indicators must process clicks, place OnChartEvent inside an indicator.

Redraws and Deinitialization Cleanup

After creating, moving, or changing properties on chart objects, call ChartRedraw(chart_id) to force MetaTrader 5 to update the visual canvas immediately rather than waiting for the next incoming price tick.

In OnDeinit(), iterate through your program objects using ObjectDelete() or call ObjectsDeleteAll(chart_id, prefix) to leave the user chart clean when removing the EA.

Implementation details & mechanics

Core implementation pattern

In OnInit(), check ObjectFind(0, "btn_Buy") < 0. If not found, call ObjectCreate(0, "btn_Buy", OBJ_BUTTON, 0, 0, 0) and set anchor corner, pixel offsets, width, height, background color, and caption text. Call ChartRedraw(). In OnChartEvent(), inspect id == CHARTEVENT_OBJECT_CLICK and match sparam == "btn_Buy". Reset button state via ObjectSetInteger(0, "btn_Buy", OBJPROP_STATE, false) and execute a buy order.

Error handling & safety rules

In OnChartEvent(), handle clicks on "btn_CloseAll" by iterating open positions and closing matching tickets via CTrade. In OnDeinit(const int reason), invoke ObjectsDeleteAll(0, "btn_") to remove all custom panel buttons and labels from the chart.

MQL5 Code Implementation Code

//+------------------------------------------------------------------+
//|                                     ChartObjectsEventsGuideEA.mq5|
//|                             Copyright 2026, Pineify Guides Series |
//|                                              https://pineify.app |
//+------------------------------------------------------------------+
#property copyright "Pineify Guides Series"
#property link      "https://pineify.app/mql5/chart-objects-events-guide"
#property version   "1.00"
#property strict

#include <Trade\Trade.mqh>

#define PREFIX "PineifyUI_"

CTrade g_trade;

//+------------------------------------------------------------------+
//| Helper: Create a chart button with pixel positioning             |
//+------------------------------------------------------------------+
bool CreateButton(const string name, const string text,
                  const int x, const int y,
                  const int width, const int height,
                  const color bgCol, const color textCol)
  {
   // Check if object already exists to avoid redundant creation
   if(ObjectFind(0, name) >= 0)
      return true;

   if(!ObjectCreate(0, name, OBJ_BUTTON, 0, 0, 0))
     {
      PrintFormat("Failed to create button %s! Error: %d", name, GetLastError());
      return false;
     }

   // Anchor to top-left corner using pixel coordinates
   ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
   ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
   ObjectSetInteger(0, name, OBJPROP_XSIZE, width);
   ObjectSetInteger(0, name, OBJPROP_YSIZE, height);

   // Styling
   ObjectSetString(0, name, OBJPROP_TEXT, text);
   ObjectSetString(0, name, OBJPROP_FONT, "Segoe UI");
   ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 10);
   ObjectSetInteger(0, name, OBJPROP_COLOR, textCol);
   ObjectSetInteger(0, name, OBJPROP_BGCOLOR, bgCol);
   ObjectSetInteger(0, name, OBJPROP_BORDER_COLOR, clrDarkGray);
   ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
   ObjectSetInteger(0, name, OBJPROP_STATE, false);

   return true;
  }

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   g_trade.SetExpertMagicNumber(998877);

   // Create UI buttons
   CreateButton(PREFIX + "BuyBtn", "BUY 0.10", 20, 40, 110, 36, clrDodgerBlue, clrWhite);
   CreateButton(PREFIX + "CloseBtn", "CLOSE ALL", 140, 40, 110, 36, clrCrimson, clrWhite);

   // Refresh chart to display objects immediately
   ChartRedraw(0);

   Print("Chart objects UI created successfully.");
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   // Delete all graphical objects matching program prefix
   int deleted = ObjectsDeleteAll(0, PREFIX);
   ChartRedraw(0);

   PrintFormat("Removed %d UI chart objects. Reason: %d", deleted, reason);
  }

//+------------------------------------------------------------------+
//| Chart event handler                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
   // Filter for object click events
   if(id == CHARTEVENT_OBJECT_CLICK)
     {
      // Handle BUY button click
      if(sparam == PREFIX + "BuyBtn")
        {
         Print("User clicked BUY button.");
         double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
         g_trade.Buy(0.10, _Symbol, ask, 0, 0, "Pineify Button Click");

         // Reset button pressed state
         ObjectSetInteger(0, sparam, OBJPROP_STATE, false);
         ChartRedraw(0);
        }
      // Handle CLOSE ALL button click
      else if(sparam == PREFIX + "CloseBtn")
        {
         Print("User clicked CLOSE ALL button.");
         // Close all positions matching this symbol
         for(int i = PositionsTotal() - 1; i >= 0; i--)
           {
            ulong ticket = PositionGetTicket(i);
            if(PositionGetString(POSITION_SYMBOL) == _Symbol)
               g_trade.PositionClose(ticket);
           }

         // Reset button pressed state
         ObjectSetInteger(0, sparam, OBJPROP_STATE, false);
         ChartRedraw(0);
        }
     }
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   // Standard EA calculations can proceed concurrently with UI events
  }

Copy this code into MetaEditor, save it in your MQL5 folder (Experts, Scripts, or Include), and compile with F7.

Generate custom MQL5 code with Pineify AI

Describe the trade execution, indicator calculations, risk management, or data processing logic you need. Pineify produces clean, typed MQL5 source code ready to compile in MetaEditor.

Frequently Asked Questions

Related MQL5 pages

Technical references

Risk and testing note

Past performance is not indicative of future results. Backtest statistics are based on historical data and do not guarantee future profits. Trading involves significant risk of loss. This content is for educational purposes only and does not constitute financial advice.