🚀 AI One-Click Generation of mql4 Strategy Code

Mql4 Tutorial: How to Control Indicators and Objects in Subwindows

mql4 | Published on: 2025/12/15
The following content is generated by EasyQuant .

Problem Description

How can I place a text label inside a specific indicator window, like the RSI window, instead of the main chart?

Solution

To place a text label inside a specific indicator window (subwindow) in MetaTrader 4, you need to determine the Window Index of that indicator.

There are two primary ways to achieve this:

  1. Inside a Custom Indicator: The indicator identifies its own window index automatically.
  2. From an EA or Script: The program searches for an existing indicator (like RSI) by its "Short Name" to find the window index.

Below are the implementations for both scenarios.

Method 1: Creating a Custom Indicator with a Label

This is the most reliable method. We create a custom indicator that calculates RSI and places a label directly into its own subwindow.

//+------------------------------------------------------------------+
//|                                               RSI_With_Label.mq4 |
//|                        Copyright 2023, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Quantitative AI"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

//--- Indicator Settings
#property indicator_separate_window // Essential: Draws in a subwindow
#property indicator_buffers 1
#property indicator_color1  clrDodgerBlue
#property indicator_width1  2

//--- Inputs
input int      InpRsiPeriod = 14;           // RSI Period
input color    InpLabelColor = clrWhite;    // Label Color
input int      InpFontSize   = 10;          // Font Size
input string   InpFont       = "Arial";     // Font Name
input int      InpCorner     = CORNER_LEFT_UPPER; // Corner to anchor

//--- Buffers
double RsiBuffer[];

//--- Global Variables for Object Management
string labelName = "RSI_Info_Label";

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
   //--- Indicator Buffer Mapping
   SetIndexBuffer(0, RsiBuffer);
   SetIndexStyle(0, DRAW_LINE);
   
   //--- Set Short Name (Important for WindowFind in other scripts)
   string shortName = "RSI_Label(" + IntegerToString(InpRsiPeriod) + ")";
   IndicatorShortName(shortName);
   
   //--- Append unique ID to label name to avoid conflicts
   labelName += "_" + shortName;

   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   //--- Clean up: Remove the object when indicator is removed
   if(ObjectFind(0, labelName) >= 0)
   {
      ObjectDelete(0, labelName);
   }
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
{
   //--- 1. Calculate RSI
   int limit = rates_total - prev_calculated;
   if(prev_calculated > 0) limit++;
   
   for(int i = 0; i < limit; i++)
   {
      RsiBuffer[i] = iRSI(NULL, 0, InpRsiPeriod, PRICE_CLOSE, i);
   }

   //--- 2. Manage the Text Label
   // We do this in OnCalculate to ensure the window exists
   UpdateLabel(RsiBuffer[0]);

   return(rates_total);
}

//+------------------------------------------------------------------+
//| Helper function to create/update the label                       |
//+------------------------------------------------------------------+
void UpdateLabel(double currentRsiValue)
{
   //--- Find the window index where this indicator is running
   // ChartWindowFind() with no arguments returns the window of the calling indicator
   int windowIndex = ChartWindowFind(); 

   //--- Check if object exists, if not, create it
   if(ObjectFind(0, labelName) < 0)
   {
      // ObjectCreate arguments: ChartID, Name, Type, SubWindow, Time1, Price1
      // Note: OBJ_LABEL ignores Time/Price, but we must pass the windowIndex
      if(!ObjectCreate(0, labelName, OBJ_LABEL, windowIndex, 0, 0))
      {
         Print("Failed to create label. Error: ", GetLastError());
         return;
      }
      
      // Initial properties
      ObjectSetInteger(0, labelName, OBJPROP_CORNER, InpCorner);
      ObjectSetInteger(0, labelName, OBJPROP_XDISTANCE, 10); // 10 pixels from edge
      ObjectSetInteger(0, labelName, OBJPROP_YDISTANCE, 10); // 10 pixels from edge
      ObjectSetString(0, labelName, OBJPROP_FONT, InpFont);
      ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, InpFontSize);
      ObjectSetInteger(0, labelName, OBJPROP_COLOR, InpLabelColor);
      ObjectSetInteger(0, labelName, OBJPROP_BACK, false); 
      ObjectSetInteger(0, labelName, OBJPROP_SELECTABLE, false);
      ObjectSetInteger(0, labelName, OBJPROP_HIDDEN, true); // Hide from object list
   }

   //--- Update the text
   string text = "RSI(" + IntegerToString(InpRsiPeriod) + "): " + DoubleToString(currentRsiValue, 2);
   ObjectSetString(0, labelName, OBJPROP_TEXT, text);
   
   //--- Optional: Change color based on levels
   if(currentRsiValue > 70) ObjectSetInteger(0, labelName, OBJPROP_COLOR, clrRed);
   else if(currentRsiValue < 30) ObjectSetInteger(0, labelName, OBJPROP_COLOR, clrLime);
   else ObjectSetInteger(0, labelName, OBJPROP_COLOR, InpLabelColor);
   
   //--- Force redraw to show changes immediately
   ChartRedraw(0);
}

Method 2: Using a Script to Label an Existing Indicator

Use this script if you have a standard RSI already on the chart and want to inject a label into its window without replacing the indicator.

Note: This requires the RSI "Short Name" to match exactly. Standard MT4 RSI is usually named RSI(14) (if period is 14).

//+------------------------------------------------------------------+
//|                                        Label_Existing_Window.mq4 |
//|                        Copyright 2023, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Quantitative AI"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict
#property show_inputs // Show inputs window on run

//--- Inputs
input string   InpTargetIndicator = "RSI(14)"; // Exact short name of the indicator
input string   InpLabelText       = "RSI Window Label";
input color    InpColor           = clrYellow;

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
   //--- 1. Find the window index of the target indicator
   // ChartWindowFind(0, Name) searches the main chart (0) for the indicator short name
   int windowIndex = ChartWindowFind(0, InpTargetIndicator);

   //--- 2. Validate the window
   if(windowIndex == -1)
   {
      Alert("Indicator '", InpTargetIndicator, "' not found on chart!");
      Print("Available windows: ", (int)ChartGetInteger(0, CHART_WINDOWS_TOTAL));
      return;
   }
   
   if(windowIndex == 0)
   {
      Alert("Found on Main Chart. This script is intended for subwindows.");
      // We continue anyway, but warn the user
   }

   //--- 3. Create the Label Object
   string objName = "External_Label_" + InpTargetIndicator;
   
   // Delete if exists to reset
   if(ObjectFind(0, objName) >= 0) ObjectDelete(0, objName);

   // Create OBJ_LABEL in the specific windowIndex
   if(ObjectCreate(0, objName, OBJ_LABEL, windowIndex, 0, 0))
   {
      //--- Set Properties
      ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
      ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, 20);
      ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, 20);
      ObjectSetString(0, objName, OBJPROP_TEXT, InpLabelText);
      ObjectSetString(0, objName, OBJPROP_FONT, "Arial Bold");
      ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, 12);
      ObjectSetInteger(0, objName, OBJPROP_COLOR, InpColor);
      
      ChartRedraw(0);
      Print("Label placed successfully in Window #", windowIndex);
   }
   else
   {
      Print("Failed to create object. Error: ", GetLastError());
   }
}

Key Technical Details

  1. #property indicator_separate_window: This directive in Method 1 tells MT4 to create a new subwindow rather than overlaying on the price chart.
  2. ChartWindowFind():
    • When called without parameters inside an indicator, it returns the index of the window that indicator occupies.
    • When called with parameters (ChartWindowFind(0, "Name")), it searches for a specific indicator name.
  3. ObjectCreate Parameter: The 4th parameter in ObjectCreate is the sub_window index.
    • 0 = Main Chart.
    • 1 and higher = Indicator subwindows.
  4. OBJ_LABEL vs OBJ_TEXT:
    • OBJ_LABEL: Uses X/Y pixel coordinates relative to a corner. It stays in place when you scroll the chart. This is usually preferred for status labels.
    • OBJ_TEXT: Uses Time/Price coordinates. It moves when you scroll the chart.

Q&A

Q: How do I find the exact "Short Name" for Method 2?
A: Open the "Data Window" (Ctrl+D) in MT4. Hover your mouse over the indicator line. The name displayed at the top of the value list (e.g., RSI(14)) is the short name. Alternatively, right-click the chart, select "Indicators List", select the indicator, and click "Edit". The name is usually derived from the inputs.

Q: Can I place a label in the RSI window from an Expert Advisor (EA)?
A: Yes. Use the logic from Method 2 inside the EA's OnInit or OnTick. However, the RSI indicator must already be attached to the chart manually or via a template for the EA to find it. EAs run in Window 0, so they must explicitly look up the subwindow index.

Q: Why does my label disappear when I change timeframes?
A: MQL4 objects persist on the chart ID. However, if your code logic deletes objects in OnDeinit (which runs on timeframe change) and fails to recreate them properly in OnInit or OnCalculate, they will vanish. Ensure your creation logic checks if(ObjectFind(...) < 0) inside OnCalculate or OnTick to ensure persistence.