Problem Description
Solution
To manage charts programmatically in MQL4, you utilize the ChartOpen, ChartClose, and the chart navigation functions (ChartFirst, ChartNext) to iterate through existing windows.
Below is a complete script that demonstrates three core functionalities:
FindChartID: Iterates through all open charts to find a specific Symbol and Timeframe.OpenNewChart: Opens a new chart window.CloseChartWindow: Closes a specific chart window.
MQL4 Script: Chart Manager
//+------------------------------------------------------------------+
//| ChartManagerScript.mq4 |
//| Copyright 2023, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
#property script_show_inputs
//--- Input parameters
input string InpSymbol = "EURUSD"; // Symbol to manage
input ENUM_TIMEFRAMES InpPeriod = PERIOD_H1; // Timeframe to manage
input bool InpCloseIfFound = false; // Close chart if found?
input bool InpOpenIfMissing = true; // Open chart if not found?
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
// 1. Try to find an existing chart for the specified Symbol and Period
long chartID = FindChartID(InpSymbol, InpPeriod);
if(chartID > 0)
{
PrintFormat("Found existing chart for %s %s. ID: %I64d",
InpSymbol, GetPeriodName(InpPeriod), chartID);
// Bring the found chart to the foreground (optional)
// ChartSetInteger(chartID, CHART_BRING_TO_TOP, true);
if(InpCloseIfFound)
{
// Prevent closing the chart the script is currently running on
if(chartID == ChartID())
{
Print("Cannot close the chart where the script is running.");
}
else
{
Print("Closing chart ID: ", chartID);
if(ChartClose(chartID))
Print("Chart closed successfully.");
else
Print("Failed to close chart. Error: ", GetLastError());
}
}
}
else
{
PrintFormat("Chart for %s %s not found.", InpSymbol, GetPeriodName(InpPeriod));
if(InpOpenIfMissing)
{
Print("Attempting to open new chart...");
long newChartID = ChartOpen(InpSymbol, InpPeriod);
if(newChartID > 0)
PrintFormat("Successfully opened new chart. ID: %I64d", newChartID);
else
Print("Failed to open chart. Error: ", GetLastError());
}
}
}
//+------------------------------------------------------------------+
//| Function to find a chart ID by Symbol and Period |
//+------------------------------------------------------------------+
long FindChartID(string symbol, ENUM_TIMEFRAMES period)
{
long currChartId = ChartFirst(); // Get the first chart ID
// Loop through all open charts
while(currChartId >= 0)
{
// Check if Symbol and Period match
if(ChartSymbol(currChartId) == symbol && ChartPeriod(currChartId) == period)
{
return(currChartId); // Return the ID if found
}
// Move to the next chart
currChartId = ChartNext(currChartId);
}
return(0); // Return 0 if not found
}
//+------------------------------------------------------------------+
//| Helper function to convert period enum to string |
//+------------------------------------------------------------------+
string GetPeriodName(ENUM_TIMEFRAMES period)
{
switch(period)
{
case PERIOD_M1: return("M1");
case PERIOD_M5: return("M5");
case PERIOD_M15: return("M15");
case PERIOD_M30: return("M30");
case PERIOD_H1: return("H1");
case PERIOD_H4: return("H4");
case PERIOD_D1: return("D1");
case PERIOD_W1: return("W1");
case PERIOD_MN1: return("MN1");
default: return("Unknown");
}
}
//+------------------------------------------------------------------+
Explanation of Key Functions
-
ChartOpen(symbol, period):- Opens a new chart window.
- Returns a
longvalue representing the Chart ID. - If it fails (returns 0), use
GetLastError()to debug.
-
ChartClose(chart_id):- Closes the specific chart identified by the ID.
- Returns
trueif successful.
-
ChartFirst()andChartNext(chart_id):- There is no direct function to "Get Chart by Symbol". You must iterate through the list.
ChartFirst()gets the ID of the very first chart in the terminal list.ChartNext(current_id)gets the ID of the chart following the current one.- The loop continues until
ChartNextreturns -1 (end of list).
-
ChartSymbol(chart_id)andChartPeriod(chart_id):- These retrieve the properties of the chart currently being examined in the loop to compare against your target criteria.
How to Use
- Copy the code into a new Script file in MetaEditor (e.g.,
ChartManager.mq4). - Compile the script.
- Drag the script onto any chart in your terminal.
- In the inputs window:
- InpSymbol: Type the symbol you want to find/open (e.g., "GBPUSD").
- InpPeriod: Select the timeframe.
- InpCloseIfFound: Set to
trueif you want to close that specific chart if it already exists. - InpOpenIfMissing: Set to
trueif you want to open it if it doesn't exist.
Q&A
Q: Can I open a chart for a symbol that is not in the Market Watch?
A: No. If the symbol is not selected in the Market Watch window, ChartOpen may fail or return error 4106 (ERR_UNKNOWN_SYMBOL). You should ensure the symbol is selected using SymbolSelect("SymbolName", true) before attempting to open the chart.
Q: Does ChartClose work on the chart running the script?
A: Yes, a script can close its own chart. However, this immediately terminates the script execution. In the provided code, I added a safety check if(chartID == ChartID()) to prevent accidental self-closing, but you can remove this if that is the desired behavior.
Q: How do I apply a template to the newly opened chart?
A: Immediately after getting the newChartID from ChartOpen, you can call ChartApplyTemplate(newChartID, "MyTemplate.tpl");. Note that this is an asynchronous command and is added to the chart's queue.