ParMA_BB
Download scriptThis technical tool is designed to provide a more advanced method of tracking price trends compared to standard moving averages. Rather than simply averaging past prices, it uses mathematical modeling to project where the price is headed based on its current trajectory.
Core Functionality
The primary purpose of this script is to calculate a Parabolic Moving Average (ParMA). While a typical moving average looks backward to tell you what has happened, this parabolic approach treats price movement as a curve. By calculating the "curvature" of recent price action, it attempts to identify the underlying momentum more smoothly.
Key Components
The logic is divided into two main layers:
1. The Parabolic Calculation (The Core) Instead of basic addition and division, the script uses a method called Parabolic Regression. It analyzes a specific window of recent price data (defined by the "Period" setting) to determine three specific coefficients. These coefficients allow the script to fit a mathematical curve to the market data.
- The final value provided is a projection that accounts for both the current price and its acceleration/deceleration over time.
2. Bollinger Band Integration (The Optional Layer) The script includes an optional feature that adds "Bands" to the ParMA line.
- Standard Deviation: When enabled, the script measures how much the price is fluctuating away from the average.
- Upper and Lower Bands: It calculates a "buffer zone" based on this volatility. This helps traders visualize whether the current price is behaving normally or if it is moving into an extreme territory (potentially indicating overbought or oversold conditions).
Visual and Data Output
- The Main Line: A smooth curve representing the Parabolic Moving Average.
- The Bands: If enabled, two additional lines appear above and below the main curve to show the volatility boundaries.
- On-Screen Dashboard: The script provides a real-time text display on your chart, showing the exact numerical values for the ParMA, the Upper Band, and the Lower Band simultaneously.
Summary of Behavior
In simple terms, this tool ignores "noise" by modeling the market as a curve rather than a series of jagged lines. It tells you not just where the price was, but helps define the path the price is currently carving out based on its recent momentum and volatility.
//+------------------------------------------------------------------+
//| ParMA_BB.mq4 |
//| Copyright © 2006, MetaQuotes Software Corp. |
//| http://www.metaquotes.net |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2006, MetaQuotes Software Corp."
#property link "http://www.metaquotes.net"
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_color1 BlueViolet // main line
#property indicator_color2 DodgerBlue // upper band
#property indicator_color3 DodgerBlue // lower band
//---- input parameters
extern int ParMA_Period = 30;
extern bool BandsEnabled = false;
extern double BandsDev = 1.0;
//---- buffers
double ParMABuffer[];
double UpperBandBuffer[];
double LowerBandBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
if (ParMA_Period <= 1) // fool-proof & to prevent zero divide error
{ ParMA_Period = 3; }
//---- indicators
IndicatorDigits(Digits);
//
SetIndexStyle(0, DRAW_LINE);
SetIndexBuffer(0, ParMABuffer);
SetIndexLabel(0, "ParMA Line");
SetIndexDrawBegin(0, ParMA_Period);
//
if (BandsEnabled == true) // initialize Bollinger Bands buffers, if allowed
{
SetIndexStyle(1, DRAW_LINE);
SetIndexBuffer(1, UpperBandBuffer);
SetIndexLabel(1, "ParMA Upper Band");
SetIndexDrawBegin(1, ParMA_Period);
//
SetIndexStyle(2, DRAW_LINE);
SetIndexBuffer(2, LowerBandBuffer);
SetIndexLabel(2, "ParMA Lower Band");
SetIndexDrawBegin(2, ParMA_Period);
}
//----
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//----
Comment(""); // remove comment when finished; see notes below
//----
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int start()
{
int counted_bars = IndicatorCounted();
int Limit, cnt, i, k;
double old_val, new_val, sum, std_dev;
//----
if (counted_bars < 0) { return(-1); } // to prevent possible erors
Limit = Bars - counted_bars;
//
if (Limit > ParMA_Period) // run once when getting started
{ cnt = Limit - ParMA_Period; }
else // run elsewhere
{ cnt = Limit; }
// calculate ParMA - one step on time-serie bars array
for (i=cnt; i>=0; i--)
{ ParMABuffer[i] = GetParMA(i, ParMA_Period); }
//
if (BandsEnabled == true) // draw Bollinger Bands, if allowed
{
// calculate standard deviation
i = Bars - ParMA_Period;
if (counted_bars > (ParMA_Period - 1))
{ i = Bars - counted_bars - 1; }
while (i >= 0)
{
sum = 0.0;
k = i + ParMA_Period - 1;
old_val = ParMABuffer[i];
while (k >= i)
{
new_val = Close[k] - old_val;
sum += new_val * new_val;
k--;
}
std_dev = MathSqrt(sum / ParMA_Period);
// complete BB's buffers
UpperBandBuffer[i] = old_val + BandsDev * std_dev;
LowerBandBuffer[i] = old_val - BandsDev * std_dev;
i--;
}
// optional - may be deleted without hesitations
// if you did it, remove 'Comment("");' from deinit() procedure too
Comment("ParMA = ", NormalizeDouble(ParMABuffer[0], Digits), "\n",
"UpperBand = ", NormalizeDouble(UpperBandBuffer[0], Digits), "\n",
"LowerBand = ", NormalizeDouble(LowerBandBuffer[0], Digits));
}
// optional - may be deleted without hesitations
// if you did it, remove 'Comment("");' from deinit() procedure too
if (BandsEnabled != true)
{ Comment("ParMA = ", NormalizeDouble(ParMABuffer[0], Digits)); }
//----
return(0);
}
//+------------------------------------------------------------------+
/*
Parabolic approximation: y(x) = b0 + b1 * x + b2 * x^2;
To obtain coefficients b0, b1, b2 we have to solve a linear system:
b0 * N + b1 * Sum(x,N) + b2 * Sum(x^2,N) = Sum(y,N);
b0 * Sum(x,N) + b1 * Sum(x^2,N) + b2 * Sum(x^3,N) = Sum((x*y),N);
b0 * Sum(x^2,N) + b1 * Sum(x^3,N) + b2 * Sum(x^4,N) = Sum(((x^2)*y),N);
that can easily be done explicitly by hands.
*/
//+------------------------------------------------------------------+
double GetParMA(int shift, int ma_period)
{
static int ro_cnt = 1; // run-once counter
static double sum_x = 0.0, sum_x2 = 0.0, sum_x3 = 0.0, sum_x4 = 0.0;
int i, loop_begin; // counters
double sum_y, sum_xy, sum_x2y, var_tmp;
double A, B, C, D, E, F, K, L, M, P, Q, R, S; // intermediates
double B0, B1, B2; // parabolic regression coefficients
double ret_val; // value to be returned - parabolic MA
//----
// initial accumulation - run once when getting started
while (ro_cnt <= ma_period)
{
var_tmp = ro_cnt;
sum_x += var_tmp; // sum(x)
var_tmp *= ro_cnt;
sum_x2 += var_tmp; // sum(x^2)
var_tmp *= ro_cnt;
sum_x3 += var_tmp; // sum(x^3)
var_tmp *= ro_cnt;
sum_x4 += var_tmp; // sum(x^4)
ro_cnt++;
}
// main calculation loop
loop_begin = shift + ma_period - 1;
sum_y = 0.0;
sum_xy = 0.0;
sum_x2y = 0.0;
for (i = 1; i<=ma_period; i++)
{
var_tmp = Close[loop_begin-i+1];
sum_y += var_tmp;
sum_xy += i * var_tmp; // sum(x*y)
sum_x2y += i * i * var_tmp; // sum((x^2)*y)
}
// initialization
A = ma_period;
B = sum_x; C = sum_x2; F = sum_x3;
M = sum_x4; P = sum_y; R = sum_xy; S = sum_x2y;
// intermediates
D = B; E = C; K = C; L = F;
Q = D / A; E = E - Q * B; F = F - Q * C;
R = R - Q * P; Q = K / A; L = L - Q * B;
M = M - Q * C; S = S - Q * P; Q = L / E;
// calculate regression coefficients
B2 = (S - R * Q) / (M - F * Q);
B1 = (R - F * B2) / E;
B0 = (P - B * B1 - C * B2) / A;
// value to be returned - parabolic MA
ret_val = B0 + (B1 + B2 * A) * A;
//----
return(ret_val);
}
//+------------------------------------------------------------------+
Comments