Author: Written WizardSerg under article konkop in <Modern trading> #4/2001
WATR

The WATR indicator is a technical analysis tool designed to help traders visualize market trends by identifying the underlying direction of price movement and filtering out "noise." It operates by plotting two distinct lines on your chart—one for upward momentum and one for downward momentum—to provide a clearer picture of whether the market is currently trending or experiencing a temporary reversal.

How the Logic Works

The core logic of the script relies on three primary components: trend detection, volatility adjustment, and "anti-trend" filtering.

1. Dynamic Trend Tracking Instead of simply following every price fluctuation, the indicator evaluates whether the current price is consistently moving in a specific direction relative to its previous positions.

  • Upward Momentum: The script identifies an upward trend when the closing price remains consistently above its calculated upper boundary.
  • Downward Momentum: Conversely, it tracks downward movement by observing when prices fall below the lower boundary.

2. Volatility-Based Buffering A key feature of this indicator is that it doesn't just use raw price data; it incorporates volatility. By using a standard measurement known as the Average True Range (ATR), the indicator calculates "buffers." These buffers act as a safety margin, ensuring that small, insignificant price wiggles don't trigger a fake trend change. The width of these margins can be adjusted via user settings to suit different trading styles (e.g., making them wider for volatile markets or tighter for stable ones).

3. Noise Filtering (Anti-Trend Detection) One of the smartest parts of this logic is how it handles "messy" price action. The script includes a specific check for "Anti-Trend Bars." These are instances where the price moves in the opposite direction of the established trend for just a single moment (like a small spike against the main flow).

  • When the script detects these contradictory movements, it chooses to maintain the existing trend line rather than reacting to the anomaly.
  • This prevents the indicator from "flickering" or giving false signals during minor pullbacks.

4. Dynamic Switching and Reversals The indicator is designed to switch roles based on market behavior:

  • Trend Continuation: If the price continues in its current direction, the indicator strengthens that specific line while clearing the opposite one.
  • Trend Reversal: If the price breaks through a boundary with enough strength (crossing from above the upper line to below it, or vice versa), the indicator recognizes a potential shift in market sentiment and flips the active trend line accordingly.

Summary for the Trader

In practical terms, this tool helps you stay on the right side of the market. It attempts to "smooth out" the jagged movements of price charts by creating clear visual boundaries. When both lines are not visible or one is clearly dominant, it tells you the current path of least resistance; when the lines flip or cross, it signals that the market's momentum has shifted, helping you avoid "catching a falling knife" or trading against a powerful trend.

Indicators Used
Indicator of the average true range
Miscellaneous
Implements a curve of type %1
12 Views
0 Downloads
0 Favorites
WATR
//+------------------------------------------------------------------+
//|                                                        WATR.mq4  |
//|                      Written WizardSerg under article konkop in  |
//|                                        "Modern trading" #4/2001  |
//|                                  http://www.wizardserg.inweb.ru  |
//|                                              wizardserg@mail.ru  |
//+------------------------------------------------------------------+
#property copyright "Written WizardSerg under article konkop in <Modern trading> #4/2001"
#property link      "http://www.wizardserg.inweb.ru"
//----
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 Coral
#property indicator_color2 DodgerBlue
//---- input parameters
extern int    WATR_K = 10;
extern double WATR_M = 4.0;
extern int    ATR = 21;
//---- buffers
double ExtMapBufferUp[];
double ExtMapBufferDown[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {  
   IndicatorBuffers(2);  
   SetIndexBuffer(0, ExtMapBufferUp); 
   ArraySetAsSeries(ExtMapBufferUp, true);      
   SetIndexStyle(0, DRAW_LINE, STYLE_SOLID, 2);
   SetIndexBuffer(1, ExtMapBufferDown); 
   ArraySetAsSeries(ExtMapBufferDown, true);      
   SetIndexStyle(1, DRAW_LINE, STYLE_SOLID, 2);
   IndicatorShortName("WATR(" + WATR_K + ", " + WATR_M + ")"); 
   SetIndexLabel(0, "WATR_Up");
   SetIndexLabel(1, "WATR_Dn");    
   return(0); 
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator function                                        |
//+------------------------------------------------------------------+
bool AntiTrendBar(int i)
  {
   bool res = (TrendUp(i) && (Close[i] < Open[i])) ||         
              (!TrendUp(i) && (Close[i] > Open[i]));    
   return(res);
  }
//+------------------------------------------------------------------+
//| Custom indicator function                                        |
//+------------------------------------------------------------------+
double CalcIndicValue(int i, bool trend)
  {
   double res = Close[i];  
   if(trend)
       res -= (WATR_K*Point + WATR_M*iATR(NULL, 0, ATR, i));
   else
       res += (WATR_K*Point + WATR_M*iATR(NULL, 0, ATR, i));        
   return(res);
  }
//+------------------------------------------------------------------+
//| Custom indicator function                                        |
//+------------------------------------------------------------------+
bool TrendUp(int i)
  {
   return((Close[i+1] > ExtMapBufferUp[i+1]) && 
          (ExtMapBufferUp[i+1] != EMPTY_VALUE));
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
   int limit;
   int counted_bars = IndicatorCounted();
//---- ïîñëåäíèé ïîñ÷èòàííûé áàð áóäåò ïåðåñ÷èòàí
//---- ïåðâîå çíà÷åíèå èíäèêàòîðà == öåíå-1 point, 
//     òî åñòü ñ÷èòàåò òðåíä âîñõîäÿùèì
   ExtMapBufferUp[Bars] = Close[Bars] - WATR_K*Point;     
// limit = (counted_bars > 0) ? (Bars - counted_bars) : (Bars - 1);
   limit = Bars - counted_bars;
//---- îñíîâíîé öèêë
   for(int i = limit; i >= 0; i--)
     {
       if(AntiTrendBar(i))
         {
           ExtMapBufferUp[i] = ExtMapBufferUp[i+1];            
           ExtMapBufferDown[i] = ExtMapBufferDown[i+1];            
         }
       else
         {
           if(TrendUp(i))
             {
               ExtMapBufferUp[i] = CalcIndicValue(i, true);
               if(ExtMapBufferUp[i] < ExtMapBufferUp[i+1])
                   ExtMapBufferUp[i] = ExtMapBufferUp[i+1];                                 
               ExtMapBufferDown[i] = EMPTY_VALUE; 
             }
           else
             {
               ExtMapBufferDown[i] = CalcIndicValue(i, false);                        
               if(ExtMapBufferDown[i] > ExtMapBufferDown[i+1])
                   ExtMapBufferDown[i] = ExtMapBufferDown[i+1];                                             
               ExtMapBufferUp[i] = EMPTY_VALUE;
             }
         }
       // ïåðåñå÷åíèÿ ñ öåíîé                 
       if(TrendUp(i) && (Close[i] < ExtMapBufferUp[i]))
         {
           ExtMapBufferDown[i] = CalcIndicValue(i, false);  
           ExtMapBufferUp[i] = EMPTY_VALUE;
         }
       if((!TrendUp(i)) && (Close[i] > ExtMapBufferDown[i]))
         {
           ExtMapBufferUp[i] = CalcIndicValue(i, true);                  
           ExtMapBufferDown[i] = EMPTY_VALUE; 
         }
     }
   return(0);
  }
//+------------------------------------------------------------------+


Comments