🚀 AI One-Click Generation of mql4 Strategy Code

Mql4 Guide: Using `SetIndexStyle()` to Create Arrow, Section, and Histogram Indicators

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

Problem Description

How do I create a custom indicator that plots arrows on the chart instead of a line?

Solution

To create a custom indicator that plots arrows in MQL4, you need to configure the indicator buffers to use the DRAW_ARROW style and assign specific Wingdings codes to represent the arrow shapes.

Below is a complete, fully commented example of a custom indicator. This example implements a simple Moving Average Crossover strategy: it plots a Blue Up Arrow when a fast MA crosses above a slow MA, and a Red Down Arrow when it crosses below.

MQL4 Code: Arrow Indicator Example

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

//--- 1. Indicator Settings
#property indicator_chart_window    // Draw on the main chart
#property indicator_buffers 2       // We need 2 buffers: one for Buy arrows, one for Sell arrows
#property indicator_color1  clrBlue // Color for Buffer 0 (Buy)
#property indicator_color2  clrRed  // Color for Buffer 1 (Sell)

//--- 2. Input Parameters
input int FastMA_Period = 9;
input int SlowMA_Period = 21;
input ENUM_MA_METHOD MA_Method = MODE_EMA;

//--- 3. Indicator Buffers
double BuyArrowBuffer[];
double SellArrowBuffer[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
   //--- 4. Configure Buffer 0 (Buy Arrows)
   SetIndexBuffer(0, BuyArrowBuffer);
   SetIndexStyle(0, DRAW_ARROW);       // Set drawing style to ARROW
   SetIndexArrow(0, 233);              // Wingdings code 233 is an Up Arrow
   SetIndexLabel(0, "Buy Signal");
   SetIndexEmptyValue(0, 0.0);         // Value to indicate "no drawing"

   //--- 5. Configure Buffer 1 (Sell Arrows)
   SetIndexBuffer(1, SellArrowBuffer);
   SetIndexStyle(1, DRAW_ARROW);       // Set drawing style to ARROW
   SetIndexArrow(1, 234);              // Wingdings code 234 is a Down Arrow
   SetIndexLabel(1, "Sell Signal");
   SetIndexEmptyValue(1, 0.0);         // Value to indicate "no drawing"

   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| 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[])
{
   //--- 6. Determine the range of bars to calculate
   int limit = rates_total - prev_calculated;
   
   // If this is the first run, calculate all bars
   if(prev_calculated == 0) limit = rates_total - 1;
   
   // Main calculation loop (running from oldest to newest)
   for(int i = limit; i > 0; i--)
   {
      // Calculate Moving Averages for current bar (i) and previous bar (i+1)
      double fastCurr = iMA(NULL, 0, FastMA_Period, 0, MA_Method, PRICE_CLOSE, i);
      double slowCurr = iMA(NULL, 0, SlowMA_Period, 0, MA_Method, PRICE_CLOSE, i);
      
      double fastPrev = iMA(NULL, 0, FastMA_Period, 0, MA_Method, PRICE_CLOSE, i+1);
      double slowPrev = iMA(NULL, 0, SlowMA_Period, 0, MA_Method, PRICE_CLOSE, i+1);

      //--- 7. Logic for Buy Signal (Crossover Up)
      if(fastPrev < slowPrev && fastCurr > slowCurr)
      {
         // Place arrow slightly below the Low price
         BuyArrowBuffer[i] = low[i] - 10 * Point; 
         SellArrowBuffer[i] = 0.0; // Ensure no sell signal here
      }
      //--- 8. Logic for Sell Signal (Crossover Down)
      else if(fastPrev > slowPrev && fastCurr < slowCurr)
      {
         // Place arrow slightly above the High price
         SellArrowBuffer[i] = high[i] + 10 * Point;
         BuyArrowBuffer[i] = 0.0; // Ensure no buy signal here
      }
      //--- No Signal
      else
      {
         BuyArrowBuffer[i] = 0.0;
         SellArrowBuffer[i] = 0.0;
      }
   }

   return(rates_total);
}
//+------------------------------------------------------------------+

Key Functions Explained

  1. #property indicator_chart_window:
    This tells MT4 to draw the indicator directly on the price chart (where candles are), rather than in a separate window at the bottom (like RSI or MACD).

  2. SetIndexStyle(index, DRAW_ARROW):
    This is the most critical function. It changes the drawing mode from the default line to symbols.

  3. SetIndexArrow(index, code):
    This defines which symbol to draw. The code corresponds to the Wingdings font character map.

    • 233: Up Arrow
    • 234: Down Arrow
    • 241: Thumb Up
    • 242: Thumb Down
    • 251: X mark
    • 159: Big Dot
  4. SetIndexEmptyValue(index, 0.0):
    Unlike a line indicator which draws a value at every bar, arrows only appear on specific events. This function tells MT4: "If the value in the buffer is 0.0, do not draw anything."

  5. Positioning (low[i] - 10 * Point):
    When assigning a value to the buffer in OnCalculate, you are setting the Y-axis price where the arrow appears.

    • For a Buy arrow, we usually set it slightly below the Low of the candle so it doesn't overlap the chart.
    • For a Sell arrow, we set it slightly above the High.

How to Install

  1. Open MetaTrader 4.
  2. Press F4 to open the MetaEditor.
  3. Click New -> Custom Indicator -> Name it "SimpleArrowIndicator".
  4. Paste the code above into the file, replacing everything.
  5. Press F7 to Compile.
  6. Go back to the main MT4 window, find "SimpleArrowIndicator" in the Navigator, and drag it onto a chart.

Q&A

Q: How do I change the size of the arrows?
A: You can use the SetIndexStyle function with an additional parameter for width. For example: SetIndexStyle(0, DRAW_ARROW, STYLE_SOLID, 3); where 3 is the thickness (size) of the arrow.

Q: Can I use custom images instead of Wingdings?
A: No, standard MQL4 buffers (DRAW_ARROW) only support Wingdings font codes. To use custom images (bmp), you would need to use ObjectCreate with OBJ_BITMAP_LABEL, which is significantly more complex and slower for backtesting.

Q: Why do my arrows disappear when I refresh the chart?
A: This usually happens if the logic inside OnCalculate relies on static variables that reset, or if the limit calculation is incorrect. Ensure your loop correctly handles prev_calculated to recalculate history if necessary, or simply recalculate the visible bars.

Q: How do I find other arrow shapes?
A: In MetaEditor, go to Help -> MQL4 Reference. Search for "Wingdings". It will provide a table of all available icons and their corresponding integer codes.