Support & Resistance Indicator for MetaTrader 5: What It Is, How It Works, and Its Benefits

Support and resistance are two of the most important concepts in technical analysis. Traders use these price levels to identify areas where the market may react, reverse, pause, or continue its movement. However, manually identifying support and resistance levels can be time-consuming, especially when the market is moving quickly.

Support & Resistance Indicator for MetaTrader 5: What It Is, How It Works, and Its Benefits


The Support & Resistance Indicator for MetaTrader 5 is designed to help traders automatically identify and display potential support and resistance areas based on Fractals. Instead of manually searching through historical candles, the indicator continuously processes market data and maintains the most recently identified support and resistance levels directly on the chart.

This article explains what the indicator is, how it works, how to read it, and what benefits it can provide when used as part of a technical analysis strategy.

1. What Is the Support & Resistance Indicator?

The Support & Resistance Indicator is a custom MT5 indicator that uses the built-in Fractals indicator as its primary source of information.

The purpose of the indicator is simple:

  • Identify potential resistance points using upper fractals.
  • Identify potential support points using lower fractals.
  • Display the identified levels on the price chart.
  • Keep the latest identified support and resistance price available across subsequent candles.

In the source code, the indicator creates two primary buffers:

double SellBuffer[];
double BuyBuffer[];

These buffers are responsible for storing and displaying the support and resistance values calculated by the indicator.

The indicator is configured to run directly in the main chart window, meaning traders can see the calculated levels together with the normal candlesticks.

2. What Is a Fractal?

To understand how this indicator works, it is important to understand the concept of a Fractal.

A market fractal is a price pattern that identifies a local turning point. In general, an upper fractal occurs around a local high, while a lower fractal occurs around a local low.

An upper fractal can be interpreted as an area where buying momentum previously pushed the market upward, but the price subsequently failed to continue higher. This makes the area potentially useful as a resistance reference.

A lower fractal represents the opposite situation. The market previously moved downward but then found buying pressure around that area. Therefore, the level can potentially act as support.

The important point is that a fractal is based on historical price structure. It does not guarantee that price will reverse from the level in the future.

3. How Does the Indicator Work?

The indicator first creates a handle for the MT5 Fractals indicator:

FRA_Handle = iFractals(NULL, 0);

This tells MetaTrader 5 to use the Fractals indicator for the current symbol and current timeframe.

If MetaTrader cannot create the Fractals handle, the indicator stops initialization and reports an error. This is important because the support and resistance calculations depend on the Fractals data.

Reading the Fractal Data

The indicator then copies the upper and lower fractal information into two arrays:

CopyBuffer(FRA_Handle, 0, 0, to_copy, FRAUp);
CopyBuffer(FRA_Handle, 1, 0, to_copy, FRALo);

The first buffer contains upper fractal information, while the second contains lower fractal information.

The indicator then checks every relevant candle and determines whether a fractal exists.

When an upper fractal is detected, the indicator stores the candle's high price:

if (upVel && upVel != EMPTY_VALUE)
{
    BuyBuffer[bar] = high[bar];
}

Similarly, when a lower fractal is detected, it stores the candle's low price:

if (loVel && loVel != EMPTY_VALUE)
{
    SellBuffer[bar] = low[bar];
}

This process allows the indicator to extract important price points from the fractal structure.

4. How Does It Maintain the Support and Resistance Levels?

One of the useful characteristics of this indicator is that it does not simply display a value on the candle where the fractal occurs and then immediately remove it.

Instead, when a new fractal is not detected, the indicator carries forward the previous value:

BuyBuffer[bar] = BuyBuffer[bar + 1];

and:

SellBuffer[bar] = SellBuffer[bar + 1];

This means that the latest detected support or resistance price can continue to be represented across subsequent candles until another relevant fractal replaces it.

Conceptually, this creates a continuously updated reference level.

5. Support and Resistance in Practical Trading

Support is generally considered an area where selling pressure may decrease and buying pressure may increase. When price approaches support, traders may watch for evidence that buyers are becoming active.

Resistance is generally considered an area where buying pressure may decrease and selling pressure may increase. When price approaches resistance, traders may watch for evidence of rejection or a potential reversal.

The indicator provides these levels automatically, allowing traders to focus more on price behavior around the levels rather than spending time manually identifying every previous swing point.

6. How to Use the Indicator

Using the indicator is straightforward.

Step 1: Open MetaTrader 5

Open your MetaTrader 5 platform and select the financial instrument you want to analyze. The indicator can be used on different markets and timeframes, depending on the trader's strategy.

Step 2: Select a Timeframe

Select the desired timeframe, such as M15, M30, H1, H4, or another timeframe.

The fractal calculations are based on the timeframe currently being displayed. Therefore, changing the timeframe can change the location of the identified support and resistance levels.

Step 3: Attach the Indicator

Add the Support & Resistance indicator to the chart.

The indicator will calculate the Fractals data and begin displaying the corresponding support and resistance information.

Step 4: Observe Price Reaction

Do not use the level simply because it exists. Instead, observe how price behaves when it approaches the level.

For example, if price approaches a resistance level and produces several rejection candles, this may provide additional evidence that sellers are active.

Likewise, if price approaches a support level and produces bullish rejection or strong buying momentum, traders may consider this additional evidence that the support area is being defended.

7. Using Support and Resistance for Entries

The indicator can be used as a reference for potential trade entries, but the level itself should not automatically be treated as a trading signal.

For a potential buy setup, a trader may look for:

  • Price approaching a support level.
  • A rejection of lower prices.
  • A bullish candlestick pattern.
  • Increasing buying momentum.
  • Confirmation from another technical indicator or market structure.

For a potential sell setup, a trader may look for:

  • Price approaching a resistance level.
  • A rejection of higher prices.
  • A bearish candlestick pattern.
  • Increasing selling momentum.
  • Confirmation from another technical indicator or market structure.

This approach is generally more reliable than entering a trade solely because price has reached a support or resistance level.

8. Using the Indicator for Stop Loss Placement

Support and resistance can also be useful when determining potential stop-loss locations.

For example, if a trader opens a buy position near support, the trader may consider placing the stop loss below the relevant support structure rather than placing it at an arbitrary distance.

For a sell position near resistance, the stop loss may be considered above the relevant resistance structure.

However, the appropriate stop-loss distance depends on the market's volatility, timeframe, trading strategy, spread, and risk management rules.

The indicator itself does not calculate a recommended stop-loss or take-profit value. It simply provides a price-structure reference that traders can incorporate into their own risk-management decisions.

9. Using the Indicator for Breakout Trading

Support and resistance levels can also be used for breakout analysis.

Suppose price repeatedly approaches a resistance level. Eventually, price may break above that level with strong momentum.

Instead of treating every touch as a sell signal, a breakout trader may wait for price to move above the resistance and then look for confirmation that the breakout is genuine.

The same concept applies to support. If price breaks below an established support level, traders may monitor the market for bearish continuation.

In some situations, a broken resistance level can later become support, while a broken support level can later become resistance. This behavior is commonly referred to as a role reversal.

10. Multi-Timeframe Analysis

One of the strongest ways to use support and resistance is through multi-timeframe analysis.

For example, a trader could use a higher timeframe such as H4 to understand the larger market structure and then use H1 or M15 to search for more precise entry opportunities.

A support or resistance level that appears significant on a higher timeframe may be more important than a level that exists only on a very low timeframe.

However, higher-timeframe levels do not guarantee a reversal. Markets can break significant levels when momentum, volatility, or fundamental factors are strong enough.

11. Benefits of This Indicator

The Support & Resistance Indicator provides several practical benefits.

Automatic Level Detection

The indicator automatically processes fractal information, reducing the need to manually identify every local high and low.

Visual Market Structure

The displayed levels help traders understand where important historical price reactions have occurred.

Time Saving

Instead of manually scanning many candles, traders can use the indicator as an initial reference when analyzing a chart.

Useful for Different Strategies

The levels can be incorporated into reversal strategies, breakout strategies, trend-following strategies, price-action analysis, and multi-timeframe analysis.

Works Directly on the MT5 Chart

Because the indicator is designed for MetaTrader 5's main chart window, traders can analyze the calculated levels together with candlestick price action.

12. Important Limitations

Although the indicator can be useful, traders should understand its limitations.

First, Fractals are based on historical price information. A newly forming market structure may not immediately be confirmed as a fractal.

Second, support and resistance are not guaranteed reversal points. Price can break through any historical level.

Third, the indicator does not analyze economic news, market sentiment, liquidity, fundamental events, or unexpected volatility.

Fourth, using an indicator alone is generally not enough to create a complete trading system.

For these reasons, traders should combine the indicator with appropriate risk management and, when appropriate, other forms of technical or fundamental analysis.

13. Understanding the Buy and Sell Buffer Names

An important technical detail in the source code is that the buffer names are called BuyBuffer and SellBuffer. These names describe how the developer organized the data internally, but they should not automatically be interpreted as direct buy and sell trading signals.

The indicator is fundamentally designed to represent support and resistance information.

A support level does not necessarily mean "buy now," and a resistance level does not necessarily mean "sell now."

Instead, these levels should be treated as areas where traders should pay closer attention to price action.

14. Why Confirmation Is Important

Suppose the indicator identifies a support level at a particular price. Price reaches the level, but instead of bouncing upward, it continues falling strongly.

This demonstrates why the level should not be treated as an automatic trading signal.

A more complete trading process could be:

  1. Identify the support or resistance level.
  2. Wait for price to approach the level.
  3. Observe price action around the level.
  4. Look for confirmation.
  5. Define the trade's stop-loss level.
  6. Calculate the acceptable position size based on risk.
  7. Define the potential reward or take-profit objective.
  8. Only then consider executing the trade.

This process transforms the indicator from a simple visual tool into one component of a more structured trading methodology.

15. Final Conclusion

The Support & Resistance Indicator for MetaTrader 5 is a useful technical-analysis tool that automatically identifies price levels using the MT5 Fractals calculation.

Its primary purpose is to make important historical price areas easier to observe. Upper fractals are used to identify potential resistance information, while lower fractals are used to identify potential support information. Once a level is identified, the indicator carries the latest value forward until another relevant fractal updates the structure.

The biggest benefit is convenience. Traders do not have to manually inspect every historical candle to locate potential swing points. The indicator provides a continuously updated reference that can be used alongside candlestick analysis, market structure, trend analysis, breakout strategies, and multi-timeframe analysis.

However, it is important to remember that support and resistance are areas of interest, not guaranteed trading signals. Markets can reject a level, consolidate around it, or break through it completely.

Therefore, the best way to use this indicator is as part of a complete trading plan. Combine the identified levels with price action, trend direction, market structure, volatility, confirmation signals, and disciplined risk management.

When used in this way, the Support & Resistance Indicator can become a valuable tool for helping traders answer one of the most important questions in technical analysis:

"Where are the important price areas that the market may react to next?"

By automatically highlighting these areas, the indicator can help make chart analysis more structured, consistent, and efficient.

16. FullSource Code


//+------------------------------------------------------------------+
//|                                       Support_and_Resistance.mq5 |
//|                                       Copyright © 2005,  Дмитрий |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2006, MetaQuotes Software Corp."
#property link "http://www.metaquotes.net/"
//---- номер версии индикатора
#property version "1.12"
//---- отрисовка индикатора в главном окне
#property indicator_chart_window
//---- для расчета и отрисовки индикатора использовано два буфера
#property indicator_buffers 2
//---- использовано всего два графических построения
#property indicator_plots 2
//+----------------------------------------------+
//|  объявление констант                         |
//+----------------------------------------------+
#define RESET 0 // Константа для возврата терминалу команды на пересчет индикатора
//+----------------------------------------------+
//|  Параметры отрисовки медвежьего индикатора   |
//+----------------------------------------------+
//---- отрисовка индикатора 1 в виде символа
#property indicator_type1 DRAW_ARROW
//---- в качестве цвета уровней поддержки использован розовый цвет
#property indicator_color1 clrDarkGreen
//---- толщина линии индикатора 1 равна 1
#property indicator_width1 1
//---- отображение метки поддержки
#property indicator_label1 "Support"
//+----------------------------------------------+
//|  Параметры отрисовки бычьго индикатора       |
//+----------------------------------------------+
//---- отрисовка индикатора 2 в виде символа
#property indicator_type2 DRAW_ARROW
//---- в качестве цвета уровней сопротивления использован зеленый цвет
#property indicator_color2 clrMaroon
//---- толщина линии индикатора 2 равна 1
#property indicator_width2 1
//---- отображение метки сопротивления
#property indicator_label2 "Resistance"

//+----------------------------------------------+
//| Входные параметры индикатора                 |
//+----------------------------------------------+

//+----------------------------------------------+

//---- объявление динамических массивов, которые будут в
// дальнейшем использованы в качестве индикаторных буферов
double SellBuffer[];
double BuyBuffer[];
//---
int StartBars;
int FRA_Handle;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit() {
   //---- инициализация глобальных переменных
   StartBars = 6;
   //---- получение хендла индикатора iFractals
   FRA_Handle = iFractals(NULL, 0);
   if (FRA_Handle == INVALID_HANDLE) {
      Print(" Не удалось получить хендл индикатора iFractals");
      return (INIT_FAILED);
   }

   //---- превращение динамического массива в индикаторный буфер
   SetIndexBuffer(0, SellBuffer, INDICATOR_DATA);
   //---- осуществление сдвига начала отсчета отрисовки индикатора 1
   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, StartBars);
   //--- создание метки для отображения в DataWindow
   PlotIndexSetString(0, PLOT_LABEL, "Support");
   //---- символ для индикатора
   PlotIndexSetInteger(0, PLOT_ARROW, 158);
   //---- индексация элементов в буфере как в таймсерии
   ArraySetAsSeries(SellBuffer, true);

   //---- превращение динамического массива в индикаторный буфер
   SetIndexBuffer(1, BuyBuffer, INDICATOR_DATA);
   //---- осуществление сдвига начала отсчета отрисовки индикатора 2
   PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, StartBars);
   //--- создание метки для отображения в DataWindow
   PlotIndexSetString(1, PLOT_LABEL, "Resistance");
   //---- символ для индикатора
   PlotIndexSetInteger(1, PLOT_ARROW, 158);
   //---- индексация элементов в буфере как в таймсерии
   ArraySetAsSeries(BuyBuffer, true);

   //---- Установка формата точности отображения индикатора
   IndicatorSetInteger(INDICATOR_DIGITS, _Digits);
   //---- имя для окон данных и лэйба для субъокон
   string short_name = "Support & Resistance";
   IndicatorSetString(INDICATOR_SHORTNAME, short_name);
   //--- завершение инициализации
   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[]) {
                           
   double bidPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double askPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   
   // Calculate the price directly between Bid and Ask
   double midPrice = (bidPrice + askPrice) / 2.0;

   //---- проверка количества баров на достаточность для расчета
   if (BarsCalculated(FRA_Handle) < rates_total || rates_total < StartBars) return (RESET);

   //---- объявления локальных переменных
   int to_copy, limit, bar;
   double FRAUp[], FRALo[], upVel, loVel;

   //---- расчеты необходимого количества копируемых данных
   //---- и стартового номера limit для цикла пересчета баров
   if (prev_calculated > rates_total || prev_calculated <= 0) // проверка на первый старт расчета индикатора
   {
      to_copy = rates_total; // расчетное количество всех баров
      limit = rates_total - StartBars - 1; // стартовый номер для расчета всех баров
   } else {
      to_copy = rates_total - prev_calculated + 3; // расчетное количество только новых баров
      limit = rates_total - prev_calculated + 2; // стартовый номер для расчета новых баров
   }

   //---- индексация элементов в массивах как в таймсериях  
   ArraySetAsSeries(FRAUp, true);
   ArraySetAsSeries(FRALo, true);
   ArraySetAsSeries(high, true);
   ArraySetAsSeries(low, true);

   //---- копируем вновь появившиеся данные в массивы
   if (CopyBuffer(FRA_Handle, 0, 0, to_copy, FRAUp) <= 0) return (RESET);
   if (CopyBuffer(FRA_Handle, 1, 0, to_copy, FRALo) <= 0) return (RESET);

   //---- основной цикл расчета индикатора
   for (bar = limit; bar >= 0; bar--) {
      BuyBuffer[bar] = EMPTY_VALUE;
      SellBuffer[bar] = EMPTY_VALUE;
      
      //----
      upVel = FRAUp[bar];
      loVel = FRALo[bar];
      
      //----
      if (upVel && upVel != EMPTY_VALUE) {
         BuyBuffer[bar] = high[bar];
      } else {
         BuyBuffer[bar] = BuyBuffer[bar + 1];
      }
      
      if (loVel && loVel != EMPTY_VALUE) {
         SellBuffer[bar] = low[bar];
      } else {
         SellBuffer[bar] = SellBuffer[bar + 1];
      }
      
   }
   //----    
   return (rates_total);
}
//+------------------------------------------------------------------+

Power Multiplier Levels (PML) Indicator for MT5 – Complete Guide and Explanation

In this article I will explain the functionality and working logic of my custom MetaTrader 5 indicator called Power Multiplier Levels (PML). This indicator is designed to generate multiple horizontal price levels from a selected H1 candle using a mathematical multiplier. The generated levels can be used as potential support, resistance, expansion, target, and reaction zones.

Power Multiplier Levels (PML) Indicator for MT5


Unlike traditional indicators such as Moving Averages, RSI, or MACD, this indicator does not calculate momentum or trend strength. Instead, it projects future price levels from a specific candle using predefined multiplication formulas for each trading instrument.

Best use: XAUUSD (Gold), EURUSD, GBPUSD, USDJPY, and other forex pairs.

What Is the Purpose of This Indicator?

The main objective of the PML indicator is to help traders identify structured price levels above and below a selected reference candle. The indicator automatically draws a series of horizontal lines based on a mathematical multiplier that is specific to the chosen symbol.

The indicator can be used for:

  • Intraday trading
  • Swing trading
  • Gold trading (XAUUSD)
  • Target projection
  • Support and resistance mapping
  • Reaction zone analysis

How the Indicator Works

The indicator starts by finding a specific H1 candle using the date and time inputs:

TargetYear
TargetMonth
TargetDay
TargetHour
TargetMinute

Once the candle is found, the indicator extracts two base prices:

  • firstHigh – the base for downward projections
  • firstLow – the base for upward projections

These values can be taken from:

  • The candle High/Low
  • The candle Open/Close range

Buy, Sell, or Both Modes

The indicator provides three operating modes:

BUYSELL
BUY
SELL

BUYSELL

Draws both upward and downward levels.

BUY

Draws only the downward projection levels from the selected high.

SELL

Draws only the upward projection levels from the selected low.

Symbol-Specific Multipliers

One of the unique features of this indicator is that each instrument has its own predefined multiplier.

EURUSD  = 1.00512148471
GBPUSD  = 1.00701748471
USDJPY  = 100.701748471
XAUUSD  = 1.0084149257

For upward projections:

price = price * Multiplier

For downward projections:

price = price / Multiplier

This creates a geometric expansion and contraction of price levels rather than a fixed pip distance.

Example on XAUUSD

Suppose the selected candle has:

High = 3400.00
Low  = 3380.00
Multiplier = 1.0084149257

Upward Levels

Level 1 = 3380 × 1.0084149257 = 3408.44
Level 2 = 3408.44 × 1.0084149257 = 3437.12
Level 3 = 3437.12 × 1.0084149257 = 3466.03

Downward Levels

Level 1 = 3400 ÷ 1.0084149257 = 3371.63
Level 2 = 3371.63 ÷ 1.0084149257 = 3343.49
Level 3 = 3343.49 ÷ 1.0084149257 = 3315.59

These levels are automatically drawn on the chart.

Choosing the Base Candle

The indicator searches all H1 candles and compares their date and time with the target inputs.

if (t.year == TargetYear &&
    t.mon  == TargetMonth &&
    t.day  == TargetDay &&
    t.hour == TargetHour &&
    t.min  == TargetMinute)

When the candle is found, the base prices are stored and used for all calculations.

Base High and Base Low Options

Highest / Lowest

Uses the actual candle high and low.

firstHigh = iHigh(...)
firstLow  = iLow(...)

HighOpenClose / LowOpenClose

Uses the candle body instead of the wick.

For bullish candles:

firstHigh = Close
firstLow  = Open

For bearish candles:

firstHigh = Open
firstLow  = Close

This is useful for traders who want levels based on the candle body rather than extreme spikes.

Deviation Feature

The indicator includes an optional deviation calculation.

input double Deviation = 0.0;

When the value is not zero, additional gray lines are drawn.

For upward levels:

dev = price * Deviation;

For downward levels:

dev = price / Deviation;

These can be used as secondary target zones or reaction buffers.

Visual Appearance

The indicator draws:

  • Maroon lines for upward levels
  • Green lines for downward levels
  • Gray lines for deviation levels

Every line also receives a text label showing the exact price.

DoubleToString(price, _Digits)

Why Horizontal Lines?

Horizontal levels are easy to read and remain fixed while new candles form. This makes them very practical for:

  • Take profit placement
  • Stop loss planning
  • Breakout confirmation
  • Reversal observation

Practical Trading Workflow

For SELL Setup

  1. Choose the important H1 candle.
  2. Set mode to SELL.
  3. Use the upward maroon levels as resistance zones.
  4. Look for bearish confirmation near the levels.

For BUY Setup

  1. Set mode to BUY.
  2. Use the downward green levels as support zones.
  3. Wait for bullish confirmation before entering.

Suggested Settings for Gold (XAUUSD)

ChooseBuySell = BUYSELL
ChooseRumus   = XAUUSD
ChooseBaseHigh = Highest
ChooseBaseLow  = Lowest
Deviation = 0.0

Select the first H1 candle of the trading session that you want to analyze.

Advantages of the Indicator

  • Very lightweight
  • No repainting
  • Works on any MT5 chart
  • Clear visual levels
  • Customizable colors
  • Body-based or wick-based calculation
  • Suitable for manual trading and algorithmic analysis

Limitations

This indicator is not a complete trading system. It does not provide:

  • Buy/sell signals
  • Trend detection
  • Risk management
  • Automatic trade execution

The levels should be combined with price action, market structure, volume, or other confirmation tools.

Who Should Use This Indicator?

This indicator is especially useful for:

  • Gold traders
  • Forex intraday traders
  • Support/resistance traders
  • Session breakout traders
  • Traders who prefer objective price levels

Conclusion

The Power Multiplier Levels (PML) MT5 Indicator is a unique price-projection tool that generates structured horizontal levels from a selected H1 candle using instrument-specific mathematical multipliers.

Instead of relying on lagging indicators, this approach focuses on predefined price geometry. The indicator can help traders map potential support and resistance zones, project targets, and organize market structure in a clean and objective way.

For best results, combine the PML levels with:

  • Market structure
  • Break of structure (BOS)
  • Liquidity zones
  • Candlestick confirmation
  • Session analysis

I personally use this indicator as a framework for identifying high-probability reaction areas on XAUUSD and major forex pairs. Because the calculations are deterministic and non-repainting, the levels remain stable and easy to evaluate during live trading.

If you want to improve the indicator further, you can add alerts, automatic session detection, multi-timeframe support, or dynamic level extensions.

Full Source Code


#property indicator_chart_window
#property indicator_plots 0
#property strict

enum TheBuySell {
   BUYSELL,
   BUY,
   SELL,
};

input TheBuySell ChooseBuySell = BUYSELL;

enum TheRumus {
   AUDUSD, // 1.00612148471 AUDUSD
   EURGBP, // 1.0034149257 EURGBP
   EURJPY, // 100.612148471 EURJPY
   EURUSD, // 1.00512148471 EURUSD
   GBPAUD, // 1.0084149257 GBPAUD
   GBPJPY, // 100.84149257 GBPJPY
   GBPUSD, // 1.00701748471 GBPUSD
   NZDUSD, // 1.0068149257 NZDUSD
   USDJPY, // 100.701748471 USDJPY
   XAUUSD, // 1.0084149257 XAUUSD
};
input TheRumus ChooseRumus = XAUUSD;

input int TargetYear    = 2026;
input int TargetMonth   = 8;
input int TargetDay     = 10;
input int TargetHour    = 1;
input int TargetMinute  = 0;

input double Deviation = 0.0;

input color UpperColor = clrMaroon;
input color LowerColor = clrGreen;
input color DeviationColor = clrGray;

enum TheBaseHigh {
   Highest,
   HighOpenClose,
};
input TheBaseHigh ChooseBaseHigh = Highest;

enum TheBaseLow {
   Lowest,
   LowOpenClose,
};
input TheBaseLow ChooseBaseLow = Lowest;

int NumLines = 9;

// Adjust according to broker server time
//input int ServerToJakartaOffsetHours = 0;

double firstHigh, firstLow, Multiplier;

int OnInit() {
   DrawLevels();
   return (INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
   ObjectsDeleteAll(0, "PML_");
}

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[]) {
   return (rates_total);
}

void DrawLevels() {
   ObjectsDeleteAll(0, "PML_");

   if (!GetTargetCandle()) {
      Print("Target candle not found.");
      return;
   }

   if(ChooseBuySell == BUYSELL || ChooseBuySell == SELL) {
      DrawLine("PML_BASE_UP", firstLow, UpperColor);
      DrawText("PML_TEXT_BASE_UP", firstLow, UpperColor);
   }

   if(ChooseBuySell == BUYSELL || ChooseBuySell == BUY) {
      DrawLine("PML_BASE_DOWN", firstHigh, LowerColor);
      DrawText("PML_TEXT_BASE_DOWN", firstHigh, LowerColor);
   }

   double price;
   double dev;

   switch(ChooseRumus) {
      case AUDUSD: Multiplier = 1.00612148471; break;
      case EURGBP: Multiplier = 1.0034149257; break;
      case EURJPY: Multiplier = 100.612148471; break;
      case EURUSD: Multiplier = 1.00512148471; break;
      case GBPAUD: Multiplier = 1.0084149257; break;
      case GBPJPY: Multiplier = 100.84149257; break;
      case GBPUSD: Multiplier = 1.00701748471; break;
      case NZDUSD: Multiplier = 1.0068149257; break;
      case USDJPY: Multiplier = 100.701748471; break;
      case XAUUSD: Multiplier = 1.0084149257; break;
   }
   
   if(ChooseBuySell == BUYSELL || ChooseBuySell == SELL) {
      // UP
      price = firstLow;
   
      for (int i = 1; i <= NumLines; i++) {
         price *= Multiplier;
   
         DrawLine("PML_UP_" + IntegerToString(i), price, UpperColor);
         DrawText("PML_UP_TXT_" + IntegerToString(i), price, UpperColor);
   
         if (Deviation != 0) {
            dev = price * Deviation;
            DrawLine("PML_DEV_UP_" + IntegerToString(i), dev, DeviationColor);
            DrawText("PML_DEV_UP_TXT_" + IntegerToString(i), dev, DeviationColor);
         }
      }
   }

   if(ChooseBuySell == BUYSELL || ChooseBuySell == BUY) {
      // DOWN
      price = firstHigh;
   
      for (int i = 1; i <= NumLines; i++) {
         price /= Multiplier;
   
         DrawLine("PML_DOWN_" + IntegerToString(i), price, LowerColor);
         DrawText("PML_DOWN_TXT_" + IntegerToString(i), price, LowerColor);
   
         if (Deviation != 0) {
            dev = price / Deviation;
            DrawLine("PML_DEV_DOWN_" + IntegerToString(i), dev, DeviationColor);
            DrawText("PML_DEV_DOWN_TXT_" + IntegerToString(i), dev, DeviationColor);
         }
      }
   }
}

bool GetTargetCandle() {
   int bars = iBars(_Symbol, PERIOD_H1);

   for (int i = 0; i < bars; i++) {
      datetime serverTime = iTime(_Symbol, PERIOD_H1, i);

      MqlDateTime t;
      TimeToStruct(serverTime, t);

      if (t.year == TargetYear &&
         t.mon == TargetMonth &&
         t.day == TargetDay &&
         t.hour == TargetHour &&
         t.min == TargetMinute) {
         
         if(ChooseBaseHigh == Highest) {
            firstHigh = iHigh(_Symbol, PERIOD_H1, i);
         } else {
            if(iClose(_Symbol, PERIOD_H1, i) > iOpen(_Symbol, PERIOD_H1, i)) {
               firstHigh = iClose(_Symbol, PERIOD_H1, i);
            } else {
               firstHigh = iOpen(_Symbol, PERIOD_H1, i);
            }
         }
         
         if(ChooseBaseLow == Lowest) {
            firstLow = iLow(_Symbol, PERIOD_H1, i);
         } else {
            if(iClose(_Symbol, PERIOD_H1, i) > iOpen(_Symbol, PERIOD_H1, i)) {
               firstLow = iOpen(_Symbol, PERIOD_H1, i);
            } else {
               firstLow = iClose(_Symbol, PERIOD_H1, i);
            }
         }

         return (true);
      }
   }

   return (false);
}

void DrawLine(string name, double price, color clr) {
   ObjectCreate(0, name, OBJ_HLINE, 0, 0, price);
   ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
   ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
   ObjectSetInteger(0, name, OBJPROP_BACK, true);
   ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID);
}

void DrawText(string name, double price, color clr) {
   datetime t = iTime(_Symbol, _Period, 0);

   ObjectCreate(0, name, OBJ_TEXT, 0, t, price);
   ObjectSetString(0, name, OBJPROP_TEXT, DoubleToString(price, _Digits));
   ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
}


Thank you for reading this article. Feel free to test the indicator on a demo account first and adapt the settings to your broker and trading session.

EMA Cross Arrow Input for MT5 – Complete Trading Guide

The EMA_Cross_Arrow_Input.mq5 indicator is a custom MetaTrader 5 (MT5) indicator based on one of the most popular concepts in technical analysis: the Exponential Moving Average (EMA) crossover.

EMA Cross Arrow Input for MT5 – Complete Trading Guide


This indicator plots three EMA lines and can optionally display buy and sell arrows when the fast EMA crosses the mid EMA. Although the code is relatively short, it contains several practical features that make it useful for trend identification, momentum analysis, and trade timing.


What Is an Exponential Moving Average (EMA)?

A moving average smooths price data to help traders identify the underlying trend. The Exponential Moving Average (EMA) gives more weight to recent prices, making it more responsive than the Simple Moving Average (SMA).

For example:

  • EMA 8 reacts quickly to price changes.
  • EMA 20 reacts more slowly.
  • EMA 50 reacts even more slowly and often represents the broader trend.

When a faster EMA crosses above a slower EMA, it suggests increasing bullish momentum. When it crosses below, it suggests increasing bearish momentum.


Overview of the Indicator

Default Settings

  • Fast EMA: 8 periods (orange)
  • Mid EMA: 20 periods (green)
  • Slow EMA: 50 periods (blue)
  • ArrowSignal: false by default

The indicator displays:

  • Orange line = fast EMA
  • Green line = mid EMA
  • Blue line = slow EMA
  • Aqua up arrows = buy signals
  • Orange down arrows = sell signals

How the Indicator Works

The indicator is drawn directly on the chart window using:

#property indicator_chart_window

It uses five buffers:

  1. Fast EMA values
  2. Mid EMA values
  3. Slow EMA values
  4. Buy arrow positions
  5. Sell arrow positions

The EMA buffers store the moving average values, while the arrow buffers store the price level where an arrow should appear.


User Inputs

One of the best features is that the EMA periods are fully customizable from the MT5 input window.

input int  FastMAPeriod = 8;
input int  MidMAPeriod  = 20;
input int  SlowMAPeriod = 50;
input bool ArrowSignal  = false;

Common Alternatives

Style Settings
Scalping 5 / 13 / 34
Intraday 8 / 20 / 50
Swing trading 10 / 21 / 55
Position trading 20 / 50 / 200

Initialization Process

During OnInit() the indicator performs three important tasks.

1. Bind Buffers

SetIndexBuffer(0, FastBuffer, INDICATOR_DATA);

2. Set Arrow Symbols

PlotIndexSetInteger(3, PLOT_ARROW, 233);
PlotIndexSetInteger(4, PLOT_ARROW, 234);
  • 233 = upward arrow
  • 234 = downward arrow

3. Create EMA Handles

hFastMA = iMA(_Symbol, _Period, FastMAPeriod, 0, MODE_EMA, PRICE_CLOSE);

The EMAs are calculated from the closing price.


Calculation Logic

Inside OnCalculate() the indicator first checks that enough candles exist.

int minBars = MathMax(MathMax(FastMAPeriod, MidMAPeriod), SlowMAPeriod) + 5;

Then it copies the EMA values into the custom buffers.

CopyBuffer(hFastMA, 0, 0, rates_total, FastBuffer);

Crossover Detection

Bullish Crossover

bool crossUp =
   (FastBuffer[i + 1] <= MidBuffer[i + 1]) &&
   (FastBuffer[i] >  MidBuffer[i]);

This means:

  • Previous closed candle: fast EMA was below or equal to mid EMA.
  • Current closed candle: fast EMA is above mid EMA.

Bearish Crossover

bool crossDown =
   (FastBuffer[i + 1] >= MidBuffer[i + 1]) &&
   (FastBuffer[i] <  MidBuffer[i]);

Why Closed Candles Matter

The indicator checks closed candles only. This is important because EMAs can cross and uncross during a forming candle, creating false signals.

Using closed candles:

  • reduces noise,
  • avoids unstable signals,
  • improves reliability for manual and automated trading.

Arrow Placement

Buy arrows are placed slightly below the candle:

BuyBuffer[i] = low[i] - 10 * _Point;

Sell arrows are placed slightly above the candle:

SellBuffer[i] = high[i] + 10 * _Point;

The Role of the 50 EMA

The 50 EMA is not used for generating arrows. It acts as a trend filter.

  • EMA 8 = short-term momentum
  • EMA 20 = signal line
  • EMA 50 = higher-timeframe trend context

Trading with the Indicator

Bullish Setup

Conditions:

  • Price above 50 EMA
  • EMA 8 crosses above EMA 20
  • Buy arrow appears

Entry: Buy at the next candle open.

Stop loss:

  • below the signal candle,
  • below EMA 20,
  • or below the recent swing low.

Take profit:

  • 1:2 or 1:3 risk-reward,
  • next resistance,
  • or trail below EMA 20.

Bearish Setup

Conditions:

  • Price below 50 EMA
  • EMA 8 crosses below EMA 20
  • Sell arrow appears

Entry: Sell at the next candle open.

Stop loss:

  • above the signal candle,
  • above EMA 20,
  • or above the recent swing high.

Take profit:

  • support level,
  • fixed RR target,
  • or trail above EMA 20.

Best Timeframes

Timeframe Quality
M1 Poor
M5 Fair
M15 Good
H1 Very good
H4 Excellent
D1 Excellent

Market Conditions

Trending Markets

The indicator performs best when:

  • EMAs are clearly separated,
  • price respects EMA 20,
  • crossovers occur after pullbacks.

Ranging Markets

It performs poorly when:

  • EMAs are intertwined,
  • price moves sideways,
  • crossovers happen frequently.

Improving the Strategy

Use the 50 EMA Filter

  • Buy signals above EMA 50
  • Sell signals below EMA 50

Add Higher Timeframe Confirmation

Example:

  • H4 trend bullish
  • H1 buy crossover

Combine with Support and Resistance

Signals near strong support or resistance are usually higher probability.


Risk Management

  • Risk 0.5% to 1% per trade
  • Avoid major news events
  • Do not take every arrow blindly
  • Wait for trend alignment

Advantages

  • Simple and easy to understand
  • Customizable EMA periods
  • Works on any MT5 symbol
  • Uses closed-candle confirmation
  • Visual arrows for quick scanning
  • Suitable for manual or automated trading

Limitations

  • Lagging indicator
  • Whipsaws in sideways markets
  • No built-in stop loss or take profit
  • No volatility filter
  • No multi-timeframe confirmation

Example Workflow (XAUUSD H1)

  1. Check H4 trend using EMA 50.
  2. Wait for a pullback to EMA 20 on H1.
  3. Wait for EMA 8 to cross above EMA 20.
  4. Confirm with a bullish candle close.
  5. Enter at the next candle.
  6. Place stop below the pullback low.
  7. Target 2R or trail behind EMA 20.

Conclusion

The EMA_Cross_Arrow_Input.mq5 indicator is a practical MT5 tool for trend-following and momentum trading.

Its three-EMA structure provides:

  • EMA 8: fast momentum
  • EMA 20: signal confirmation
  • EMA 50: trend context

The optional arrows make chart scanning easier, while the use of closed candles improves signal stability.

However, no moving-average system is perfect. The indicator works best when combined with market structure, support and resistance, higher-timeframe analysis, and disciplined risk management.

Used correctly, this indicator can become a solid foundation for intraday trading, swing trading, and MT5 algorithmic trading strategies.

Full Source Code


//+------------------------------------------------------------------+
//|                    EMA_Cross_Arrow_Input.mq5                     |
//|           EMA periods can be changed from indicator inputs       |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_buffers 5
#property indicator_plots   5

//--- Fast MA
#property indicator_label1  "Fast MA"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrOrange
#property indicator_width1  1

//--- Mid MA
#property indicator_label2  "Mid MA"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrGreen
#property indicator_width2  1

//--- Slow MA
#property indicator_label3  "Slow MA"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrBlue
#property indicator_width3  1

//--- Buy arrows
#property indicator_label4  "Buy"
#property indicator_type4   DRAW_ARROW
#property indicator_color4  clrAqua
#property indicator_width4  2

//--- Sell arrows
#property indicator_label5  "Sell"
#property indicator_type5   DRAW_ARROW
#property indicator_color5  clrOrange
#property indicator_width5  2

//--- Inputs
input int  FastMAPeriod = 8;
input int  MidMAPeriod  = 20;
input int  SlowMAPeriod = 50;
input bool ArrowSignal  = false;

//--- Buffers
double FastBuffer[];
double MidBuffer[];
double SlowBuffer[];
double BuyBuffer[];
double SellBuffer[];

//--- Handles
int hFastMA, hMidMA, hSlowMA;

//+------------------------------------------------------------------+
//| Initialization                                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   //--- Bind buffers
   SetIndexBuffer(0, FastBuffer, INDICATOR_DATA);
   SetIndexBuffer(1, MidBuffer,  INDICATOR_DATA);
   SetIndexBuffer(2, SlowBuffer, INDICATOR_DATA);
   SetIndexBuffer(3, BuyBuffer,  INDICATOR_DATA);
   SetIndexBuffer(4, SellBuffer, INDICATOR_DATA);

   //--- Arrow symbols
   PlotIndexSetInteger(3, PLOT_ARROW, 233);
   PlotIndexSetInteger(4, PLOT_ARROW, 234);

   //--- Create EMA handles
   hFastMA = iMA(_Symbol, _Period, FastMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
   hMidMA  = iMA(_Symbol, _Period, MidMAPeriod,  0, MODE_EMA, PRICE_CLOSE);
   hSlowMA = iMA(_Symbol, _Period, SlowMAPeriod, 0, MODE_EMA, PRICE_CLOSE);

   if(hFastMA == INVALID_HANDLE || hMidMA == INVALID_HANDLE || hSlowMA == INVALID_HANDLE)
      return(INIT_FAILED);

   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Calculation                                                      |
//+------------------------------------------------------------------+
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[])
{
   int minBars = MathMax(MathMax(FastMAPeriod, MidMAPeriod), SlowMAPeriod) + 5;

   if(rates_total < minBars)
      return(0);

   //--- Copy EMA values
   CopyBuffer(hFastMA, 0, 0, rates_total, FastBuffer);
   CopyBuffer(hMidMA,  0, 0, rates_total, MidBuffer);
   CopyBuffer(hSlowMA, 0, 0, rates_total, SlowBuffer);

   //--- Start point
   int start = (prev_calculated > 1) ? prev_calculated - 1 : 1;

   for(int i = start; i < rates_total - 1; i++)
   {
      BuyBuffer[i]  = EMPTY_VALUE;
      SellBuffer[i] = EMPTY_VALUE;

      if(!ArrowSignal)
         continue;

      //--- Closed candle crossover
      bool crossUp =
         (FastBuffer[i + 1] <= MidBuffer[i + 1]) &&
         (FastBuffer[i] >  MidBuffer[i]);

      bool crossDown =
         (FastBuffer[i + 1] >= MidBuffer[i + 1]) &&
         (FastBuffer[i] <  MidBuffer[i]);

      //--- Buy signal
      if(crossUp)
         BuyBuffer[i] = low[i] - 10 * _Point;

      //--- Sell signal
      if(crossDown)
         SellBuffer[i] = high[i] + 10 * _Point;
   }

   return(rates_total);
}

//+------------------------------------------------------------------+
//| Deinitialization                                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   if(hFastMA != INVALID_HANDLE) IndicatorRelease(hFastMA);
   if(hMidMA  != INVALID_HANDLE) IndicatorRelease(hMidMA);
   if(hSlowMA != INVALID_HANDLE) IndicatorRelease(hSlowMA);
}
//+------------------------------------------------------------------+

(Update) High Open Low Indicator (Automatic Fibonacci) MT5

In this update I want to explain the newest version of my MQL5 indicator called HOL Indicator v3. This version is not only a visual Fibonacci tool, but also a complete intraday trading assistant for MetaTrader 5. The main purpose of this indicator is to display the most important price levels of the current trading day and the previous trading day, while also providing additional information such as average daily range, spread, time remaining in the current candle, floating profit or loss, and optional alert signals. The indicator works directly on the chart window and uses chart objects instead of traditional indicator buffers, which makes the display clean and lightweight. The indicator is designed especially for traders who focus on price action, market structure, and intraday reversals.

The core concept of the HOL indicator is based on three important levels: today’s open price, today’s highest price, and today’s lowest price. In this version I create a Fibonacci object from the lowest price to the highest price of the current H1 trading session. The open price is then calculated as a Fibonacci level between those two extremes. This gives a very clear visual representation of where the market opened relative to the current daily range. I believe this information is very useful because many institutional and intraday traders pay close attention to the opening price of the day. The same logic is also applied to yesterday’s data, so traders can compare today’s movement with the previous day’s structure.

One important improvement in version 3 is the synchronization and safety check before any calculation is executed. The indicator first waits until H1 data is fully synchronized and ensures that enough bars are available. This prevents many common errors that can happen when MetaTrader is just opened or when historical data is not fully loaded. I also add protection against zero range calculations. If the range between the highest and lowest price is too small, the indicator will skip the Fibonacci calculation instead of producing invalid values or division-by-zero errors.

The object management is also improved. All objects created by the indicator contain a unique name with the prefix “holo”. During deinitialization the indicator automatically scans all chart objects and deletes only the objects that belong to this indicator. This is very useful when changing timeframe, removing the indicator, or updating the code, because it keeps the chart clean and avoids leaving old Fibonacci objects behind.

Another feature that I add in this update is the secondary open level analysis. The indicator can scan a lower timeframe, for example M5, and find the highest open price and the lowest open price of the current day. These levels are drawn as dashed horizontal trend lines. In my trading approach these secondary open levels can act as intraday reaction zones. When price moves above the highest M5 open but still remains below the daily high, the indicator can generate a potential sell alert. When price moves below the lowest M5 open but remains above the daily low, the indicator can generate a potential buy alert. The alert system can be enabled or disabled through the input settings.

I also add a detailed information panel using the Comment function. The panel displays GMT time, server time, and local time. This helps traders who work with multiple sessions or compare broker time with real market sessions. The panel also shows the Average Daily Range based on the last nine completed trading days, today’s current range in both pips and points, and the percentage of today’s range relative to the ADR. This gives a quick measurement of whether the market is still quiet or has already expanded significantly.

(Update) High Open Low Indicator (Automatic Fibonacci) MT5

In addition, the panel shows the current Ask price, the current spread, and the remaining time before the current candle closes. For active traders this information is very practical because it is available directly on the chart without opening other windows. I also include a floating PnL calculation for all open positions of the current symbol. The indicator sums the profit or loss in points, making it easy to monitor exposure while analyzing the chart.

The CreateTodayH1Line function is one of the most important parts of the code. It identifies the first H1 candle of the current broker day, gets its open price, and then scans all H1 candles from that point until the current time to find the highest and lowest prices. After that it creates a Fibonacci object and assigns custom colors for the highest, lowest, and open levels. The highest level is shown in maroon, the lowest level in dark green, and the open level in purple. I intentionally use different colors so the structure can be recognized instantly even when many objects are present on the chart.

The CreateYesterdayH1Line function is simpler because it uses completed D1 data. Since yesterday is already finished, the indicator can directly obtain the high, low, open, and close values from the daily timeframe. The Fibonacci object is then projected from the beginning of yesterday to the beginning of today. This creates a stable reference that does not repaint during the current session.

I also include utility functions for calculating Average Daily Range and converting it into points. These functions ignore the current unfinished day and use only completed daily candles, which produces more reliable statistics. Another helper function calculates the total floating PnL of all open positions on the current symbol. Although this is not required for drawing Fibonacci levels, I add it because it makes the indicator more informative during live trading.

Overall, HOL Indicator v3 is a significant upgrade compared with my previous versions. The indicator combines daily structure, intraday structure, volatility measurement, session information, object management, and optional signal alerts in a single lightweight tool. My goal is not to create a fully automated trading system, but to build a visual decision-support indicator that helps traders read the market more clearly. I use this indicator mainly for intraday trading on pairs such as XAUUSD and major forex symbols, especially when I want to compare the current price with today’s open, today’s range, and yesterday’s structure.

Source Code


//+------------------------------------------------------------------+
//|                          HOL v3.mq5                              |
//|         Fibo from Highest Close (0%) to Lowest Close (100%)      |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_plots 0 // No plots, only objects

//+------------------------------------------------------------------+
//| Custom Settings                                                  |
//+------------------------------------------------------------------+
input bool     ShowAlert            = true; // Turn on Alert
input bool     ShowToday            = true; // Today Line
input bool     ShowYesterday        = true; // Yesterday Line
input color    ColorOpen            = clrPurple;
input color    ColorHighest         = clrMaroon;
input color    ColorLowest          = clrDarkGreen;
input bool     SecondaryLine        = true;
input ENUM_TIMEFRAMES SecondLineTF  = PERIOD_M5;

string fiboName = "holo";

int OnInit() {
   return (INIT_SUCCEEDED);
}

void OnDeinit(const int reason) {
   int total = ObjectsTotal(0, 0, -1);

   for (int i = total - 1; i >= 0; i--) {
      string name = ObjectName(0, i, 0, -1);

      // delete only Fibonacci objects with "holo" in the name
      if (StringFind(name, fiboName) >= 0) {
         ObjectDelete(0, name);
      }
   }
   Comment("");
}

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[]) {

   //--- Wait until synchronize
   if (!SeriesInfoInteger(_Symbol, PERIOD_H1, SERIES_SYNCHRONIZED))
      return rates_total;

   //--- Wait until data enough
   if (Bars(_Symbol, PERIOD_H1) < 10)
      return rates_total;

   if (ShowToday) {
      CreateTodayH1Line(fiboName);
   }

   if (ShowYesterday) {
      CreateYesterdayH1Line(fiboName);
   }

   double todayRange = iHigh(_Symbol, PERIOD_D1, 0) - iLow(_Symbol, PERIOD_D1, 0);

   if (MathAbs(todayRange) <= _Point) {
      Print("Range not ready yet, skip fibo calculation");
      return rates_total;
   }

   double averageRange = GetAverageDailyRange(9);
   double averageRangePoint = GetAverageDailyRangePoints(9);
   double todayRangePercent = (todayRange / averageRange) * 100.00;

   string theComment = "--- HOL indicator v3 ---\n";
   theComment = theComment + "\nGMT Date Time = " + TimeToString(TimeGMT(), TIME_DATE | TIME_SECONDS);
   theComment = theComment + "\nServer Date Time = " + TimeToString(TimeCurrent(), TIME_DATE | TIME_SECONDS);
   theComment = theComment + "\nLocal Date Time = " + TimeToString(TimeLocal(), TIME_DATE | TIME_SECONDS);
   theComment = theComment + "\n";
   theComment = theComment + "\nADR (9 days) = " + DoubleToString(averageRange, 0) + " pips / " + DoubleToString(averageRangePoint, 0) + " point";
   theComment = theComment + "\nToday Range = " + DoubleToString(todayRange, 0) + " pips / " + DoubleToString(todayRange / _Point, 0) + " point / " + DoubleToString(todayRangePercent, 2) + "%";
   theComment = theComment + "\n";
   theComment = theComment + "\nPrice = " + DoubleToString(SymbolInfoDouble(_Symbol, SYMBOL_ASK), Digits());
   theComment = theComment + "\nSpread = " + IntegerToString(SymbolInfoInteger(_Symbol, SYMBOL_SPREAD));
   theComment = theComment + "\nBar End = " + TimeToString((iTime(_Symbol, _Period, 0) + PeriodSeconds(_Period)) - TimeCurrent(), TIME_SECONDS);
   theComment = theComment + "\nPnL = " + DoubleToString(GetTotalPnLPips(), 0) + " point";
   theComment = theComment + "\n";

   Comment(theComment);

   return (rates_total);

}

//+------------------------------------------------------------------+
//| Create Fibonacci H1 Today                                        |
//+------------------------------------------------------------------+
void CreateTodayH1Line(string name = "HOLO") {

   //--- fibo name
   int dayShift = 0;
   name = name + "H1" + IntegerToString(dayShift);

   //--- start of today
   datetime today = StringToTime(TimeToString(TimeCurrent(), TIME_DATE));

   //--- shift of first H1 candle today (00:00)
   int firstShift = iBarShift(_Symbol, PERIOD_H1, today, false);

   if (iTime(_Symbol, PERIOD_H1, firstShift) < today) {
      firstShift--;
   }

   if (firstShift < 0) {
      Print("Cannot find today's H1 candle");
      return;
   }

   //--- open of first H1 candle today
   double open = iOpen(_Symbol, PERIOD_H1, firstShift);

   //--- find highest and lowest H1 of today
   double highest = -DBL_MAX;
   double lowest = DBL_MAX;

   // scan from first H1 candle today down to current H1 candle
   for (int i = firstShift; i >= 0; i--) {
      datetime t = iTime(_Symbol, PERIOD_H1, i);

      if (t < today)
         break;

      double h = iHigh(_Symbol, PERIOD_H1, i);
      double l = iLow(_Symbol, PERIOD_H1, i);

      if (h > highest) highest = h;
      if (l < lowest) lowest = l;
   }

   //--- remove old fibo if exists
   ObjectDelete(0, name);

   //--- create Fibonacci object
   datetime time1 = iTime(_Symbol, PERIOD_H1, firstShift); // 00:00 H1
   datetime time2 = TimeCurrent();

   if (!ObjectCreate(0, name, OBJ_FIBO, 0, time1, lowest, time2, highest)) {
      Print("Failed to create Fibonacci");
      return;
   }

   //--- style
   ObjectSetInteger(0, name, OBJPROP_COLOR, clrNONE);
   ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
   ObjectSetInteger(0, name, OBJPROP_RAY_RIGHT, true);
   ObjectSetInteger(0, name, OBJPROP_LEVELCOLOR, 0, ColorHighest);
   ObjectSetInteger(0, name, OBJPROP_LEVELCOLOR, 1, ColorLowest);
   ObjectSetInteger(0, name, OBJPROP_LEVELCOLOR, 2, ColorOpen);
   ObjectSetInteger(0, name, OBJPROP_BACK, true);
   ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID);

   //--- levels: Open, High, Low
   ObjectSetInteger(0, name, OBJPROP_LEVELS, 3);

   // Level 0 = Highest
   ObjectSetDouble(0, name, OBJPROP_LEVELVALUE, 0, 0.0);
   ObjectSetString(0, name, OBJPROP_LEVELTEXT, 0, IntegerToString(dayShift) + " H1 highest" + " = %$  ");

   // Level 1 = Lowest
   ObjectSetDouble(0, name, OBJPROP_LEVELVALUE, 1, 1.0);
   ObjectSetString(0, name, OBJPROP_LEVELTEXT, 1, IntegerToString(dayShift) + " H1 lowest" + " = %$  ");

   // Level 2 = Open
   double rangeHighestLowest = highest - lowest;
   if (MathAbs(rangeHighestLowest) <= _Point) {
      Print("Range not ready yet, skip fibo calculation");
      return;
   }
   double openLevel = ((highest - open) / rangeHighestLowest) * 1.0;

   ObjectSetDouble(0, name, OBJPROP_LEVELVALUE, 2, openLevel);
   ObjectSetString(0, name, OBJPROP_LEVELTEXT, 2, IntegerToString(dayShift) + " H1 open" + " = %$  ");

   //Print(_Symbol, " Today Open=", open, " Highest=", highest, " Lowest=", lowest);

   if (SecondaryLine) {
      string SecondaryHighName = name + "HighSecondary";
      string SecondaryLowName = name + "LowSecondary";

      // Delete old objects
      ObjectDelete(0, SecondaryHighName);
      ObjectDelete(0, SecondaryLowName);

      // Start of today (broker time)
      datetime today = StringToTime(TimeToString(TimeCurrent(), TIME_DATE));

      // Find first M5 bar of today
      int firstShift = iBarShift(_Symbol, SecondLineTF, today, false);

      if (firstShift < 0) {
         Print("Cannot find first M5 bar of today");
         return;
      }

      double SecondaryHighestOpen = -DBL_MAX;
      double SecondaryLowestOpen = DBL_MAX;

      int SecondaryHighestShift = -1;
      int SecondaryLowestShift = -1;

      // Scan all M5 bars of today
      for (int i = firstShift; i >= 0; i--) {

         double op = iOpen(_Symbol, SecondLineTF, i);

         if (op > SecondaryHighestOpen) {
            SecondaryHighestOpen = op;
            SecondaryHighestShift = i;
         }

         if (op < SecondaryLowestOpen) {
            SecondaryLowestOpen = op;
            SecondaryLowestShift = i;
         }
      }

      if (SecondaryHighestShift == -1 || SecondaryLowestShift == -1)
         return;

      datetime time1 = iTime(_Symbol, SecondLineTF, firstShift);
      datetime time2 = TimeCurrent();

      //--- Create highest open trend line
      ObjectCreate(0, SecondaryHighName, OBJ_TREND, 0, time1, SecondaryHighestOpen, time2, SecondaryHighestOpen);
      ObjectSetInteger(0, SecondaryHighName, OBJPROP_COLOR, ColorHighest);
      ObjectSetInteger(0, SecondaryHighName, OBJPROP_WIDTH, 1);
      ObjectSetInteger(0, SecondaryHighName, OBJPROP_RAY_RIGHT, true);
      ObjectSetInteger(0, SecondaryHighName, OBJPROP_STYLE, STYLE_DASHDOT);

      //--- Create lowest open trend line
      ObjectCreate(0, SecondaryLowName, OBJ_TREND, 0, time1, SecondaryLowestOpen, time2, SecondaryLowestOpen);
      ObjectSetInteger(0, SecondaryLowName, OBJPROP_COLOR, ColorLowest);
      ObjectSetInteger(0, SecondaryLowName, OBJPROP_WIDTH, 1);
      ObjectSetInteger(0, SecondaryLowName, OBJPROP_RAY_RIGHT, true);
      ObjectSetInteger(0, SecondaryLowName, OBJPROP_STYLE, STYLE_DASHDOT);

      if (ShowAlert) {

         MqlTick last_tick;
         SymbolInfoTick(_Symbol, last_tick);

         double currentBid = last_tick.bid;
         if (currentBid > SecondaryHighestOpen && currentBid < highest) {
            Alert("Alhamdulillah, " + _Symbol + " SELL signal");
         }

         double currentAsk = last_tick.bid;
         if (currentAsk < SecondaryLowestOpen && currentAsk > lowest) {
            Alert("Alhamdulillah, " + _Symbol + " BUY signal, Bismillahirrohmanirrohim!!");
         }

      }

   }

}

//+------------------------------------------------------------------+
//| Create Fibonacci H1 Yesterday                                    |
//+------------------------------------------------------------------+
void CreateYesterdayH1Line(string name = "HOLO") {
   //--- fibo name
   int dayShift = 1;
   name = name + "H1" + IntegerToString(dayShift);

   //--- Get OHLC   
   double highest = iHigh(_Symbol, PERIOD_D1, dayShift);
   double lowest = iLow(_Symbol, PERIOD_D1, dayShift);
   double open = iOpen(_Symbol, PERIOD_D1, dayShift);
   double close = iClose(_Symbol, PERIOD_D1, dayShift);

   //--- remove old fibo if exists
   ObjectDelete(0, name);

   //--- create Fibonacci object
   datetime timeStart = iTime(_Symbol, PERIOD_D1, dayShift);
   datetime timeEnd = iTime(_Symbol, PERIOD_D1, dayShift - 1);

   if (!ObjectCreate(0, name, OBJ_FIBO, 0, timeStart, lowest, timeEnd, highest)) {
      Print("Failed to create Fibonacci");
      return;
   }

   //--- style
   ObjectSetInteger(0, name, OBJPROP_COLOR, clrNONE);
   ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
   ObjectSetInteger(0, name, OBJPROP_RAY_RIGHT, true);
   ObjectSetInteger(0, name, OBJPROP_RAY_LEFT, false);
   ObjectSetInteger(0, name, OBJPROP_LEVELCOLOR, 0, ColorHighest);
   ObjectSetInteger(0, name, OBJPROP_LEVELCOLOR, 1, ColorLowest);
   ObjectSetInteger(0, name, OBJPROP_LEVELCOLOR, 2, ColorOpen);
   ObjectSetInteger(0, name, OBJPROP_BACK, true);
   ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID);

   //--- levels: Open, High, Low
   ObjectSetInteger(0, name, OBJPROP_LEVELS, 3);

   // Level 0 = Highest
   ObjectSetDouble(0, name, OBJPROP_LEVELVALUE, 0, 0.0);
   ObjectSetString(0, name, OBJPROP_LEVELTEXT, 0, IntegerToString(dayShift) + " H1 highest" + " = %$  ");

   // Level 1 = Lowest
   ObjectSetDouble(0, name, OBJPROP_LEVELVALUE, 1, 1.0);
   ObjectSetString(0, name, OBJPROP_LEVELTEXT, 1, IntegerToString(dayShift) + " H1 lowest" + " = %$  ");

   // Level 2 = Open
   double rangeHighestLowest = highest - lowest;
   if (MathAbs(rangeHighestLowest) <= _Point) {
      Print("Range not ready yet, skip fibo calculation");
      return;
   }
   double openLevel = ((highest - open) / rangeHighestLowest) * 1.0;

   ObjectSetDouble(0, name, OBJPROP_LEVELVALUE, 2, openLevel);
   ObjectSetString(0, name, OBJPROP_LEVELTEXT, 2, IntegerToString(dayShift) + " H1 open" + " = %$  ");

}

//+------------------------------------------------------------------+
//| Calculate total Profit/Loss of all open positions in pips        |
//+------------------------------------------------------------------+
double GetTotalPnLPips() {
   double total_pips = 0;

   for (int i = PositionsTotal() - 1; i >= 0; i--) {
      ulong ticket = PositionGetTicket(i);
      if (PositionGetString(POSITION_SYMBOL) == _Symbol) {
         double open_price = PositionGetDouble(POSITION_PRICE_OPEN);
         double current_price = (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) ?
            SymbolInfoDouble(_Symbol, SYMBOL_BID) :
            SymbolInfoDouble(_Symbol, SYMBOL_ASK);

         double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
         double tick_size = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);

         // Calculate PnL in points
         double pnl_points = (current_price - open_price) / tick_size;

         // Convert points to pips
         double pnl_pips = pnl_points * (tick_size / point);

         // Add to total (for Buy, profit is positive; for Sell, profit is reversed)
         if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
            total_pips -= pnl_pips;
         else
            total_pips += pnl_pips;
      }
   }

   return total_pips;
}

//+------------------------------------------------------------------+
//| Average Daily Range (ADR) for last N completed days              |
//+------------------------------------------------------------------+
double GetAverageDailyRange(int days = 10) {
   double total = 0.0;
   int count = 0;

   // Start from yesterday (shift 1), skip current unfinished day
   for (int i = 1; i <= days; i++) {
      double high = iHigh(_Symbol, PERIOD_D1, i);
      double low = iLow(_Symbol, PERIOD_D1, i);

      if (high > 0 && low > 0) {
         total += (high - low);
         count++;
      }
   }

   if (count == 0)
      return 0.0;

   return total / count;
}

//+------------------------------------------------------------------+
//| Average Daily Range in points                                    |
//+------------------------------------------------------------------+
double GetAverageDailyRangePoints(int days = 10) {
   return GetAverageDailyRange(days) / _Point;
}

//+------------------------------------------------------------------+
//| Create horizontal trend line at H4                               |
//+------------------------------------------------------------------+
void CreateH4OpenHorizontal(string name = "H4Open", int barShift = 1) {

   name = name + "H4Open";

   datetime time1 = iTime(_Symbol, PERIOD_H4, barShift);
   datetime time2 = TimeCurrent();

   double open1 = iOpen(_Symbol, PERIOD_H4, barShift);

   if (ObjectFind(0, name) >= 0)
      ObjectDelete(0, name);

   ObjectCreate(0, name, OBJ_TREND, 0, time1, open1, time2, open1);

   ObjectSetInteger(0, name, OBJPROP_COLOR, clrOrange);
   ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
   ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DASHDOT);
   ObjectSetInteger(0, name, OBJPROP_RAY_RIGHT, true);

}

//+------------------------------------------------------------------+
//| Create trend lines on highest and lowest M5 OPEN of today        |
//+------------------------------------------------------------------+
void CreateOpenTrendLinesToday(string name = "HighestLowestOpen") {
   string highName = name + "HighSecondary";
   string lowName = name + "LowSecondary";

   // Delete old objects
   ObjectDelete(0, highName);
   ObjectDelete(0, lowName);

   // Start of today (broker time)
   datetime today = StringToTime(TimeToString(TimeCurrent(), TIME_DATE));

   // Find first M5 bar of today
   int firstShift = iBarShift(_Symbol, SecondLineTF, today, false);

   if (firstShift < 0) {
      Print("Cannot find first M5 bar of today");
      return;
   }

   double highestOpen = -DBL_MAX;
   double lowestOpen = DBL_MAX;

   int highestShift = -1;
   int lowestShift = -1;

   // Scan all M5 bars of today
   for (int i = firstShift; i >= 0; i--) {

      double op = iOpen(_Symbol, SecondLineTF, i);

      if (op > highestOpen) {
         highestOpen = op;
         highestShift = i;
      }

      if (op < lowestOpen) {
         lowestOpen = op;
         lowestShift = i;
      }
   }

   if (highestShift == -1 || lowestShift == -1)
      return;

   datetime time1 = iTime(_Symbol, SecondLineTF, firstShift);
   datetime time2 = TimeCurrent();

   //--- Create highest open trend line
   ObjectCreate(0, highName, OBJ_TREND, 0, time1, highestOpen, time2, highestOpen);
   ObjectSetInteger(0, highName, OBJPROP_COLOR, ColorHighest);
   ObjectSetInteger(0, highName, OBJPROP_WIDTH, 1);
   ObjectSetInteger(0, highName, OBJPROP_RAY_RIGHT, true);
   ObjectSetInteger(0, highName, OBJPROP_STYLE, STYLE_DASHDOT);

   //--- Create lowest open trend line
   ObjectCreate(0, lowName, OBJ_TREND, 0, time1, lowestOpen, time2, lowestOpen);
   ObjectSetInteger(0, lowName, OBJPROP_COLOR, ColorLowest);
   ObjectSetInteger(0, lowName, OBJPROP_WIDTH, 1);
   ObjectSetInteger(0, lowName, OBJPROP_RAY_RIGHT, true);
   ObjectSetInteger(0, lowName, OBJPROP_STYLE, STYLE_DASHDOT);

}

For traders who enjoy studying MQL5, this update also demonstrates several useful programming techniques such as object-oriented chart drawing, safe range calculation, multi-timeframe scanning, automatic object cleanup, and real-time information display. I hope this explanation helps readers understand both the trading logic and the programming logic behind the indicator. Thank you for following my development journey, and I will continue improving the HOL indicator in future updates as I discover new ideas and receive feedback from other traders.

Automatic Fibonacci Indicator for MT5 (fibo_a_v1) – Full Explanation and Guide

Fibonacci retracement is one of the most widely used tools in technical analysis. Traders use it to identify potential support and resistance levels, retracement zones, continuation areas, and profit targets. However, drawing Fibonacci levels manually every time the market changes can be time-consuming and inconsistent.

Automatic Fibonacci Indicator for MT5


To solve this problem, I created fibo_a_v1, an Automatic Fibonacci Indicator for MetaTrader 5 (MT5). This indicator automatically scans a selected price range, finds the highest and lowest points, and draws a Fibonacci object directly on the chart. The goal is to make Fibonacci analysis faster, cleaner, and more objective.

What Is fibo_a_v1?

fibo_a_v1 is a custom MT5 indicator that automatically creates a Fibonacci retracement and extension object between the highest high and lowest low found within a user-defined time range.

Unlike many automatic Fibonacci tools that continuously redraw based on the latest swing, this indicator allows the trader to specify:

  • A start date and time
  • A finish date and time
  • The timeframe used for analysis
  • The direction of the Fibonacci
  • The color and visual style

This gives much more control and makes the indicator useful for backtesting, session analysis, intraday trading, and swing trading.

Main Features

1. Automatic High and Low Detection

The indicator scans all candles between the selected start and finish times and automatically finds the highest price and the lowest price. This removes the need to manually select swing points.

2. Custom Timeframe Analysis

You can choose the timeframe used for Fibonacci calculation, such as M1, M5, M15, M30, H1, H4, or D1. Even if your chart is on a different timeframe, the indicator can still calculate the Fibonacci using the selected timeframe.

3. Flexible Direction

The input FiboUpToDown controls the drawing direction:

  • true → Fibonacci is drawn from Low to High
  • false → Fibonacci is drawn from High to Low

This makes the indicator suitable for both bullish and bearish analysis.

4. Extended Fibonacci Levels

In addition to the standard retracement levels, the indicator includes important extension levels:

  • 127.2%
  • 141.4%
  • 161.8%
  • 200%
  • 261.8%

These levels are useful for projecting profit targets.

5. Ray Right

The Fibonacci is extended to the right side of the chart, allowing traders to monitor future price interaction with the levels.

Input Parameters Explained

FiboTF

input ENUM_TIMEFRAMES FiboTF = PERIOD_M5;

This determines which timeframe is used for the calculation.

Example: if the chart is H1 but FiboTF = PERIOD_M5, the indicator will scan M5 candles.

StartFibo

input string StartFibo = "2026.08.07 15:40";

The beginning of the analysis range.

FinishFibo

input string FinishFibo = "2026.08.10 06:00";

The end of the analysis range.

FiboUpToDown

input bool FiboUpToDown = false;
  • false → High to Low (bearish)
  • true → Low to High (bullish)

FiboColor

input color FiboColor = clrDeepSkyBlue;

Sets the color of all Fibonacci levels.

How the Indicator Works

Step 1 – Convert Input Time

datetime StartTime = StringToTime(StartFibo);

Step 2 – Find Bar Shift

int StartShift = iBarShift(_Symbol, FiboTF, StartTime, false);

Step 3 – Scan the Range

for (int i = StartShift; i >= FinishShift; i--)

For each candle, the indicator reads the high and low values and stores the highest and lowest prices found in the selected range.

Step 4 – Draw Fibonacci

Depending on the selected direction, the Fibonacci object is created either from low to high or from high to low.

Step 5 – Apply Levels

Level Purpose
0.0%Start point
23.6%Shallow retracement
38.2%Common pullback
50.0%Psychological level
61.8%Golden ratio
78.6%Deep retracement
100%Full move
127.2%Extension target
141.4%Extension target
161.8%Major extension target
200%Strong continuation target
261.8%Extended trend target

Practical Trading Examples

Bullish Setup

Suppose EURUSD moves from 1.1000 to 1.1100.

Set:

  • StartFibo = beginning of the move
  • FinishFibo = end of the move
  • FiboUpToDown = true

The indicator will draw Fibonacci from low to high.

Possible buy zones:

  • 38.2%
  • 50%
  • 61.8%

Targets:

  • 127.2%
  • 161.8%

Bearish Setup

Suppose XAUUSD falls from 3400 to 3350.

Set FiboUpToDown = false.

The indicator draws from high to low.

Possible sell zones:

  • 38.2%
  • 50%
  • 61.8%

Targets:

  • 127.2%
  • 161.8%

Why Use Automatic Fibonacci?

  • Speed: No need to draw manually.
  • Consistency: The same rules are applied every time.
  • Backtesting: Analyze historical ranges precisely.
  • Multi-Timeframe Precision: Use M5 for precise swings while trading on H1 or H4.
  • Objective Analysis: Removes emotional swing selection.

Best Use Cases

This indicator works especially well for:

  • Intraday trading
  • London session analysis
  • New York session analysis
  • Swing trading
  • Breakout pullbacks
  • Trend continuation setups
  • Historical market study

Limitations

No indicator is perfect. Current limitations include:

  • Manual time selection is required.
  • No automatic latest swing detection.
  • No price-touch alerts.
  • Only one Fibonacci object is managed.

Installation

  1. Open MetaTrader 5.
  2. Go to File → Open Data Folder.
  3. Open MQL5 → Indicators.
  4. Copy fibo_a_v1.mq5 into the folder.
  5. Restart MT5 or refresh the Navigator.
  6. Drag the indicator onto the chart.

Recommended Settings

Trading Style Timeframe
ScalpingM1–M5
Day TradingM5–M15
Swing TradingH1–H4
Position TradingH4–D1

Final Thoughts

fibo_a_v1 is a simple but powerful MT5 indicator designed for traders who want a faster and more disciplined way to use Fibonacci analysis. By combining automatic high/low detection, custom time ranges, multi-timeframe calculation, and extended Fibonacci targets, the indicator becomes useful for both beginners and experienced traders.

I created this tool primarily for my own trading workflow, where I often need to analyze a specific market movement and project retracement and extension levels quickly. Instead of spending time drawing Fibonacci objects manually, the indicator performs the calculation instantly and keeps the chart organized.

For best results, do not use Fibonacci levels alone. Combine them with:

  • Market structure
  • Support and resistance
  • Trend analysis
  • Candlestick confirmation
  • Volume or momentum indicators

Used correctly, Fibonacci can help identify high-probability pullback zones, continuation areas, and realistic profit targets.

Full Code (Source)


//+------------------------------------------------------------------+
//|                                              fibo_a_v1.mq5       |
//|                       Automatic Fibonacci for H1 timeframe       |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property strict
#property indicator_plots 0

//--- input
input ENUM_TIMEFRAMES FiboTF        = PERIOD_M5;

input string StartFibo     = "2026.08.07 15:40";
input string FinishFibo    = "2026.08.10 06:00";

input bool           FiboUpToDown   = false;       // true=Low to High, false=High to Low
input color          FiboColor      = clrDeepSkyBlue;
input bool           ShowPrice      = true;

//--- object name
string FiboName = "fibo_a";

//+------------------------------------------------------------------+
//| Delete object                                                    |
//+------------------------------------------------------------------+
void DeleteFibo() {
   if (ObjectFind(0, FiboName) >= 0)
      ObjectDelete(0, FiboName);
}

//+------------------------------------------------------------------+
//| Draw Fibonacci                                                   |
//+------------------------------------------------------------------+
void DrawFibo() {
   //if(_Period != FiboTF)
   //return;

   datetime StartTime = StringToTime(StartFibo);
   int StartShift = iBarShift(_Symbol, FiboTF, StartTime, false);
   if (StartShift < 0) return;

   datetime FinishTime = StringToTime(FinishFibo);
   int FinishShift = iBarShift(_Symbol, FiboTF, FinishTime, false);
   if (FinishShift < 0) return;

   //--- start candle data
   datetime startTime = iTime(_Symbol, FiboTF, StartShift);

   //--- find highest and lowest from StartShift to current bar
   double highest = -DBL_MAX;
   double lowest = DBL_MAX;
   int highShift = -1;
   int lowShift = -1;

   for (int i = StartShift; i >= FinishShift; i--) {
      double h = iHigh(_Symbol, FiboTF, i);
      double l = iLow(_Symbol, FiboTF, i);

      if (h > highest) {
         highest = h;
         highShift = i;
      }

      if (l < lowest) {
         lowest = l;
         lowShift = i;
      }
   }

   datetime highTime = iTime(_Symbol, FiboTF, highShift);
   datetime lowTime = iTime(_Symbol, FiboTF, lowShift);

   DeleteFibo();

   bool created;

   if (FiboUpToDown) {
      // Low -> High
      created = ObjectCreate(0, FiboName, OBJ_FIBO, 0,
         lowTime, lowest,
         highTime, highest);
   } else {
      // High -> Low
      created = ObjectCreate(0, FiboName, OBJ_FIBO, 0,
         highTime, highest,
         lowTime, lowest);
   }

   if (!created)
      return;

   //--- style
   ObjectSetInteger(0, FiboName, OBJPROP_COLOR, clrNONE);
   ObjectSetInteger(0, FiboName, OBJPROP_WIDTH, 1);
   ObjectSetInteger(0, FiboName, OBJPROP_RAY_RIGHT, true);
   //ObjectSetInteger(0, FiboName, OBJPROP_SELECTABLE, true);
   //ObjectSetInteger(0, FiboName, OBJPROP_SELECTED, false);

   //--- show price
   ObjectSetInteger(0, FiboName, OBJPROP_LEVELS, 12);

   double levels[12] = {
      0.0,
      0.236,
      0.382,
      0.5,
      0.618,
      0.786,
      1.0,
      1.272,
      1.414,
      1.618,
      2.0,
      2.618
   };
   string texts[12] = {
      "0.0",
      "23.6",
      "38.2",
      "50.0",
      "61.8",
      "78.6",
      "100",
      "127.2",
      "141.4",
      "161.8",
      "200",
      "261.8"
   };

   for (int i = 0; i < 12; i++) {
      ObjectSetDouble(0, FiboName, OBJPROP_LEVELVALUE, i, levels[i]);
      ObjectSetString(0, FiboName, OBJPROP_LEVELTEXT, i, texts[i] + " / %$ ");
      ObjectSetInteger(0, FiboName, OBJPROP_LEVELCOLOR, i, FiboColor);
      ObjectSetInteger(0, FiboName, OBJPROP_BACK, true);
      ObjectSetInteger(0, FiboName, OBJPROP_STYLE, STYLE_DASH);
   }
}

//+------------------------------------------------------------------+
//| OnInit                                                           |
//+------------------------------------------------------------------+
int OnInit() {
   DrawFibo();
   return (INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| OnDeinit                                                         |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
   DeleteFibo();
}

//+------------------------------------------------------------------+
//| OnCalculate                                                      |
//+------------------------------------------------------------------+
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[]) {
   DrawFibo();
   return (rates_total);
}
//+------------------------------------------------------------------+

I hope this indicator helps improve your trading analysis and saves valuable charting time. If you use fibo_a_v1 in your trading or have suggestions for future versions, feel free to share your feedback on the blog.

Happy trading and thank you for reading!

How to Build an Advanced Automatic Fibonacci Indicator in MQL5 for MetaTrader 5

MetaTrader 5 is one of the most powerful trading platforms for technical analysis and algorithmic trading. Many traders use Fibonacci levels to identify support, resistance, retracement zones, and potential reversal areas. However, drawing Fibonacci manually every day can be time-consuming and may lead to inconsistency between trading sessions.

High Open Low Open



To solve this problem, I created an MQL5 indicator called **Auto Fibo Close High/Low**. This indicator automatically draws Fibonacci levels based on the current day’s H1 range, displays yesterday’s range, calculates the average daily range (ADR), shows useful trading statistics on the chart, and generates alerts when price approaches important levels.

The indicator starts with the following declaration:

#property indicator_chart_window
#property indicator_plots 0

Because it works with chart objects such as Fibonacci tools and trend lines, it does not use standard indicator buffers or plots.

==================================================
MAIN IDEA OF THE INDICATOR
==================================================

The core concept is very simple but extremely useful for intraday trading:

1. Detect the first H1 candle of the current trading day.
2. Find the highest and lowest prices from that candle until the current time.
3. Draw a Fibonacci object from the low to the high.
4. Add the daily open as a custom Fibonacci level.
5. Optionally draw yesterday’s range.
6. Alert the trader when price gets close to the highest or lowest level.
7. Display ADR, spread, bar countdown, floating PnL, and time information directly on the chart.

This creates a complete trading framework without requiring manual chart preparation.

==================================================
INPUT SETTINGS
==================================================

The indicator includes several customizable inputs:

input int      signalGAP      = 10;
input bool     ShowAlert     = true;
input bool     ShowToday     = true;
input bool     ShowYesterday = true;
input color    ColorOpen     = clrPurple;
input color    ColorHighest  = clrMaroon;
input color    ColorLowest   = clrDarkGreen;
input bool     LatestH4Open  = false;

These settings allow the trader to adapt the indicator to different strategies.

- signalGAP defines how many points away price can be before an alert is triggered.
- ShowAlert enables or disables alerts.
- ShowToday draws today’s Fibonacci range.
- ShowYesterday draws yesterday’s Fibonacci range.
- ColorOpen changes the open level color.
- ColorHighest changes the highest level color.
- ColorLowest changes the lowest level color.
- LatestH4Open draws a horizontal line at the latest H4 opening price.

==================================================
REMOVING OLD OBJECTS
==================================================

A good MQL5 indicator should clean up its objects when removed from the chart.

if (StringFind(name, fiboName) >= 0)
   ObjectDelete(0, name);

This ensures that all Fibonacci objects created by the indicator are deleted automatically. It prevents the chart from becoming cluttered with old objects.

==================================================
DATA SYNCHRONIZATION
==================================================

Inside OnCalculate, the indicator first checks whether H1 data is ready.

if (!SeriesInfoInteger(_Symbol, PERIOD_H1, SERIES_SYNCHRONIZED))
   return rates_total;

if (Bars(_Symbol, PERIOD_H1) < 10)
   return rates_total;

These checks are very important, especially when MetaTrader has just started or historical data is still downloading. Without them, the indicator could produce invalid values or runtime errors.

==================================================
CREATING TODAY’S FIBONACCI RANGE
==================================================

When ShowToday is enabled, the function CreateTodayH1Line is executed.

CreateTodayH1Line(fiboName);

The indicator calculates the start of the current trading day:

datetime today = StringToTime(TimeToString(TimeCurrent(), TIME_DATE));

Then it finds the first H1 candle of the day:

int firstShift = iBarShift(_Symbol, PERIOD_H1, today, false);

After that, it scans all H1 candles from the beginning of the day until the current candle to determine the highest and lowest prices.

for (int i = firstShift; i >= 0; i--)
{
   double h = iHigh(_Symbol, PERIOD_H1, i);
   double l = iLow(_Symbol, PERIOD_H1, i);

   if (h > highest) highest = h;
   if (l < lowest)  lowest  = l;
}

This produces a dynamic intraday range that updates automatically as the market moves.

==================================================
DRAWING THE FIBONACCI OBJECT
==================================================

The Fibonacci object is created using the lowest and highest prices.

ObjectCreate(0, name, OBJ_FIBO, 0, time1, lowest, time2, highest);

The object is then styled:

ObjectSetInteger(0, name, OBJPROP_RAY_RIGHT, true);
ObjectSetInteger(0, name, OBJPROP_LEVELCOLOR, 0, ColorHighest);
ObjectSetInteger(0, name, OBJPROP_LEVELCOLOR, 1, ColorLowest);
ObjectSetInteger(0, name, OBJPROP_LEVELCOLOR, 2, ColorOpen);

The Fibonacci extends to the right, allowing the levels to remain visible as new candles appear.

==================================================
ADDING THE DAILY OPEN LEVEL
==================================================

One feature that makes this indicator different from a standard Fibonacci tool is the custom open level.

double openLevel = ((highest - open) / rangeHighestLowest);

This value is added as an additional Fibonacci level:

ObjectSetDouble(0, name, OBJPROP_LEVELVALUE, 2, openLevel);

The final structure becomes:

- 0% = Highest price
- 100% = Lowest price
- Custom level = Daily open

Many intraday traders use the daily open as a directional reference. Combining it with the day’s range creates a very practical trading framework.

==================================================
YESTERDAY’S RANGE
==================================================

The indicator can also draw yesterday’s range using daily data.

double highest = iHigh(_Symbol, PERIOD_D1, dayShift);
double lowest  = iLow(_Symbol, PERIOD_D1, dayShift);
double open    = iOpen(_Symbol, PERIOD_D1, dayShift);

Because the daily candle already contains the complete range, there is no need to scan H1 candles. This provides a clean reference for previous-day support and resistance.

==================================================
PRICE ALERTS
==================================================

The indicator can alert when price approaches the highest or lowest level.

double highestGAP = MathAbs(currentPrice - highest) / _Point;

if (highestGAP <= signalGAP)
   Alert(_Symbol + " highest " + DoubleToString(highestGAP, 0));

A similar block is used for the lowest level.

This is useful for traders waiting for price to retest the extremes of the daily range.

==================================================
M5 CONFIRMATION TREND LINES
==================================================

When an alert is triggered, the indicator examines the last five M5 candles.

For bullish conditions:

if (iOpen(_Symbol, PERIOD_M5, m) < iClose(_Symbol, PERIOD_M5, m))

For bearish conditions:

if (iOpen(_Symbol, PERIOD_M5, m) > iClose(_Symbol, PERIOD_M5, m))

The highest bullish open or lowest bearish open is used to draw an additional horizontal trend line.

ObjectCreate(0, UpTrendLine, OBJ_TREND, 0, time1, lastm5highest, time2, lastm5highest);

This creates a secondary intraday reference level that can help with entries, stop-loss placement, and trade management.

==================================================
AVERAGE DAILY RANGE (ADR)
==================================================

The indicator calculates the average daily range of the last completed days.

for (int i = 1; i <= days; i++)
{
   double high = iHigh(_Symbol, PERIOD_D1, i);
   double low  = iLow(_Symbol, PERIOD_D1, i);

   total += (high - low);
}

The current day’s range is compared with the ADR.

double todayRangePercent = (todayRange / averageRange) * 100.0;

This tells the trader whether the market has already moved more or less than its recent average. For example, if today’s range has reached 120% of ADR, the market may be overextended.

==================================================
CHART INFORMATION PANEL
==================================================

One of the most practical features is the information panel displayed on the chart.

theComment = theComment + "Price = " + DoubleToString(SymbolInfoDouble(_Symbol, SYMBOL_ASK), Digits());
theComment = theComment + "\nSpread = " + IntegerToString(SymbolInfoInteger(_Symbol, SYMBOL_SPREAD));

The panel also shows:

- Time remaining until the current bar closes
- Total floating PnL in points
- GMT time
- Server time
- Local time
- ADR
- Today’s range and its percentage of ADR

This transforms the indicator into a compact trading dashboard.

==================================================
FLOATING PNL CALCULATION
==================================================

The function GetTotalPnLPips loops through all open positions for the current symbol.

double pnl_points = (current_price - open_price) / tick_size;

It automatically handles both buy and sell positions and returns the total floating result in points.

This is especially useful for active traders managing multiple positions on the same symbol.

==================================================
OPTIONAL H4 OPEN LINE
==================================================

If enabled, the indicator draws a horizontal line at the latest H4 opening price.

double open1 = iOpen(_Symbol, PERIOD_H4, barShift);

Many intraday traders use the H4 open as a directional bias level. Price trading above the H4 open may suggest bullish intraday conditions, while trading below it may suggest bearish conditions.

==================================================
WHY THIS INDICATOR IS USEFUL
==================================================

This indicator combines several tools that traders usually apply manually:

- Daily range analysis
- Fibonacci levels
- Daily open reference
- Previous-day levels
- ADR measurement
- Price proximity alerts
- M5 confirmation levels
- H4 bias line
- Real-time trading statistics

By automating these tasks, the trader can focus more on decision-making and less on chart preparation.

==================================================
PERFORMANCE NOTES
==================================================

Because the indicator creates and deletes chart objects frequently, it is best used on charts with sufficient historical data. Avoid attaching multiple copies of the same indicator to the same chart unless you use different object names.

The synchronization checks and range validation included in the code help prevent common startup errors.

==================================================
FULL SOURCE CODE
==================================================


//+------------------------------------------------------------------+
//|             Auto Fibo Close High/Low.mq5                         |
//|         Fibo from Highest Close (0%) to Lowest Close (100%)      |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_plots 0 // No plots, only objects

//+------------------------------------------------------------------+
//| Custom Settings                                                  |
//+------------------------------------------------------------------+
input int      signalGAP            = 10; // GAP Point for Alert
input bool     ShowAlert            = true; // Turn on Alert
input bool     ShowToday            = true; // Today Line
input bool     ShowYesterday        = true; // Yesterday Line
input color    ColorOpen            = clrPurple;
input color    ColorHighest         = clrMaroon;
input color    ColorLowest          = clrDarkGreen;
input bool     LatestH4Open         = false;

string fiboName = "holo";

int OnInit() {
   return (INIT_SUCCEEDED);
}

void OnDeinit(const int reason) {
   int total = ObjectsTotal(0, 0, -1);

   for (int i = total - 1; i >= 0; i--) {
      string name = ObjectName(0, i, 0, -1);

      // delete only Fibonacci objects with "holo" in the name
      if (StringFind(name, fiboName) >= 0) {
         ObjectDelete(0, name);
      }
   }
   Comment("");
}

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[]) {

   //--- Wait until synchronize
   if (!SeriesInfoInteger(_Symbol, PERIOD_H1, SERIES_SYNCHRONIZED))
      return rates_total;

   //--- Wait until data enough
   if (Bars(_Symbol, PERIOD_H1) < 10)
      return rates_total;

   if (ShowToday) {
      CreateTodayH1Line(fiboName);
   }

   if (ShowYesterday) {
      CreateYesterdayH1Line(fiboName);
   }

   double todayRange = iHigh(_Symbol, PERIOD_D1, 0) - iLow(_Symbol, PERIOD_D1, 0);

   if (MathAbs(todayRange) <= _Point) {
      Print("Range not ready yet, skip fibo calculation");
      return rates_total;
   }

   double averageRange = GetAverageDailyRange(9);
   double averageRangePoint = GetAverageDailyRangePoints(9);
   double todayRangePercent = (todayRange / averageRange) * 100.00;

   string theComment = "\n";
   theComment = theComment + "Price = " + DoubleToString(SymbolInfoDouble(_Symbol, SYMBOL_ASK), Digits());
   theComment = theComment + "\nSpread = " + IntegerToString(SymbolInfoInteger(_Symbol, SYMBOL_SPREAD));
   theComment = theComment + "\nBar End = " + TimeToString((iTime(_Symbol, _Period, 0) + PeriodSeconds(_Period)) - TimeCurrent(), TIME_SECONDS);
   theComment = theComment + "\nPnL = " + DoubleToString(GetTotalPnLPips(), 0) + " point";
   theComment = theComment + "\n";
   theComment = theComment + "\nGMT Date Time = " + TimeToString(TimeGMT(), TIME_DATE | TIME_SECONDS);
   theComment = theComment + "\nServer Date Time = " + TimeToString(TimeCurrent(), TIME_DATE | TIME_SECONDS);
   theComment = theComment + "\nLocal Date Time = " + TimeToString(TimeLocal(), TIME_DATE | TIME_SECONDS);
   theComment = theComment + "\n";
   theComment = theComment + "\nADR (9 days) = " + DoubleToString(averageRange, 0) + " pips / " + DoubleToString(averageRangePoint, 0) + " point";
   theComment = theComment + "\nToday Range = " + DoubleToString(todayRange, 0) + " pips / " + DoubleToString(todayRange / _Point, 0) + " point / " + DoubleToString(todayRangePercent, 2) + "%";

   Comment(theComment);
   
   if(LatestH4Open) {
      CreateH4OpenHorizontal(fiboName, 1);
   }

   return (rates_total);

}

//+------------------------------------------------------------------+
//| Create Fibonacci H1 Today                                        |
//+------------------------------------------------------------------+
void CreateTodayH1Line(string name = "HOLO") {

   //--- fibo name
   int dayShift = 0;
   name = name + "H1" + IntegerToString(dayShift);

   //--- start of today
   datetime today = StringToTime(TimeToString(TimeCurrent(), TIME_DATE));

   //--- shift of first H1 candle today (00:00)
   int firstShift = iBarShift(_Symbol, PERIOD_H1, today, false);

   if (iTime(_Symbol, PERIOD_H1, firstShift) < today) {
      firstShift--;
   }

   if (firstShift < 0) {
      Print("Cannot find today's H1 candle");
      return;
   }

   //--- open of first H1 candle today
   double open = iOpen(_Symbol, PERIOD_H1, firstShift);

   //--- find highest and lowest H1 of today
   double highest = -DBL_MAX;
   double lowest = DBL_MAX;

   // scan from first H1 candle today down to current H1 candle
   for (int i = firstShift; i >= 0; i--) {
      datetime t = iTime(_Symbol, PERIOD_H1, i);

      if (t < today)
         break;

      double h = iHigh(_Symbol, PERIOD_H1, i);
      double l = iLow(_Symbol, PERIOD_H1, i);

      if (h > highest) highest = h;
      if (l < lowest) lowest = l;
   }

   //--- remove old fibo if exists
   ObjectDelete(0, name);

   //--- create Fibonacci object
   datetime time1 = iTime(_Symbol, PERIOD_H1, firstShift); // 00:00 H1
   datetime time2 = TimeCurrent();

   if (!ObjectCreate(0, name, OBJ_FIBO, 0, time1, lowest, time2, highest)) {
      Print("Failed to create Fibonacci");
      return;
   }

   //--- style
   ObjectSetInteger(0, name, OBJPROP_COLOR, clrNONE);
   ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
   ObjectSetInteger(0, name, OBJPROP_RAY_RIGHT, true);
   ObjectSetInteger(0, name, OBJPROP_LEVELCOLOR, 0, ColorHighest);
   ObjectSetInteger(0, name, OBJPROP_LEVELCOLOR, 1, ColorLowest);
   ObjectSetInteger(0, name, OBJPROP_LEVELCOLOR, 2, ColorOpen);
   ObjectSetInteger(0, name, OBJPROP_BACK, true);
   ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID);

   //--- levels: Open, High, Low
   ObjectSetInteger(0, name, OBJPROP_LEVELS, 3);

   // Level 0 = Highest
   ObjectSetDouble(0, name, OBJPROP_LEVELVALUE, 0, 0.0);
   ObjectSetString(0, name, OBJPROP_LEVELTEXT, 0, IntegerToString(dayShift) + " H1 highest" + " = %$  ");

   // Level 1 = Lowest
   ObjectSetDouble(0, name, OBJPROP_LEVELVALUE, 1, 1.0);
   ObjectSetString(0, name, OBJPROP_LEVELTEXT, 1, IntegerToString(dayShift) + " H1 lowest" + " = %$  ");

   // Level 2 = Open
   double rangeHighestLowest = highest - lowest;
   if (MathAbs(rangeHighestLowest) <= _Point) {
      Print("Range not ready yet, skip fibo calculation");
      return;
   }
   double openLevel = ((highest - open) / rangeHighestLowest) * 1.0;

   ObjectSetDouble(0, name, OBJPROP_LEVELVALUE, 2, openLevel);
   ObjectSetString(0, name, OBJPROP_LEVELTEXT, 2, IntegerToString(dayShift) + " H1 open" + " = %$  ");

   Print(_Symbol,
      " Today Open=", open,
      " Highest=", highest,
      " Lowest=", lowest);

   if (ShowAlert) {

      double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);

      /*double openGAP = MathAbs(currentPrice - open) / _Point;
      if(openGAP <= signalGAP) {
         Alert(_Symbol + " open " + DoubleToString(openGAP, 0));
      } */

      double highestGAP = MathAbs(currentPrice - highest) / _Point;
      if (highestGAP <= signalGAP) {
         Alert(_Symbol + " highest " + DoubleToString(highestGAP, 0));

         //--- Add Second Line
         double lastm5highest = -DBL_MAX;
         for (int m = 1; m <= 5; m++) {
            if (iOpen(_Symbol, PERIOD_M5, m) < iClose(_Symbol, PERIOD_M5, m)) {
               double m5o = iOpen(_Symbol, PERIOD_M5, m);
               if (m5o > lastm5highest) lastm5highest = m5o;
            }
         }

         string UpTrendLine = name + "UpTrendLine";
         if (ObjectCreate(0, UpTrendLine, OBJ_TREND, 0, time1, lastm5highest, time2, lastm5highest)) {
            ObjectSetInteger(0, UpTrendLine, OBJPROP_COLOR, clrOrange);
            ObjectSetInteger(0, UpTrendLine, OBJPROP_WIDTH, 1);
            ObjectSetInteger(0, UpTrendLine, OBJPROP_STYLE, STYLE_DASHDOT);
            ObjectSetInteger(0, UpTrendLine, OBJPROP_RAY_LEFT, false);
            ObjectSetInteger(0, UpTrendLine, OBJPROP_RAY_RIGHT, true);

         }

      }

      double lowestGAP = MathAbs(currentPrice - lowest) / _Point;
      if (lowestGAP <= signalGAP) {
         Alert(_Symbol + " lowest " + DoubleToString(lowestGAP, 0));

         //--- Add Second Line
         double lastm5lowest = DBL_MAX;
         for (int m = 1; m <= 5; m++) {
            if (iOpen(_Symbol, PERIOD_M5, m) > iClose(_Symbol, PERIOD_M5, m)) {
               double m5o = iOpen(_Symbol, PERIOD_M5, m);
               if (m5o < lastm5lowest) lastm5lowest = m5o;
            }
         }

         string DownTrendLine = name + "DownTrendLine";
         if (ObjectCreate(0, DownTrendLine, OBJ_TREND, 0, time1, lastm5lowest, time2, lastm5lowest)) {
            ObjectSetInteger(0, DownTrendLine, OBJPROP_COLOR, clrOrange);
            ObjectSetInteger(0, DownTrendLine, OBJPROP_WIDTH, 1);
            ObjectSetInteger(0, DownTrendLine, OBJPROP_STYLE, STYLE_DASHDOT);
            ObjectSetInteger(0, DownTrendLine, OBJPROP_RAY_LEFT, false);
            ObjectSetInteger(0, DownTrendLine, OBJPROP_RAY_RIGHT, true);

         }

      }

   }

}

//+------------------------------------------------------------------+
//| Create Fibonacci H1 Yesterday                                    |
//+------------------------------------------------------------------+
void CreateYesterdayH1Line(string name = "HOLO") {
   //--- fibo name
   int dayShift = 1;
   name = name + "H1" + IntegerToString(dayShift);

   //--- Get OHLC   
   double highest = iHigh(_Symbol, PERIOD_D1, dayShift);
   double lowest = iLow(_Symbol, PERIOD_D1, dayShift);
   double open = iOpen(_Symbol, PERIOD_D1, dayShift);
   double close = iClose(_Symbol, PERIOD_D1, dayShift);

   //--- remove old fibo if exists
   ObjectDelete(0, name);

   //--- create Fibonacci object
   datetime timeStart = iTime(_Symbol, PERIOD_D1, dayShift);
   datetime timeEnd = iTime(_Symbol, PERIOD_D1, dayShift - 1);

   if (!ObjectCreate(0, name, OBJ_FIBO, 0, timeStart, lowest, timeEnd, highest)) {
      Print("Failed to create Fibonacci");
      return;
   }

   //--- style
   ObjectSetInteger(0, name, OBJPROP_COLOR, clrNONE);
   ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
   ObjectSetInteger(0, name, OBJPROP_RAY_RIGHT, true);
   ObjectSetInteger(0, name, OBJPROP_RAY_LEFT, false);
   ObjectSetInteger(0, name, OBJPROP_LEVELCOLOR, 0, ColorHighest);
   ObjectSetInteger(0, name, OBJPROP_LEVELCOLOR, 1, ColorLowest);
   ObjectSetInteger(0, name, OBJPROP_LEVELCOLOR, 2, ColorOpen);
   ObjectSetInteger(0, name, OBJPROP_BACK, true);
   ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID);

   //--- levels: Open, High, Low
   ObjectSetInteger(0, name, OBJPROP_LEVELS, 3);

   // Level 0 = Highest
   ObjectSetDouble(0, name, OBJPROP_LEVELVALUE, 0, 0.0);
   ObjectSetString(0, name, OBJPROP_LEVELTEXT, 0, IntegerToString(dayShift) + " H1 highest" + " = %$  ");

   // Level 1 = Lowest
   ObjectSetDouble(0, name, OBJPROP_LEVELVALUE, 1, 1.0);
   ObjectSetString(0, name, OBJPROP_LEVELTEXT, 1, IntegerToString(dayShift) + " H1 lowest" + " = %$  ");

   // Level 2 = Open
   double rangeHighestLowest = highest - lowest;
   if (MathAbs(rangeHighestLowest) <= _Point) {
      Print("Range not ready yet, skip fibo calculation");
      return;
   }
   double openLevel = ((highest - open) / rangeHighestLowest) * 1.0;

   ObjectSetDouble(0, name, OBJPROP_LEVELVALUE, 2, openLevel);
   ObjectSetString(0, name, OBJPROP_LEVELTEXT, 2, IntegerToString(dayShift) + " H1 open" + " = %$  ");

}

//+------------------------------------------------------------------+
//| Calculate total Profit/Loss of all open positions in pips        |
//+------------------------------------------------------------------+
double GetTotalPnLPips() {
   double total_pips = 0;

   for (int i = PositionsTotal() - 1; i >= 0; i--) {
      ulong ticket = PositionGetTicket(i);
      if (PositionGetString(POSITION_SYMBOL) == _Symbol) {
         double open_price = PositionGetDouble(POSITION_PRICE_OPEN);
         double current_price = (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) ?
            SymbolInfoDouble(_Symbol, SYMBOL_BID) :
            SymbolInfoDouble(_Symbol, SYMBOL_ASK);

         double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
         double tick_size = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);

         // Calculate PnL in points
         double pnl_points = (current_price - open_price) / tick_size;

         // Convert points to pips
         double pnl_pips = pnl_points * (tick_size / point);

         // Add to total (for Buy, profit is positive; for Sell, profit is reversed)
         if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
            total_pips -= pnl_pips;
         else
            total_pips += pnl_pips;
      }
   }

   return total_pips;
}

//+------------------------------------------------------------------+
//| Average Daily Range (ADR) for last N completed days              |
//+------------------------------------------------------------------+
double GetAverageDailyRange(int days = 10) {
   double total = 0.0;
   int count = 0;

   // Start from yesterday (shift 1), skip current unfinished day
   for (int i = 1; i <= days; i++) {
      double high = iHigh(_Symbol, PERIOD_D1, i);
      double low = iLow(_Symbol, PERIOD_D1, i);

      if (high > 0 && low > 0) {
         total += (high - low);
         count++;
      }
   }

   if (count == 0)
      return 0.0;

   return total / count;
}

//+------------------------------------------------------------------+
//| Average Daily Range in points                                    |
//+------------------------------------------------------------------+
double GetAverageDailyRangePoints(int days = 10) {
   return GetAverageDailyRange(days) / _Point;
}

//+------------------------------------------------------------------+
//| Create horizontal trend line at H4                               |
//+------------------------------------------------------------------+
void CreateH4OpenHorizontal(string name = "H4Open", int barShift = 1) {
   
   name = name + "H4Open";
   
   datetime time1 = iTime(_Symbol, PERIOD_H4, barShift);
   datetime time2 = TimeCurrent();

   double open1 = iOpen(_Symbol, PERIOD_H4, barShift);

   if(ObjectFind(0, name) >= 0)
      ObjectDelete(0, name);

   ObjectCreate(0, name, OBJ_TREND, 0, time1, open1, time2, open1);

   ObjectSetInteger(0, name, OBJPROP_COLOR, clrOrange);
   ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
   ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DASHDOT);
   ObjectSetInteger(0, name, OBJPROP_RAY_RIGHT, true);
   
}
 
==================================================
CONCLUSION
==================================================

The Auto Fibo Close High/Low indicator is a powerful example of advanced object-based programming in MQL5. It goes far beyond a standard Fibonacci tool by automatically adapting to the current market structure, adding meaningful custom levels, generating alerts, calculating ADR, and displaying real-time trading information.

For forex, gold, and index traders using the H1 timeframe, this indicator can significantly speed up chart analysis and provide a consistent framework for identifying high-probability trading zones.

The complete source code includes important functions such as:

- CreateTodayH1Line
- CreateYesterdayH1Line
- GetAverageDailyRange
- GetTotalPnLPips
- CreateH4OpenHorizontal

Studying this project is an excellent way to learn MQL5 techniques including object handling, multi-timeframe analysis, dynamic Fibonacci levels, alert generation, and chart-based dashboards.