Bar_counter

Author: Copyright 2019-2025, Virologista Kerntopf Corp.
Price Data Components
0 Views
0 Downloads
0 Favorites
Bar_counter
ÿþ//+------------------------------------------------------------------+

//|                                                 Bar_Counter.mq5  |

//|                   Copyright 2019-2025, Virologista Kerntopf Corp.|

//|                  https://www.mql5.com/pt/users/virologustavo/news|

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

#property copyright "Copyright 2019-2025, Virologista Kerntopf Corp."

#property link      "https://www.mql5.com/pt/users/virologustavo/news"

#property version   "1.00"

#property indicator_chart_window

#property indicator_buffers 1

#property indicator_plots   1



//--- Input parameters

input color TextColor = clrWhite;       // Text color

input string Font = "Arial";            // Font type

input int FontSize = 8;                 // Font size

input ENUM_ANCHOR_POINT Anchor = ANCHOR_CENTER; // Anchor type

input bool Distance = false;            // Distance text from candles?

input double Offset = 50.0;             // Offset value in points

input bool NumberFirstCandle = true;    // If true, the first candle of the day is numbered as 1. Otherwise, the last candle.



//--- Buffers

double CounterBuffer[];



//--- Global variables

string ObjectPrefix = "CounterCandle_";



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

//| Indicator initialization function                                |

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

int OnInit()

  {

   // Set data buffer

   if(SetIndexBuffer(0, CounterBuffer, INDICATOR_DATA) == false)

     {

      Print("Error setting data buffer. Code: ", GetLastError());

      return INIT_FAILED;

     }



   // Initialize buffer with EMPTY_VALUE

   if(ArrayInitialize(CounterBuffer, EMPTY_VALUE) == -1)

     {

      Print("Error initializing buffer. Code: ", GetLastError());

      return INIT_FAILED;

     }



   return INIT_SUCCEEDED;

  }



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

//| Function called when the indicator is removed                    |

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

void OnDeinit(const int reason)

  {

   // Delete all objects created by the indicator

   DeleteObjects();

  }



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

//| Function to get the day from a datetime                          |

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

int GetDay(datetime time)

  {

   MqlDateTime dt;

   if(!TimeToStruct(time, dt))

     {

      Print("Error converting datetime to MqlDateTime. Code: ", GetLastError());

      return -1; // Return -1 on failure

     }

   return dt.day; // Return the day

  }



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

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

  {

   // Set arrays as time series

   if(!ArraySetAsSeries(time, true) || !ArraySetAsSeries(open, true) ||

      !ArraySetAsSeries(high, true) || !ArraySetAsSeries(low, true) ||

      !ArraySetAsSeries(close, true))

     {

      Print("Error setting arrays as time series. Code: ", GetLastError());

      return 0;

     }



   // Clear old objects

   DeleteObjects();



   // Get current day (based on server time)

   datetime now = TimeCurrent();

   int currentDay = GetDay(now);



   // Loop to process candles

   for(int i = (prev_calculated == 0 ? 0 : prev_calculated - 1); i < rates_total && !IsStopped(); i++)

     {

      // Check if the candle belongs to the current day

      int candleDay = GetDay(time[i]);

      if(candleDay == -1)

        {

         Print("Error getting day for candle ", i, ". Skipping...");

         continue;

        }

      if(candleDay != currentDay)

        {

         CounterBuffer[i] = EMPTY_VALUE; // Ignore candles from previous days

         continue;

        }



      // Check if it's the first candle of the day

      int previousDay = (i > 0) ? GetDay(time[i - 1]) : -1;



      if(candleDay != previousDay)

        {

         // Reset count for the new day

         if(NumberFirstCandle)

           {

            CounterBuffer[i] = 1; // First candle of the day is numbered as 1

           }

         else

           {

            CounterBuffer[i] = EMPTY_VALUE; // Mark as empty until the last candle is found

           }

        }

      else

        {

         // Increment the count

         if(NumberFirstCandle)

           {

            CounterBuffer[i] = (i > 0) ? CounterBuffer[i - 1] + 1 : 1;

           }

         else

           {

            CounterBuffer[i] = EMPTY_VALUE; // We don't know the last candle yet

           }

        }



      // Create text on the chart

      string objectName = ObjectPrefix + TimeToString(time[i]);

      string text = "";

      if(CounterBuffer[i] != EMPTY_VALUE)

        {

         text = IntegerToString((int)CounterBuffer[i]);

        }

      double price = (open[i] > close[i]) ? low[i] - Offset * Point() : high[i] + Offset * Point();

      if(text != "")

        {

         if(!CreateText(0, objectName, 0, time[i], price, text, 0.0, Font, FontSize, TextColor, Anchor))

           {

            Print("Error creating text for candle ", i, ". Code: ", GetLastError());

           }

        }

     }



   // If numbering the last candle of the day, adjust the count retroactively

   if(!NumberFirstCandle)

     {

      for(int i = rates_total - 1; i >= 0 && !IsStopped(); i--)

        {

         int candleDay = GetDay(time[i]);

         if(candleDay == -1)

           {

            Print("Error getting day for candle ", i, ". Skipping...");

            continue;

           }

         if(candleDay != currentDay)

           {

            CounterBuffer[i] = EMPTY_VALUE; // Ignore candles from previous days

            continue;

           }

         int nextDay = (i < rates_total - 1) ? GetDay(time[i + 1]) : -1;



         if(candleDay != nextDay)

           {

            // This is the last candle of the day

            CounterBuffer[i] = 1;

            // Retroactively number previous candles

            int count = 1;

            for(int j = i - 1; j >= 0 && GetDay(time[j]) == candleDay; j--)

              {

               CounterBuffer[j] = ++count;

              }

           }

        }



      // Update texts on the chart

      for(int i = 0; i < rates_total && !IsStopped(); i++)

        {

         if(CounterBuffer[i] != EMPTY_VALUE)

           {

            string objectName = ObjectPrefix + TimeToString(time[i]);

            string text = IntegerToString((int)CounterBuffer[i]);

            double price = (open[i] > close[i]) ? low[i] - Offset * Point() : high[i] + Offset * Point();

            if(!CreateText(0, objectName, 0, time[i], price, text, 0.0, Font, FontSize, TextColor, Anchor))

              {

               Print("Error updating text for candle ", i, ". Code: ", GetLastError());

              }

           }

        }

     }

   return rates_total;

  }



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

//| Function to create text on the chart                             |

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

bool CreateText(const long chartID,

                const string name,

                const int subWindow,

                datetime time,

                double price,

                const string text,

                const double angle,

                const string font,

                const int size,

                const color clr,

                const ENUM_ANCHOR_POINT anchor)

  {

   ResetLastError();

   if(!ObjectCreate(chartID, name, OBJ_TEXT, subWindow, time, price))

     {

      Print(__FUNCTION__, ": Failed to create text object '", name, "'! Error: ", GetLastError());

      return false;

     }



   if(!ObjectSetString(chartID, name, OBJPROP_TEXT, text))

     {

      Print(__FUNCTION__, ": Failed to set text for object '", name, "'! Error: ", GetLastError());

      ObjectDelete(chartID, name);

      return false;

     }



   if(!ObjectSetString(chartID, name, OBJPROP_FONT, font))

     {

      Print(__FUNCTION__, ": Failed to set font for object '", name, "'! Error: ", GetLastError());

      ObjectDelete(chartID, name);

      return false;

     }



   if(!ObjectSetInteger(chartID, name, OBJPROP_FONTSIZE, size))

     {

      Print(__FUNCTION__, ": Failed to set font size for object '", name, "'! Error: ", GetLastError());

      ObjectDelete(chartID, name);

      return false;

     }



   if(!ObjectSetDouble(chartID, name, OBJPROP_ANGLE, angle))

     {

      Print(__FUNCTION__, ": Failed to set angle for object '", name, "'! Error: ", GetLastError());

      ObjectDelete(chartID, name);

      return false;

     }



   if(!ObjectSetInteger(chartID, name, OBJPROP_ANCHOR, anchor))

     {

      Print(__FUNCTION__, ": Failed to set anchor for object '", name, "'! Error: ", GetLastError());

      ObjectDelete(chartID, name);

      return false;

     }



   if(!ObjectSetInteger(chartID, name, OBJPROP_COLOR, clr))

     {

      Print(__FUNCTION__, ": Failed to set color for object '", name, "'! Error: ", GetLastError());

      ObjectDelete(chartID, name);

      return false;

     }



   ObjectSetInteger(chartID, name, OBJPROP_BACK, false);

   ObjectSetInteger(chartID, name, OBJPROP_SELECTABLE, false);

   ObjectSetInteger(chartID, name, OBJPROP_HIDDEN, true);

   return true;

  }



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

//| Function to delete objects                                       |

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

void DeleteObjects()

  {

   // Count how many objects exist with the specified prefix

   int totalObjects = ObjectsTotal(0, -1, OBJ_TEXT);

   bool hasObjects = false;



   for(int i = 0; i < totalObjects; i++)

     {

      string name = ObjectName(0, i, -1, OBJ_TEXT);

      if(StringFind(name, ObjectPrefix) == 0) // Check if the name starts with the prefix

        {

          hasObjects = true;

          break;

        }

     }



   // If there are objects with the prefix, delete them all

   if(hasObjects)

     {

      ResetLastError(); // Clear the last error before calling ObjectsDeleteAll

      if(!ObjectsDeleteAll(0, ObjectPrefix))

        {

         Print("Error deleting old objects. Code: ", GetLastError());

        }

     }

   else

     {

      // No objects found, no need to log a message

      return;

     }

  }

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

Comments