🚀 AI One-Click Generation of mql4 Strategy Code

Mql4 Tutorial: How to Create and Manage Dynamic On-Chart Graphical Resources with ResourceCreate() and ResourceFree()

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

Problem Description

How can I create custom images or graphics directly within my code to display on a chart?

Solution

To create custom images or graphics directly within your MQL4 code without loading external files, you need to use Dynamic Resources.

The process involves three main steps:

  1. Data Preparation: Create an array of type uint (unsigned integer) representing the pixels.
  2. Resource Creation: Use ResourceCreate() to convert that array into a graphical resource in memory.
  3. Display: Create a chart object (usually OBJ_BITMAP_LABEL) and bind it to that resource.

MQL4 Code Example: Dynamic Graphics Generator

This Expert Advisor demonstrates how to generate a gradient background with a moving circle directly in the code.

//+------------------------------------------------------------------+
//|                                        DynamicGraphicsDemo.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

//--- Input Parameters
input int      CanvasWidth  = 300;   // Width of the image
input int      CanvasHeight = 200;   // Height of the image
input color    CircleColor  = clrRed;// Color of the moving circle

//--- Global Variables
uint     g_pixels[];              // The pixel array (buffer)
string   g_resourceName = "::MyDynamicImage"; // Resource name must start with "::"
string   g_objectName   = "MyBitmapLabel";    // Name of the chart object
int      g_circleX      = 0;      // Current X position of circle
int      g_circleY      = 100;    // Current Y position of circle
int      g_direction    = 5;      // Movement speed/direction

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   // 1. Resize the pixel array to fit the dimensions
   ArrayResize(g_pixels, CanvasWidth * CanvasHeight);
   
   // 2. Create the chart object to display the image
   if(!ObjectCreate(0, g_objectName, OBJ_BITMAP_LABEL, 0, 0, 0))
   {
      Print("Failed to create object");
      return(INIT_FAILED);
   }
   
   // 3. Configure Object Properties
   ObjectSetInteger(0, g_objectName, OBJPROP_XDISTANCE, 50); // 50 pixels from left
   ObjectSetInteger(0, g_objectName, OBJPROP_YDISTANCE, 50); // 50 pixels from top
   ObjectSetInteger(0, g_objectName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, g_objectName, OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER);
   
   // 4. Bind the object to the dynamic resource name
   // Note: The resource doesn't exist yet, but we bind the name now.
   ObjectSetString(0, g_objectName, OBJPROP_BMPFILE, g_resourceName);
   
   // 5. Enable timer for animation (every 50 milliseconds)
   EventSetMillisecondTimer(50);
   
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   EventKillTimer();
   
   // Clean up the object
   ObjectDelete(0, g_objectName);
   
   // Free the memory used by the resource
   ResourceFree(g_resourceName);
}

//+------------------------------------------------------------------+
//| Timer function (Animation Loop)                                  |
//+------------------------------------------------------------------+
void OnTimer()
{
   // Update logic: Move the circle back and forth
   g_circleX += g_direction;
   if(g_circleX > CanvasWidth - 20 || g_circleX < 20) g_direction *= -1;
   
   // Redraw the scene
   DrawScene();
}

//+------------------------------------------------------------------+
//| Function to draw pixels into the array and update resource       |
//+------------------------------------------------------------------+
void DrawScene()
{
   // --- Step A: Clear the background (Fill with a gradient) ---
   for(int y = 0; y < CanvasHeight; y++)
   {
      for(int x = 0; x < CanvasWidth; x++)
      {
         // Calculate array index: y * width + x
         int i = y * CanvasWidth + x;
         
         // Create a gradient color based on X position
         // Alpha (transparency) is the highest byte (0xFF = fully opaque)
         uchar alpha = 255; 
         uchar red   = (uchar)((double)x / CanvasWidth * 255.0);
         uchar green = (uchar)((double)y / CanvasHeight * 255.0);
         uchar blue  = 50;
         
         // Combine channels into one uint color (ARGB format)
         g_pixels[i] = ColorToARGB(C'0,0,0', alpha) | (red << 16) | (green << 8) | blue;
      }
   }
   
   // --- Step B: Draw a Circle ---
   int radius = 20;
   uint circleColorUint = ColorToARGB(CircleColor, 255); // Convert MQL color to ARGB
   
   for(int y = -radius; y <= radius; y++)
   {
      for(int x = -radius; x <= radius; x++)
      {
         if(x*x + y*y <= radius*radius) // Circle equation
         {
            int drawX = g_circleX + x;
            int drawY = g_circleY + y;
            
            // Boundary checks to prevent array out of range
            if(drawX >= 0 && drawX < CanvasWidth && drawY >= 0 && drawY < CanvasHeight)
            {
               int i = drawY * CanvasWidth + drawX;
               g_pixels[i] = circleColorUint;
            }
         }
      }
   }
   
   // --- Step C: Update the Resource ---
   // This pushes the pixel array into the resource memory
   if(!ResourceCreate(g_resourceName, g_pixels, CanvasWidth, CanvasHeight, 0, 0, 0, COLOR_FORMAT_ARGB_NORMALIZE))
   {
      Print("ResourceCreate failed");
      return;
   }
   
   // --- Step D: Force Chart Redraw ---
   ChartRedraw();
}

Key Concepts Explained

1. The Pixel Buffer (uint[])

Images in MQL4 are essentially 1-dimensional arrays of unsigned integers.

  • Size: Width * Height.
  • Indexing: To access the pixel at coordinates (x, y), the formula is index = y * Width + x.

2. Color Format (ARGB)

Standard MQL4 colors (like clrRed) are just integers, but for resources, you must explicitly handle the Alpha channel (transparency).

  • Format: 0xAARRGGBB (Alpha, Red, Green, Blue).
  • Helper Function: ColorToARGB(color_value, alpha_value) converts standard colors to this format.
    • alpha=255: Fully Opaque.
    • alpha=0: Fully Transparent (invisible).

3. ResourceCreate

This is the engine of the operation.

  • Name: Must start with :: (e.g., "::MyImage"). This tells MT4 it is a dynamic resource in memory, not a file on the disk.
  • Update: Calling ResourceCreate repeatedly with the same name updates the image. This allows for animation (as shown in the OnTimer function).

4. OBJ_BITMAP_LABEL

This is the graphical object used to display the resource.

  • You set its OBJPROP_BMPFILE property to the resource name ("::MyImage").
  • Unlike OBJ_LABEL (which is text), this object renders raw pixel data.

Q&A

Q: Can I load an image from the disk and then modify it?
A: Yes. You can use ResourceReadImage to load a .bmp file into a uint array, modify the pixels in the array using the logic above, and then save it back using ResourceCreate.

Q: Why do colors look wrong when I manually set the integer?
A: You might be mixing up RGB and BGR, or forgetting the Alpha channel. If the Alpha channel is 0, the pixel will be invisible. Always use ColorToARGB or ensure you bitwise shift the Alpha byte (0xFF << 24) correctly.

Q: Is this CPU intensive?
A: It can be. Iterating through 60,000 pixels (300x200) every 50ms is generally fine, but generating full-screen HD graphics (1920x1080) in MQL4 on every tick will lag the terminal. Keep your canvas size reasonable.