Watch how to download trading robots for free
Find us on Telegram!
Join our fan page
Join our fan page
You liked the script? Try it in the MetaTrader 5 terminal
- Views:
- 22
- Published:
-
Need a robot or indicator based on this code? Order it on Freelance Go to Freelance
//+------------------------------------------------------------------+ //| UnifiedHullMA.mq5 |
//| Unified Hull MA - 4 lines with directional colors |
//| Supports 2, 3, or 4 Hull lines |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, C.J. Weekes"
#property copyright "Copyright 2026, Alfonso Golden Trader"
#property version "1.00"
#property description "Hull Moving Average indicator with four periods on a single chart."
#property description "Colour-coded by direction. Ring-buffer memory management."
#property description "Buffer layout: 0/1=Hull1, 2/3=Hull2, 4/5=Hull3, 6/7=Hull4."
#property indicator_chart_window
#property indicator_buffers 8
#property indicator_plots 4
//--- Hull Line 1 (Buffer 0/1)
#property indicator_type1 DRAW_COLOR_LINE
#property indicator_color1 clrGray, clrLime, clrRed
#property indicator_width1 2
#property indicator_label1 "Hull1"
//--- Hull Line 2 (Buffer 2/3)
#property indicator_type2 DRAW_COLOR_LINE
#property indicator_color2 clrGray, clrDodgerBlue, clrOrangeRed
#property indicator_width2 2
#property indicator_label2 "Hull2"
//--- Hull Line 3 (Buffer 4/5)
#property indicator_type3 DRAW_COLOR_LINE
#property indicator_color3 clrGray, clrAqua, clrMagenta
#property indicator_width3 2
#property indicator_label3 "Hull3"
//--- Hull Line 4 (Buffer 6/7)
#property indicator_type4 DRAW_COLOR_LINE
#property indicator_color4 clrGray, clrGold, clrDarkOrchid
#property indicator_width4 2
#property indicator_label4 "Hull4"
//--- Input parameters
input int InpPeriod1 = 8; // Hull 1 Period
input int InpPeriod2 = 20; // Hull 2 Period
input int InpPeriod3 = 50; // Hull 3 Period
input int InpPeriod4 = 200; // Hull 4 Period
input int InpDivisor = 2; // Hull Divisor
input int InpMaxBars = 5000; // Max bars to retain (0 = unlimited)
//--- Indicator buffers
double hull1Buffer[], color1Buffer[];
double hull2Buffer[], color2Buffer[];
double hull3Buffer[], color3Buffer[];
double hull4Buffer[], color4Buffer[];
//+------------------------------------------------------------------+
//| CHull class - memory-optimized Hull MA calculator |
//+------------------------------------------------------------------+
class CHull
{
private:
int m_fullPeriod;
int m_halfPeriod;
int m_sqrtPeriod;
int m_maxBars;
int m_arraySize;
double m_weight1;
double m_weight2;
double m_weight3;
double m_divisor;
struct sHullArrayStruct
{
double value;
double value3;
double wsum1;
double wsum2;
double wsum3;
double lsum1;
double lsum2;
double lsum3;
};
sHullArrayStruct m_array[];
void ZeroArray()
{
for(int i = 0; i < m_arraySize; i++)
{
m_array[i].value = 0;
m_array[i].value3 = 0;
m_array[i].wsum1 = 0;
m_array[i].wsum2 = 0;
m_array[i].wsum3 = 0;
m_array[i].lsum1 = 0;
m_array[i].lsum2 = 0;
m_array[i].lsum3 = 0;
}
}
public:
CHull() : m_fullPeriod(1), m_halfPeriod(1), m_sqrtPeriod(1),
m_maxBars(0), m_arraySize(0), m_divisor(2.0) { }
~CHull() { ArrayFree(m_array); }
bool init(int period, double divisor, int maxBars=0)
{
m_divisor = (divisor > 1.0) ? divisor : 2.0;
m_fullPeriod = (int)(period > 1 ? period : 1);
m_halfPeriod = (int)(m_fullPeriod > 1 ? m_fullPeriod / m_divisor : 1);
m_sqrtPeriod = (int)MathSqrt(m_fullPeriod);
m_maxBars = (maxBars > m_fullPeriod * 2) ? maxBars : 0;
m_arraySize = 0;
m_weight1 = m_weight2 = m_weight3 = 1;
if(m_maxBars > 0)
{
m_arraySize = ArrayResize(m_array, m_maxBars);
if(m_arraySize < m_maxBars) return false;
ZeroArray();
}
return true;
}
double calculate(double value, int i, int bars)
{
if(m_maxBars <= 0)
{
if(m_arraySize < bars)
{
m_arraySize = ArrayResize(m_array, bars + 500);
if(m_arraySize < bars) return 0;
}
return CalculateUnlimited(value, i);
}
return CalculateRingBuffer(value, i);
}
private:
double CalculateUnlimited(double value, int i)
{
m_array[i].value = value;
if(i > m_fullPeriod)
{
m_array[i].wsum1 = m_array[i-1].wsum1 + value * m_halfPeriod - m_array[i-1].lsum1;
m_array[i].lsum1 = m_array[i-1].lsum1 + value - m_array[i-m_halfPeriod].value;
m_array[i].wsum2 = m_array[i-1].wsum2 + value * m_fullPeriod - m_array[i-1].lsum2;
m_array[i].lsum2 = m_array[i-1].lsum2 + value - m_array[i-m_fullPeriod].value;
}
else
{
m_array[i].wsum1 = m_array[i].wsum2 =
m_array[i].lsum1 = m_array[i].lsum2 = m_weight1 = m_weight2 = 0;
for(int k=0, w1=m_halfPeriod, w2=m_fullPeriod; w2>0 && i>=k; k++, w1--, w2--)
{
if(w1>0)
{
m_array[i].wsum1 += m_array[i-k].value * w1;
m_array[i].lsum1 += m_array[i-k].value;
m_weight1 += w1;
}
m_array[i].wsum2 += m_array[i-k].value * w2;
m_array[i].lsum2 += m_array[i-k].value;
m_weight2 += w2;
}
}
m_array[i].value3 = 2.0 * m_array[i].wsum1 / m_weight1 - m_array[i].wsum2 / m_weight2;
if(i > m_sqrtPeriod)
{
m_array[i].wsum3 = m_array[i-1].wsum3 + m_array[i].value3 * m_sqrtPeriod - m_array[i-1].lsum3;
m_array[i].lsum3 = m_array[i-1].lsum3 + m_array[i].value3 - m_array[i-m_sqrtPeriod].value3;
}
else
{
m_array[i].wsum3 =
m_array[i].lsum3 = m_weight3 = 0;
for(int k=0, w3=m_sqrtPeriod; w3>0 && i>=k; k++, w3--)
{
m_array[i].wsum3 += m_array[i-k].value3 * w3;
m_array[i].lsum3 += m_array[i-k].value3;
m_weight3 += w3;
}
}
return(m_array[i].wsum3 / m_weight3);
}
double CalculateRingBuffer(double value, int i)
{
int idx = i % m_maxBars;
int prevIdx = (i > 0) ? (i-1) % m_maxBars : idx;
m_array[idx].value = value;
if(i > m_fullPeriod)
{
int halfBackIdx = (i - m_halfPeriod) % m_maxBars;
int fullBackIdx = (i - m_fullPeriod) % m_maxBars;
m_array[idx].wsum1 = m_array[prevIdx].wsum1 + value * m_halfPeriod - m_array[prevIdx].lsum1;
m_array[idx].lsum1 = m_array[prevIdx].lsum1 + value - m_array[halfBackIdx].value;
m_array[idx].wsum2 = m_array[prevIdx].wsum2 + value * m_fullPeriod - m_array[prevIdx].lsum2;
m_array[idx].lsum2 = m_array[prevIdx].lsum2 + value - m_array[fullBackIdx].value;
}
else
{
m_array[idx].wsum1 = m_array[idx].wsum2 =
m_array[idx].lsum1 = m_array[idx].lsum2 = m_weight1 = m_weight2 = 0;
for(int k=0, w1=m_halfPeriod, w2=m_fullPeriod; w2>0 && i>=k; k++, w1--, w2--)
{
int backIdx = (i - k) % m_maxBars;
if(w1>0)
{
m_array[idx].wsum1 += m_array[backIdx].value * w1;
m_array[idx].lsum1 += m_array[backIdx].value;
m_weight1 += w1;
}
m_array[idx].wsum2 += m_array[backIdx].value * w2;
m_array[idx].lsum2 += m_array[backIdx].value;
m_weight2 += w2;
}
}
m_array[idx].value3 = 2.0 * m_array[idx].wsum1 / m_weight1 - m_array[idx].wsum2 / m_weight2;
if(i > m_sqrtPeriod)
{
int sqrtBackIdx = (i - m_sqrtPeriod) % m_maxBars;
m_array[idx].wsum3 = m_array[prevIdx].wsum3 + m_array[idx].value3 * m_sqrtPeriod - m_array[prevIdx].lsum3;
m_array[idx].lsum3 = m_array[prevIdx].lsum3 + m_array[idx].value3 - m_array[sqrtBackIdx].value3;
}
else
{
m_array[idx].wsum3 =
m_array[idx].lsum3 = m_weight3 = 0;
for(int k=0, w3=m_sqrtPeriod; w3>0 && i>=k; k++, w3--)
{
int backIdx = (i - k) % m_maxBars;
m_array[idx].wsum3 += m_array[backIdx].value3 * w3;
m_array[idx].lsum3 += m_array[backIdx].value3;
m_weight3 += w3;
}
}
return(m_array[idx].wsum3 / m_weight3);
}
};
CHull iHull1, iHull2, iHull3, iHull4;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
SetIndexBuffer(0, hull1Buffer, INDICATOR_DATA);
SetIndexBuffer(1, color1Buffer, INDICATOR_COLOR_INDEX);
SetIndexBuffer(2, hull2Buffer, INDICATOR_DATA);
SetIndexBuffer(3, color2Buffer, INDICATOR_COLOR_INDEX);
SetIndexBuffer(4, hull3Buffer, INDICATOR_DATA);
SetIndexBuffer(5, color3Buffer, INDICATOR_COLOR_INDEX);
SetIndexBuffer(6, hull4Buffer, INDICATOR_DATA);
SetIndexBuffer(7, color4Buffer, INDICATOR_COLOR_INDEX);
iHull1.init(InpPeriod1, InpDivisor, InpMaxBars);
iHull2.init(InpPeriod2, InpDivisor, InpMaxBars);
iHull3.init(InpPeriod3, InpDivisor, InpMaxBars);
iHull4.init(InpPeriod4, InpDivisor, InpMaxBars);
IndicatorSetString(INDICATOR_SHORTNAME,
StringFormat("UnifiedHullMA(%d,%d,%d,%d)",
InpPeriod1, InpPeriod2, InpPeriod3, InpPeriod4));
IndicatorSetInteger(INDICATOR_DIGITS, _Digits);
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[])
{
int i = prev_calculated - 1;
if(i < 0) i = 0;
for(; i < rates_total && !_StopFlag; i++)
{
double price = close[i];
hull1Buffer[i] = iHull1.calculate(price, i, rates_total);
hull2Buffer[i] = iHull2.calculate(price, i, rates_total);
hull3Buffer[i] = iHull3.calculate(price, i, rates_total);
hull4Buffer[i] = iHull4.calculate(price, i, rates_total);
if(i > 0)
{
color1Buffer[i] = (hull1Buffer[i] > hull1Buffer[i-1]) ? 1 :
((hull1Buffer[i] < hull1Buffer[i-1]) ? 2 : color1Buffer[i-1]);
color2Buffer[i] = (hull2Buffer[i] > hull2Buffer[i-1]) ? 1 :
((hull2Buffer[i] < hull2Buffer[i-1]) ? 2 : color2Buffer[i-1]);
color3Buffer[i] = (hull3Buffer[i] > hull3Buffer[i-1]) ? 1 :
((hull3Buffer[i] < hull3Buffer[i-1]) ? 2 : color3Buffer[i-1]);
color4Buffer[i] = (hull4Buffer[i] > hull4Buffer[i-1]) ? 1 :
((hull4Buffer[i] < hull4Buffer[i-1]) ? 2 : color4Buffer[i-1]);
}
else
{
color1Buffer[i] = color2Buffer[i] = color3Buffer[i] = color4Buffer[i] = 0;
}
}
return rates_total;
}
//+------------------------------------------------------------------+
Prop Firm Daily Drawdown Visualizer (Free)
Protect Your Funded Account with Institutional-Grade Risk Monitoring. The #1 reason traders fail prop firm challenges is not a bad strategy; it is breaching daily drawdown limits. The AlphaQuant Prop Firm Daily Drawdown Dashboard is a free, high-visibility Expert Advisor
News Filter for the Strategy Tester (DST-corrected calendar export)
A real economic-calendar news filter that also works in backtests. Export the events once with a script, then block new entries around news both live and in the Strategy Tester. Fixes the one-hour DST shift of historical calendar times.
Accelerator Oscillator (AC)
The Acceleration/Deceleration Indicator (AC) measures acceleration and deceleration of the current driving force.
MACD Signals
Indicator edition for new platform.