This technical indicator is designed to provide traders with a visually clear representation of market trends by smoothing out price fluctuations and highlighting potential turning points. It utilizes a specific mathematical approach known as the Hull Moving Average (HMA), which aims to reduce "lag"—the delay between a price movement and the indicator's reaction—while maintaining a smooth line.
Core Logic and Functionality
1. Multi-Layered Smoothing Process The script does not simply calculate a single average of the price. Instead, it processes data through several stages:
- Weighted Averaging: It uses a linear weighted method to give more importance to recent price data.
- Velocity Calculation: It compares two different averages (one based on a full period and one based on half that period) to determine the "velocity" or momentum of the price movement.
- Root Square Processing: It applies a square root calculation to the timeframe period, which helps in refining the curve's responsiveness to sudden market shifts.
2. Dynamic Trend Identification The indicator automatically categorizes the market into two states: Upward and Downward trends.
- Trend Coloring: The script changes the color of the line on your chart based on the direction of movement. When the price momentum is positive, the line adopts an "Up" color; when it turns negative, it switches to a "Down" color.
- Trend Persistence: It tracks the previous state of the market to ensure the transition between colors is distinct and clearly visible to the user.
3. Signal Generation (Arrows & Alerts) Beyond just showing a trend line, the script identifies specific "pivot points"—moments where the trend direction reverses suddenly.
- Visual Cues: When a reversal is detected (e.g., price moves from a downward slope to an upward peak), the script places visual markers (arrows) on the chart.
- Alert System: The logic includes an automated notification system. If the user enables alerts, the script will trigger an audible sound and a global variable update whenever a trend reversal occurs in real-time.
- Buffer Zone: It incorporates a "pip distance" logic to ensure that signals are generated with enough clearance from the peak/valley to help filter out minor market noise.
Summary for the User
In simple terms, this tool acts as a smart "filter." It takes messy price action and turns it into a smooth, color-coded line that tells you which way the market is heading. By identifying the exact moment the slope changes, it highlights potential entry or exit points via colored lines, arrows, and sound notifications, allowing you to see the market's "flow" more clearly than raw price alone would allow.
//+------------------------------------------------------------------+
//| HMA.mq4
//| Copyright © 2006 WizardSerg <wizardserg@mail.ru>, ?? ??????? ForexMagazine #104
//| wizardserg@mail.ru
//| Revised by IgorAD,igorad2003@yahoo.co.uk |
//| http://www.forex-tsd.com/ |
//+------------------------------------------------------------------+
/*
WRR modifications:
changed period to 20
changed method to 3 (Linear weighted moving average)
added notes describing settings for method, price, SetIndexStyle and iMA
added UpColour, DownColour and LineWidth settings
*/
#property copyright "MT4 release WizardSerg <wizardserg@mail.ru>, ?? ??????? ForexMagazine #104"
#property link "wizardserg@mail.ru"
#property indicator_chart_window
#property indicator_buffers 5
#property indicator_color1 LimeGreen //Uptrend Colour
#property indicator_color2 Red //Downtrend Colour
//---- input parameters
extern bool alert=true;
extern int period=18; //period 21 old, period 18 new
extern int method=3; // MODE_SMA old default, MODE_LWMA new default
/*
method settings
MODE_SMA 0 Simple moving average,
MODE_EMA 1 Exponential moving average,
MODE_SMMA 2 Smoothed moving average,
MODE_LWMA 3 Linear weighted moving average.
*/
extern int price=0; // PRICE_CLOSE
/*
price settings
PRICE_CLOSE 0 Close price.
PRICE_OPEN 1 Open price.
PRICE_HIGH 2 High price.
PRICE_LOW 3 Low price.
PRICE_MEDIAN 4 Median price, (high+low)/2.
PRICE_TYPICAL 5 Typical price, (high+low+close)/3.
PRICE_WEIGHTED 6 Weighted close price, (high+low+close+close)/4.
*/
extern color UpColour = LimeGreen;//indicator_color1
extern color DownColour = Red;//indicator_color2
extern int LineWidth = 2; //Valid values are: 1,2,3,4,5.
extern color arrow_up = DeepSkyBlue;
extern color arrow_dn = Orange;
extern int arrow_size = 0;
extern int pip_distance=10;
//---- buffers
double Uptrend[];
double Dntrend[];
double ar_up[];
double ar_dn[];
double ExtMapBuffer[];
bool sound;
static datetime soundTag = D'1980.01.01';
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
IndicatorBuffers(5);
SetIndexBuffer(0, Uptrend);
//ArraySetAsSeries(Uptrend, true);
SetIndexBuffer(1, Dntrend);
//ArraySetAsSeries(Dntrend, true);
SetIndexBuffer(2, ExtMapBuffer);
ArraySetAsSeries(ExtMapBuffer, true);
SetIndexStyle(0,DRAW_LINE,STYLE_SOLID,LineWidth,UpColour);
SetIndexStyle(1,DRAW_LINE,STYLE_SOLID,LineWidth,DownColour);
SetIndexStyle(3, DRAW_ARROW, EMPTY,arrow_size, arrow_up);
//SetIndexArrow(3, 159);
SetIndexArrow(3, 233);
SetIndexBuffer(3, ar_up);
SetIndexStyle(4, DRAW_ARROW, EMPTY,arrow_size, arrow_dn);
//SetIndexArrow(4, 159);
SetIndexArrow(4, 234);
SetIndexBuffer(4, ar_dn);
/*
SetIndexStyle sample and settings descriptions
void SetIndexStyle( int index, int type, int style=EMPTY, int width=EMPTY, color clr=CLR_NONE)
Sets the new type, style, width and color for a given indicator line.
Parameters:
index - Line index. Must lie between 0 and 7.
type - Shape style. Can be one of Drawing shape styles listed.
style - Drawing style. It is used for one-pixel thick lines. It can be one of the Drawing shape styles
listed. EMPTY value means that the style will not be changed.
width - Line width. Valid values are: 1,2,3,4,5. EMPTY value means that width will not be changed.
clr - Line color. Absence of this parameter means that the color will not be changed.
*/
IndicatorShortName("Hull Moving Average("+period+")");
return(0);
}
//+------------------------------------------------------------------+
//| Custor indicator deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
// ???? ????? ?????? ??????
return(0);
}
//+------------------------------------------------------------------+
//| ?????????? ??????? |
//+------------------------------------------------------------------+
double WMA(int x, int p)
{
return(iMA(NULL, 0, p, 0, method, price, x));
}
/*
iMA example and settings descriptions
double iMA( string symbol, int timeframe, int period, int ma_shift, int ma_method, int applied_price, int shift)
Calculates the Moving average indicator and returns its value.
Parameters:
symbol - Symbol the data of which should be used to calculate indicator. NULL means the current symbol.
timeframe - Timeframe. It can be any of Timeframe enumeration values. 0 means the current chart timeframe.
period - Averaging period for calculation.
ma_shift - MA shift. Indicators line offset relate to the chart by timeframe.
ma_method - MA method. It can be any of the Moving Average method enumeration value.
applied_price - Applied price. It can be any of Applied price enumeration values.
shift - Index of the value taken from the indicator buffer (shift relative to the current bar the given
amount of periods ago).
*/
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int start()
{
int counted_bars = IndicatorCounted();
if(counted_bars < 0)
return(-1);
int x = 0;
int p = MathSqrt(period);
int e = Bars - counted_bars + period + 1;
double vect[], trend[];
if(e > Bars)
e = Bars;
ArrayResize(vect, e);
ArraySetAsSeries(vect, true);
ArrayResize(trend, e);
ArraySetAsSeries(trend, true);
for(x = 0; x < e; x++)
{
vect[x] = 2*WMA(x, period/2) - WMA(x, period);
// Print("Bar date/time: ", TimeToStr(Time[x]), " close: ", Close[x], " vect[", x, "] = ", vect[x], " 2*WMA(p/2) = ", 2*WMA(x, period/2), " WMA(p) = ", WMA(x, period));
}
for(x = 0; x < e-period; x++)
ExtMapBuffer[x] = iMAOnArray(vect, 0, p, 0, method, x);
for(x = e-period; x >= 0; x--)
{
trend[x] = trend[x+1];
if (ExtMapBuffer[x]> ExtMapBuffer[x+1]) trend[x] =1;
if (ExtMapBuffer[x]< ExtMapBuffer[x+1]) trend[x] =-1;
if (ExtMapBuffer[x+2]< ExtMapBuffer[x+3]&&ExtMapBuffer[x+1]> ExtMapBuffer[x+2]) {sound=true;ar_up[x] =ExtMapBuffer[x+1]-pip_distance*Point;GlobalVariableSet("hma_signal",2);}
if (ExtMapBuffer[x+2]> ExtMapBuffer[x+3]&&ExtMapBuffer[x+1]< ExtMapBuffer[x+2]) {sound=true;ar_dn[x] =ExtMapBuffer[x+1]+pip_distance*Point;GlobalVariableSet("hma_signal",3);}
if (alert&&sound&&ExtMapBuffer[x+2]< ExtMapBuffer[x+3]&&ExtMapBuffer[x+1]> ExtMapBuffer[x+2]&&x==0&& soundTag!=Time[0]){PlaySound ("alert.wav");sound=false;soundTag = Time[0];}
if (alert&&sound&&ExtMapBuffer[x+2]> ExtMapBuffer[x+3]&&ExtMapBuffer[x+1]< ExtMapBuffer[x+2]&&x==0&& soundTag!=Time[0]){PlaySound ("alert.wav");sound=false;soundTag = Time[0];}
sound=false;
if (trend[x]>0)
{ Uptrend[x] = ExtMapBuffer[x];
if (trend[x+1]<0) Uptrend[x+1]=ExtMapBuffer[x+1];
Dntrend[x] = EMPTY_VALUE;
}
else
if (trend[x]<0)
{
Dntrend[x] = ExtMapBuffer[x];
if (trend[x+1]>0) Dntrend[x+1]=ExtMapBuffer[x+1];
Uptrend[x] = EMPTY_VALUE;
}
//Print( " trend=",trend[x]);
}
return(0);
}
//+------------------------------------------------------------------+
Comments