Overview of the Indicator Logic
This script is designed to analyze price movements by calculating a mathematical "best fit" curve based on historical data. Rather than simply following the current price (which can be erratic), it seeks to identify the underlying trend or trajectory of the market by using advanced statistical modeling.
Core Mechanism: Polynomial Curve Fitting
The primary logic of this tool relies on a mathematical technique known as Polynomial Regression. Here is how that works in plain terms:
- Data Selection: The script looks at a specific window of historical price data (determined by the "bars" setting).
- Trend Mapping: Instead of drawing a straight line from point A to point B, it calculates a curve that minimizes the distance between itself and all the price points in that window. This allows the indicator to smooth out "noise" (minor, insignificant price fluctuations) to show the broader direction of the market.
- Degree of Complexity: The "degree" setting determines how flexible this curve is. A lower degree results in a smoother, simpler trend line, while a higher degree allows the curve to bend more to accommodate complex price patterns.
Statistical Calculation (Gauss Elimination)
To create this accurate curve, the script performs heavy internal calculations using a method called Gauss Elimination. It builds a mathematical matrix of the price data and solves for variables that define the most accurate possible curve for that specific timeframe. By solving these equations, the indicator provides a "forecast" line that represents where the price is mathematically heading based on its recent path.
Volatility and Boundary Channels
Once the primary trend line (the regression curve) is established, the script performs further calculations to create visual boundaries:
- Standard Deviation: The tool measures how much the actual price typically deviates from the calculated trend line.
- Upper and Lower Bands: By applying a multiplier to this deviation (the "kstd" setting), the script generates two outer boundaries—an upper band and a lower band.
- The Channel: These three components (the central trend line, the upper boundary, and the lower boundary) create a visual channel. Traders can use this to see if the price is overextended (hitting the outer bands) or following the core momentum of the market.
Visual Elements and Tracing
- Trend Lines (Rays): The script includes a feature to draw specific "rays" or short trend segments. These act as visual anchors, highlighting recent shifts in direction between specific points in time.
- Dynamic Updates: As new price data arrives, the script re-calculates the curve and its boundaries, allowing the trend path to evolve dynamically with the market.
//http://www.forex-tsd.com/suggestions-trading-systems/20012-didgeridoo-trading-system.html
//mod trail 2009fxtsd
//----
#property indicator_chart_window
#property indicator_buffers 6
#property indicator_color4 LimeGreen
#property indicator_color5 Gold
#property indicator_color6 Gold
#property indicator_color1 Blue
#property indicator_color2 Brown
#property indicator_color3 Maroon
#property indicator_style1 4
#property indicator_style2 4
#property indicator_style3 4
extern int degree = 3;
extern double kstd = 2.0;
extern int bars = 250;
extern int shift = 0;
extern bool traceLines = 1;
extern bool traceRays = 1;
//-----
double fx[],sqh[],sql[];
double fx1[],sqh1[],sql1[];
double ai[10,10],b[10],x[10],sx[20];
double sum;
int ip,p,n,f;
double qq,mm,tt;
int ii,jj,kk,ll,nn;
double sq;
int i0 = 0;
/*
void clear()
{
int total = ObjectsTotal();
for (int i=total-1; i >= 0; i--)
{
string name = ObjectName(i);
if (StringFind(name, prefix) == 0) ObjectDelete(name);
}
}
*/
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
SetIndexBuffer(3, fx); // Áóôåðû ìàññèâîâ èíäèêàòîðà
SetIndexBuffer(4, sqh);
SetIndexBuffer(5, sql);
SetIndexStyle(3, DRAW_LINE);
SetIndexStyle(4, DRAW_LINE);
SetIndexStyle(5, DRAW_LINE);
SetIndexEmptyValue(3, 0.0);
SetIndexEmptyValue(4, 0.0);
SetIndexEmptyValue(5, 0.0);
SetIndexShift(3, shift);
SetIndexShift(4, shift);
SetIndexShift(5, shift);
if (traceLines) {
SetIndexBuffer(0, fx1);
SetIndexBuffer(1, sqh1);
SetIndexBuffer(2, sql1);
}
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{ for (int i=0;i<Bars;i++)
{
ObjectDelete("Ray1"+Time[i]);
ObjectDelete("Ray2"+Time[i]);
ObjectDelete("Ray3"+Time[i]);
ObjectDelete("Ray11"+Time[i]);
ObjectDelete("Ray21"+Time[i]);
ObjectDelete("Ray31"+Time[i]);
}
//clear();
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int start()
{
if (Bars < bars) return;
//----
int mi; // ïåðåìåííàÿ èñïîëüçóþùàÿñÿ òîëüêî â start
ip = bars;
p=ip; // òèïà ïðèñâàèâàíèå
sx[1]=p+1; // ïðèìå÷àíèå - [] - îçíà÷àåò ìàññèâ
nn = degree+1;
SetIndexDrawBegin(0, Bars-p-1);
SetIndexDrawBegin(1, Bars-p-1);
SetIndexDrawBegin(2, Bars-p-1);
//----------------------sx-------------------------------------------------------------------
for(mi=1;mi<=nn*2-2;mi++) // ìàòåìàòè÷åñêîå âûðàæåíèå - äëÿ âñåõ mi îò 1 äî nn*2-2
{
sum=0;
for(n=i0;n<=i0+p;n++)
{
sum+=MathPow(n,mi);
}
sx[mi+1]=sum;
}
//----------------------syx-----------
for(mi=1;mi<=nn;mi++)
{
sum=0.00000;
for(n=i0;n<=i0+p;n++)
{
if(mi==1) sum+=Close[n];
else sum+=Close[n]*MathPow(n,mi-1);
}
b[mi]=sum;
}
//===============Matrix=======================================================================================================
for(jj=1;jj<=nn;jj++)
{
for(ii=1; ii<=nn; ii++)
{
kk=ii+jj-1;
ai[ii,jj]=sx[kk];
}
}
//===============Gauss========================================================================================================
for(kk=1; kk<=nn-1; kk++)
{
ll=0;
mm=0;
for(ii=kk; ii<=nn; ii++)
{
if(MathAbs(ai[ii,kk])>mm)
{
mm=MathAbs(ai[ii,kk]);
ll=ii;
}
}
if(ll==0) return(0);
if (ll!=kk)
{
for(jj=1; jj<=nn; jj++)
{
tt=ai[kk,jj];
ai[kk,jj]=ai[ll,jj];
ai[ll,jj]=tt;
}
tt=b[kk];
b[kk]=b[ll];
b[ll]=tt;
}
for(ii=kk+1;ii<=nn;ii++)
{
qq=ai[ii,kk]/ai[kk,kk];
for(jj=1;jj<=nn;jj++)
{
if(jj==kk) ai[ii,jj]=0;
else ai[ii,jj]=ai[ii,jj]-qq*ai[kk,jj];
}
b[ii]=b[ii]-qq*b[kk];
}
}
x[nn]=b[nn]/ai[nn,nn];
for(ii=nn-1;ii>=1;ii--)
{
tt=0;
for(jj=1;jj<=nn-ii;jj++)
{
tt=tt+ai[ii,ii+jj]*x[ii+jj];
x[ii]=(1/ai[ii,ii])*(b[ii]-tt);
}
}
//===========================================================================================================================
for(n=i0;n<=i0+p;n++)
{
sum=0;
for(kk=1;kk<=degree;kk++)
{
sum+=x[kk+1]*MathPow(n,kk);
}
fx[n]=x[1]+sum;
}
//-----------------------------------Std-----------------------------------------------------------------------------------
sq=0.0;
for(n=i0;n<=i0+p;n++)
{
sq+=MathPow(Close[n]-fx[n],2);
}
sq=MathSqrt(sq/(p+1))*kstd;
for(n=i0;n<=i0+p;n++)
{
sqh[n]=fx[n]+sq;
sql[n]=fx[n]-sq;
}
for(n=0;n<Bars-IndicatorCounted();n++)
{
fx1[n]=fx[n];
sqh1[n]=sqh[n];
sql1[n]=sql[n];
}
if (traceRays)
{
if ( ObjectFind ("Ray1"+Time[0])== -1 )
ObjectCreate("Ray1"+Time[0],OBJ_TREND,0,Time[3],sqh[3],Time[0],sqh[0]);
ObjectSet ("Ray1"+Time[0],OBJPROP_COLOR,Red);
ObjectSet ("Ray1"+Time[0],OBJPROP_RAY,false);
if ( ObjectFind ("Ray11"+Time[0])== -1 )
ObjectCreate("Ray11"+Time[0],OBJ_TREND,0,Time[7],sqh[7],Time[5],sqh[5]);
ObjectSet ("Ray11"+Time[0],OBJPROP_COLOR,Maroon);
ObjectSet ("Ray11"+Time[0],OBJPROP_RAY,false);
if ( ObjectFind ("Ray2"+Time[0])== -1 )
ObjectCreate("Ray2"+Time[0],OBJ_TREND,0,Time[7],fx[7],Time[5],fx[5]);
ObjectSet ("Ray2"+Time[0],OBJPROP_COLOR,Blue);
ObjectSet ("Ray2"+Time[0],OBJPROP_RAY,false);
if ( ObjectFind ("Ray21"+Time[0])== -1 )
ObjectCreate("Ray21"+Time[0],OBJ_TREND,0,Time[3],fx[3],Time[0],fx[0]);
ObjectSet ("Ray21"+Time[0],OBJPROP_COLOR,RoyalBlue);
ObjectSet ("Ray21"+Time[0],OBJPROP_RAY,false);
if ( ObjectFind ("Ray31"+Time[0])== -1 )
ObjectCreate("Ray31"+Time[0],OBJ_TREND,0,Time[7],sql[7],Time[5],sql[5]);
ObjectSet ("Ray31"+Time[0],OBJPROP_COLOR,Maroon);
ObjectSet ("Ray31"+Time[0],OBJPROP_RAY,false);
if ( ObjectFind ("Ray3"+Time[0])== -1 )
ObjectCreate("Ray3"+Time[0],OBJ_TREND,0,Time[3],sql[3],Time[0],sql[0]);
ObjectSet ("Ray3"+Time[0],OBJPROP_COLOR,Red);
ObjectSet ("Ray3"+Time[0],OBJPROP_RAY,false);
}
return(0);
}
//+------------------------------------------------------------------+
Comments