Doom TMA Band + Arrow (Non-Repaint) MetaTrader 4 Indicator

The Doom TMA Band + Arrow (Non-Repaint) is a custom indicator designed to plot Triangular Moving Averages (TMA) on a chart along with upper and lower bands based on these averages. It includes visual markers in the form of arrows that appear when specific conditions involving price movements relative to these bands are met. The indicator is structured to be non-repainting, meaning once an arrow or line is drawn, it remains fixed, reflecting the historical data without recalculating based on new information.

#property indicator_chart_window
#property indicator_buffers 5
#property indicator_color1  White
#property indicator_color2  OrangeRed
#property indicator_color3  OrangeRed
#property indicator_color4  White
#property indicator_color5  White
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
#property indicator_width2  6
#property indicator_width3  6
#property indicator_width4  8
#property indicator_width5  8

//+------------------------------------------------------------------+
//|                   Input Parameters                               |
//+------------------------------------------------------------------+
extern string TimeFrame       = "current time frame";   // Time frame setting
extern int    HalfLength      = 55;                     // Half length of TMA calculation
extern int    Price           = PRICE_WEIGHTED;         // Price type to be used in calculations
extern double BandsDeviations = 2.5;                    // Standard deviation multiplier for bands
extern bool   Interpolate     = true;                   // Interpolation switch
extern bool   alertsOn        = false;                  // Alerts on/off switch
extern bool   alertsOnCurrent = false;                  // Alerts on the current bar switch
extern bool   alertsOnHighLow = false;                  // Alerts on high/low switch
extern bool   alertsMessage   = false;                  // Message alert switch
extern bool   alertsSound     = false;                  // Sound alert switch
extern bool   alertsEmail     = false;                  // Email alert switch

//+------------------------------------------------------------------+
//|                   Indicator Buffers                              |
//+------------------------------------------------------------------+
double tmBuffer[];     // TMA Buffer
double upBuffer[];     // Upper Band Buffer
double dnBuffer[];     // Lower Band Buffer
double wuBuffer[];     // Weighted Upper Band Buffer
double wdBuffer[];     // Weighted Lower Band Buffer
double upArrow[];      // Up Arrow Buffer
double dnArrow[];      // Down Arrow Buffer

//+------------------------------------------------------------------+
//|                   Global Variables                               |
//+------------------------------------------------------------------+
string IndicatorFileName;
bool   calculatingTma = false;
bool   returningBars  = false;
int    timeFrame;

//+------------------------------------------------------------------+
//|                   Initialize Indicator                           |
//+------------------------------------------------------------------+
int init() {
   // Convert time frame string to integer format
   timeFrame  = stringToTimeFrame(TimeFrame);
   HalfLength = MathMax(HalfLength, 1);  // Ensure HalfLength is at least 1

   // Set up indicator buffers and drawing styles
   IndicatorBuffers(7);
   SetIndexBuffer(0, tmBuffer);  SetIndexDrawBegin(0, HalfLength);
   SetIndexBuffer(1, upBuffer);  SetIndexDrawBegin(1, HalfLength);
   SetIndexBuffer(2, dnBuffer);  SetIndexDrawBegin(2, HalfLength);
   SetIndexBuffer(3, dnArrow);   SetIndexStyle(3, DRAW_ARROW); SetIndexArrow(3, 82);
   SetIndexBuffer(4, upArrow);   SetIndexStyle(4, DRAW_ARROW); SetIndexArrow(4, 82);
   SetIndexBuffer(5, wuBuffer);
   SetIndexBuffer(6, wdBuffer);

   // Check for special modes
   if (TimeFrame == "calculateTma") {
      calculatingTma = true;
      return(0);
   }
   if (TimeFrame == "returnBars") {
      returningBars = true;
      return(0);
   }

   // Get the name of the indicator file
   IndicatorFileName = WindowExpertName();
   return(0);
}

//+------------------------------------------------------------------+
//|                   De-initialize Indicator                        |
//+------------------------------------------------------------------+
int deinit() {
   return(0);
}

//+------------------------------------------------------------------+
//|                   Start Indicator Calculation                    |
//+------------------------------------------------------------------+
int start() {
   int counted_bars = IndicatorCounted();  // Number of bars that have been counted
   int limit;

   // Exit if an error occurred
   if (counted_bars < 0) return(-1);
   if (counted_bars > 0) counted_bars--;

   // Set the limit for bars to calculate
   limit = MathMin(Bars-1, Bars - counted_bars + HalfLength);

   // Return the number of bars if in returningBars mode
   if (returningBars) {
      tmBuffer[0] = limit;
      return(0);
   }

   // Calculate TMA if in calculatingTma mode
   if (calculatingTma) {
      calculateTma(limit);
      return(0);
   }

   // Handle multi-timeframe calculations
   if (timeFrame > Period()) {
      limit = MathMax(limit, MathMin(Bars-1, iCustom(NULL, timeFrame, IndicatorFileName, "returnBars", 0, 0) * timeFrame / Period()));
   }

   // Calculate indicator values for each bar
   for (int i = limit; i >= 0; i--) {
      int shift1 = iBarShift(NULL, timeFrame, Time[i]);
      datetime time1 = iTime(NULL, timeFrame, shift1);

      // Get TMA and bands values from custom indicator
      tmBuffer[i] = iCustom(NULL, timeFrame, IndicatorFileName, "calculateTma", HalfLength, Price, BandsDeviations, 0, shift1);
      upBuffer[i] = iCustom(NULL, timeFrame, IndicatorFileName, "calculateTma", HalfLength, Price, BandsDeviations, 1, shift1);
      dnBuffer[i] = iCustom(NULL, timeFrame, IndicatorFileName, "calculateTma", HalfLength, Price, BandsDeviations, 2, shift1);

      // Initialize arrow buffers
      upArrow[i] = EMPTY_VALUE;
      dnArrow[i] = EMPTY_VALUE;

      // Determine arrow conditions
      if (High[i+1] > upBuffer[i+1] && Close[i+1] > Open[i+1] && Close[i] < Open[i]) upArrow[i] = High[i];
      if (Low[i+1] < dnBuffer[i+1] && Close[i+1] < Open[i+1] && Close[i] > Open[i]) dnArrow[i] = Low[i];

      // Handle interpolation between bars
      if (timeFrame <= Period() || shift1 == iBarShift(NULL, timeFrame, Time[i-1])) continue;
      if (!Interpolate) continue;

      int n = 1;
      while (i+n < Bars && Time[i+n] >= time1) n++;
      double factor = 1.0 / n;
      for (int k = 1; k < n; k++) {
         tmBuffer[i+k] = k * factor * tmBuffer[i+n] + (1.0 - k * factor) * tmBuffer[i];
         upBuffer[i+k] = k * factor * upBuffer[i+n] + (1.0 - k * factor) * upBuffer[i];
         dnBuffer[i+k] = k * factor * dnBuffer[i+n] + (1.0 - k * factor) * dnBuffer[i];
      }
   }

   // Handle alerts
   if (alertsOn) {
      int forBar = alertsOnCurrent ? 0 : 1;

      // Check for alert conditions
      if (alertsOnHighLow) {
         if (High[forBar] > upBuffer[forBar] && High[forBar+1] < upBuffer[forBar+1]) doAlert("high penetrated upper bar");
         if (Low[forBar] < dnBuffer[forBar] && Low[forBar+1] > dnBuffer[forBar+1]) doAlert("low penetrated lower bar");
      } else {
         if (Close[forBar] > upBuffer[forBar] && Close[forBar+1] < upBuffer[forBar+1]) doAlert("close penetrated upper bar");
         if (Close[forBar] < dnBuffer[forBar] && Close[forBar+1] > dnBuffer[forBar+1]) doAlert("close penetrated lower bar");
      }
   }

   return(0);
}

//+------------------------------------------------------------------+
//|                   TMA Calculation Function                       |
//+------------------------------------------------------------------+
void calculateTma(int limit) {
   int i, j, k;
   double FullLength = 2.0 * HalfLength + 1.0;

   // Loop through bars to calculate TMA
   for (i = limit; i >= 0; i--) {
      double sum  = (HalfLength + 1) * iMA(NULL, 0, 1, 0, MODE_SMA, Price, i);
      double sumw = (HalfLength + 1);

      // Calculate weighted moving average
      for (j = 1, k = HalfLength; j <= HalfLength; j++, k--) {
         sum  += k * iMA(NULL, 0, 1, 0, MODE_SMA, Price, i+j);
         sumw += k;

         if (j <= i) {
            sum  += k * iMA(NULL, 0, 1, 0, MODE_SMA, Price, i-j);
            sumw += k;
         }
      }
      tmBuffer[i] = sum / sumw;

      // Calculate upper and lower bands
      double diff = iMA(NULL, 0, 1, 0, MODE_SMA, Price, i) - tmBuffer[i];
      wuBuffer[i] = diff;
      wdBuffer[i] = diff;
      upBuffer[i] = tmBuffer[i] + BandsDeviations * StdDev(wuBuffer, i, FullLength);
      dnBuffer[i] = tmBuffer[i] - BandsDeviations * StdDev(wdBuffer, i, FullLength);
   }
}

//+------------------------------------------------------------------+
//|                   Alert Function                                 |
//+------------------------------------------------------------------+
void doAlert(string msg) {
   if (alertsMessage) Alert(Symbol(), " ", Period(), ": ", msg);
   if (alertsSound)   PlaySound("alert2.wav");
   if (alertsEmail)   SendMail(Symbol() + " " + Period(), msg);
}

//+------------------------------------------------------------------+
//|                   Time Frame Conversion Function                 |
//+------------------------------------------------------------------+
int stringToTimeFrame(string tf) {
   if (tf == "current time frame") return Period();
   if (tf == "M1") return PERIOD_M1;
   if (tf == "M5") return PERIOD_M5;
   if (tf == "M15") return PERIOD_M15;
   if (tf == "M30") return PERIOD_M30;
   if (tf == "H1") return PERIOD_H1;
   if (tf == "H4") return PERIOD_H4;
   if (tf == "D1") return PERIOD_D1;
   if (tf == "W1") return PERIOD_W1;
   if (tf == "MN") return PERIOD_MN1;
   return Period(); // Default to current time frame if unrecognized
}

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

What is the Indicator Designed to Do?

This custom indicator is designed to calculate and display Triangular Moving Averages and their associated upper and lower bands. In addition to this, it plots arrows on the chart whenever specific conditions are met. These conditions relate to price movements concerning the upper and lower bands. The goal of these elements is to provide traders with visual cues about potential price movements, which could be of interest depending on their trading strategy.

See also  Trend Signal v1.0 (NRP+MTF) MetaTrader 4 Indicator

The Core Components of the Indicator

Triangular Moving Average (TMA):

The TMA is a type of moving average that applies a weighted calculation to smooth out the price data. Unlike simple moving averages, where all prices are weighted equally, TMA gives more weight to prices in the middle of the data set. This results in a smoother line, which can help identify trends without the noise of short-term fluctuations.

Upper and Lower Bands:

The upper and lower bands are calculated using the TMA as a baseline. These bands are offset from the TMA by a certain number of standard deviations (as specified by the BandsDeviations parameter). These bands can help identify overbought or oversold conditions depending on where the price is relative to them.

Key Parameters Explained

TimeFrame

This parameter allows you to set the time frame for which the indicator is calculated. You can apply it to the current time frame of the chart or choose a different one. This flexibility is useful when analyzing trends over multiple time periods.

HalfLength

The HalfLength parameter is central to the TMA calculation. It defines how many bars (or periods) are considered when calculating the average. The name “HalfLength” comes from the way TMA is calculated, where the length of the moving average is effectively doubled, making this value half of the total length.

Price

The Price parameter determines which price data is used for the calculations. This could be the closing price, opening price, or other price types like the weighted price. The flexibility to choose different price data allows for tailored analysis based on your trading strategy.

See also  Hilo Gold Pro v1.0 (Non-Repaint) MetaTrader 4 Expert Advisor

BandsDeviations

This parameter is key in determining how far the upper and lower bands are from the TMA. By adjusting the BandsDeviations, you can control the sensitivity of the bands—smaller deviations mean tighter bands, while larger deviations mean wider bands.

Visual Elements: Arrows on the Chart

Up and Down Arrows

One of the key visual features of this indicator is the plotting of arrows on the chart. These arrows are not random; they appear based on specific conditions involving price and the bands:

  • Up Arrow: This appears when the price has moved above the upper band and then reverses direction, closing below the open price on the next bar. It’s a signal that the price might be pulling back after hitting a potential high.
  • Down Arrow: This appears when the price has moved below the lower band and then reverses direction, closing above the open price on the next bar. It’s a signal that the price might be bouncing back after hitting a potential low.

Handling Different Time Frames

The indicator can adapt to different time frames, which is crucial for traders who want to see how the TMA and bands behave over varying periods. The code is designed to handle these changes efficiently, ensuring that the visual elements and calculations remain accurate regardless of the time frame selected.

Alerts: Notifications Based on Specific Conditions

Although alerts are a more minor feature in this context, they still play a role. The indicator can generate alerts when certain conditions are met, such as the price crossing above or below the bands. These alerts can be sent as messages, sounds, or even emails, depending on the user’s preference. This feature is particularly useful for those who don’t want to constantly monitor their charts but still want to be informed of key movements.

See also  Grid MACD System (Non-Repaint) MetaTrader 4 Expert Advisor

Conclusion

This custom indicator is all about visualizing price movements relative to the Triangular Moving Averages and their associated bands. The arrows provide quick visual cues about potential market reversals, which can be useful for decision-making. However, it’s important to remember that indicators are tools and should be used in conjunction with other analysis methods.

Leave a Comment