🚀 AI One-Click Generation of mql4 Strategy Code

Mql4 Tutorial: How to Create Dynamic On-Chart Images with ResourceCreate()

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

Problem Description

How do I draw a custom image, like a heat map or a dynamic status icon, on the chart?

Solution

To draw custom dynamic images, such as heat maps or status icons, in MQL4, you cannot use standard object properties like OBJPROP_COLOR alone. Instead, you must manipulate a pixel array (buffer) and convert it into a graphical resource using the ResourceCreate() function. This resource is then displayed on the chart using an OBJ_BITMAP_LABEL.

Here is the step-by-step logic:

  1. Define a Pixel Array: Create a one-dimensional uint array representing the pixels (Width × Height).
  2. Manipulate Pixels: Calculate the color (ARGB format) for each pixel based on your logic (e.g., RSI value, price change).
  3. Create Resource: Use ResourceCreate() to bind the array to a resource name (e.g., ::MyImage).
  4. Display Object: Create an OBJ_BITMAP_LABEL and set its OBJPROP_BMPFILE property to your resource name.

MQL4 Code Example: Dynamic RSI Heat Map

This Expert Advisor creates a dynamic "Heat Map" tile on your chart. The color shifts from Green (Oversold) to Red (Overbought) based on the RSI value, and it displays the text value inside the image.

#property copyright "Copyright 2023, Quantitative Assistant"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

//--- Input Parameters
input int      InpWidth       = 200;         // Image Width
input int      InpHeight      = 100;         // Image Height
input int      InpX           = 50;          // X Position
input int      InpY           = 50;          // Y Position
input int      InpRsiPeriod   = 14;          // RSI Period

//--- Global Variables
uint           ExtImgBuffer[];               // The pixel buffer
string         ExtResourceName = "::RsiHeatMap"; // Resource name (must start with ::)
string         ExtObjectName   = "RsiBitmap";    // Chart object name

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   // 1. Resize the pixel buffer
   ArrayResize(ExtImgBuffer, InpWidth * InpHeight);
   
   // 2. Create the Bitmap Label object on the chart
   if(ObjectFind(0, ExtObjectName) < 0)
   {
      ObjectCreate(0, ExtObjectName, OBJ_BITMAP_LABEL, 0, 0, 0);
      ObjectSetInteger(0, ExtObjectName, OBJPROP_XDISTANCE, InpX);
      ObjectSetInteger(0, ExtObjectName, OBJPROP_YDISTANCE, InpY);
      ObjectSetInteger(0, ExtObjectName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
      ObjectSetInteger(0, ExtObjectName, OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER);
      // Link the object to the dynamic resource
      ObjectSetString(0, ExtObjectName, OBJPROP_BMPFILE, ExtResourceName); 
   }
   
   // 3. Initial Draw
   UpdateHeatMap();
   
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   // Clean up object and resource to free memory
   ObjectDelete(0, ExtObjectName);
   ResourceFree(ExtResourceName);
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
   // Update the image on every tick
   UpdateHeatMap();
}

//+------------------------------------------------------------------+
//| Logic to draw the Heat Map                                       |
//+------------------------------------------------------------------+
void UpdateHeatMap()
{
   // --- 1. Calculate Logic (RSI)
   double rsi = iRSI(NULL, 0, InpRsiPeriod, PRICE_CLOSE, 0);
   
   // --- 2. Determine Background Color based on Heat
   uint bgColor;
   
   // Simple Heat Logic: 
   // < 30 = Green (Oversold)
   // > 70 = Red (Overbought)
   // 50   = Gray (Neutral)
   // We interpolate colors for smooth transition
   
   if(rsi >= 70)      bgColor = ColorToARGB(clrRed, 255); // Opaque Red
   else if(rsi <= 30) bgColor = ColorToARGB(clrGreen, 255); // Opaque Green
   else if(rsi > 50)  
   {
      // Gradient from Gray to Red
      double ratio = (rsi - 50.0) / 20.0; 
      bgColor = MixColors(clrGray, clrRed, ratio);
   }
   else 
   {
      // Gradient from Green to Gray
      double ratio = (rsi - 30.0) / 20.0;
      bgColor = MixColors(clrGreen, clrGray, ratio);
   }

   // --- 3. Fill the Pixel Buffer
   // Reset buffer with the calculated background color
   ArrayFill(ExtImgBuffer, 0, InpWidth * InpHeight, bgColor);
   
   // --- 4. Draw Text onto the Buffer
   // We use TextOut to draw directly into the pixel array
   string text = "RSI: " + DoubleToString(rsi, 2);
   
   // Setup Font
   TextSetFont("Arial", -200, FW_BOLD, 0); // -200 = 20pt size
   
   // Calculate text dimensions to center it
   uint w, h;
   TextGetSize(text, w, h);
   int textX = (InpWidth - (int)w) / 2;
   int textY = (InpHeight - (int)h) / 2;
   
   // Draw the text (White color)
   TextOut(text, textX, textY, TA_LEFT|TA_TOP, ExtImgBuffer, InpWidth, InpHeight, ColorToARGB(clrWhite), COLOR_FORMAT_ARGB_NORMALIZE);
   
   // --- 5. Create/Update the Resource
   // This pushes the array data into the graphical resource memory
   if(!ResourceCreate(ExtResourceName, ExtImgBuffer, InpWidth, InpHeight, 0, 0, InpWidth, COLOR_FORMAT_ARGB_NORMALIZE))
   {
      Print("Failed to create resource");
      return;
   }
   
   // --- 6. Force Chart Redraw
   ChartRedraw();
}

//+------------------------------------------------------------------+
//| Helper: Mix two colors based on a ratio (0.0 to 1.0)             |
//+------------------------------------------------------------------+
uint MixColors(color c1, color c2, double ratio)
{
   if(ratio < 0) ratio = 0;
   if(ratio > 1) ratio = 1;
   
   // Extract RGB components
   int r1 = (c1      ) & 0xFF;
   int g1 = (c1 >> 8 ) & 0xFF;
   int b1 = (c1 >> 16) & 0xFF;
   
   int r2 = (c2      ) & 0xFF;
   int g2 = (c2 >> 8 ) & 0xFF;
   int b2 = (c2 >> 16) & 0xFF;
   
   // Interpolate
   int r = (int)(r1 + (r2 - r1) * ratio);
   int g = (int)(g1 + (g2 - g1) * ratio);
   int b = (int)(b1 + (b2 - b1) * ratio);
   
   // Recombine and add Alpha channel (255 = fully opaque)
   return ColorToARGB(RGB(r, g, b), 255);
}

Key Functions Explained

  1. uint ExtImgBuffer[]:
    This array holds the raw pixel data. The size must be Width * Height. The format is ARGB (Alpha, Red, Green, Blue).

  2. ColorToARGB(color, alpha):
    Standard MQL4 colors (like clrRed) do not have transparency information. This function converts them to uint with an Alpha channel.

    • alpha=255: Fully Opaque.
    • alpha=0: Fully Transparent.
  3. TextOut(...):
    This function draws text directly into your uint array. This is significantly faster and cleaner than creating separate OBJ_LABEL objects on top of your image.

  4. ResourceCreate(...):
    This is the engine. It takes your uint array and converts it into a graphical resource in the terminal's memory.

    • Resource Name: Must start with :: (e.g., ::MyImage).
    • Color Format: Use COLOR_FORMAT_ARGB_NORMALIZE to ensure transparency and anti-aliasing (for text) render correctly.
  5. OBJ_BITMAP_LABEL:
    This is the container object on the chart. You do not set its color or text properties; you only set OBJPROP_BMPFILE to the name of your dynamic resource.

Q&A: Custom Graphics in MQL4

Q: Can I load an external .bmp image and modify it?
A: Yes. You can use ResourceReadImage to load a file from the MQL4/Images folder into a uint array, modify specific pixels (e.g., change a status dot from red to green), and then use ResourceCreate to update it.

Q: Why is my image black or invisible?
A: This usually happens if the Alpha channel is 0. Ensure you use ColorToARGB(color, 255) or manually set the highest 8 bits of the uint to 0xFF. Also, ensure COLOR_FORMAT_ARGB_NORMALIZE is used in ResourceCreate.

Q: Does this consume a lot of CPU?
A: ResourceCreate is relatively fast, but doing it on every tick for large images (e.g., 1920x1080) can cause lag. For small status icons or heat maps (e.g., 200x200), updating on every tick is generally fine. For larger dashboards, consider updating only when OnTimer triggers or when the underlying data changes.