Author: Forte928
geTrendOsc

This script is designed to analyze market price trends by smoothing out "noise" and identifying the underlying momentum of a financial instrument. It creates a visual oscillator that helps traders distinguish between short-term fluctuations and long-term directional movements.

Core Logic Overview

The tool operates through a three-stage mathematical process:

1. Relative Position Calculation First, the script looks at a specific window of recent price data (defined by the Window setting). It identifies the highest high and the lowest low within that period. It then calculates where the current closing price sits relative to that range. This tells the script whether the price is currently pushing toward the top, bottom, or middle of its recent movement area.

2. Momentum Normalization Once the relative positions are established, the script looks at a broader period (defined by OscPeriod). It combines these values into an oscillator. Rather than just showing a raw sum, it uses a normalization technique—balancing the positive and negative movements against their absolute values. This centers the data, making it easier to see how much "strength" is currently in the trend compared to the recent past.

3. The Hodrick-Prescott (HP) Filter This is the most sophisticated part of the logic. To prevent the oscillator from reacting too quickly to minor, insignificant price ticks (the "noise"), the script applies a Hodrick-Prescott Filter. This is a professional statistical method used to separate a time series into two components:

  • The Trend: The long-term, smooth movement of the price.
  • The Cycle: The short-term fluctuations or "wiggles."

By applying this filter, the script isolates the true underlying trend.

Visual Output and Interpretation

The script generates two primary visual elements on your chart:

  • The Oscillator (Trend Line): This represents the normalized momentum. It shows you how the price is moving relative to its recent high/low extremes.
  • The High-Pass Filter (HP Line): This is the result of the filtering process. It provides a much smoother view of the market's direction.

Key User Benefits

  • Noise Reduction: By using the HP Filter, the script helps traders avoid "fake-outs" where a small price jump might otherwise look like a significant trend change.
  • Trend Identification: It allows you to see if the current momentum is accelerating or decelerating in relation to the smoothed long-term trend.
  • Balanced Perspective: Because it calculates positions based on high/low ranges rather than just raw price, it provides a more balanced view of market "exhaustion" (when the price reaches the top or bottom of its range).
Price Data Components
Series array that contains the highest prices of each barSeries array that contains the lowest prices of each barSeries array that contains open prices of each barSeries array that contains close prices for each bar
Miscellaneous
It issuies visual alerts to the screenImplements a curve of type %1
13 Views
0 Downloads
0 Favorites
geTrendOsc
//+------------------------------------------------------------------+
//|																geTrendOsc.mq4		|
//|                      Copyright © 2007, ver 1.0							|
//|                      Forte928           									|
//+------------------------------------------------------------------+
#property copyright "Forte928"
#property link      ""
#define		IndicatorName "geTrendOsc"

//#property indicator_chart_window
#property indicator_separate_window

//#property indicator_maximum	100
//#property indicator_minimum	0


#property indicator_buffers 2
#property indicator_color1 YellowGreen
#property indicator_color2 Tomato
//#property indicator_color3 Wheat
//#property indicator_color4 LightSeaGreen

extern int		Window	= 1;
extern int		OscPeriod= 14;
extern bool		OscView	= true;
extern int		HPPeriod	= 100;
extern bool		HPView	= true;
extern int	 	Counter	= 2000;

//double  FreqTOL  =0.0001;//Tolerance of frequency calculation for Method 1

double	FxView1[];
double	FxView2[];
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~V~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Work Variables ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
double	TimeBuf1[];
double	TimeBuf2[];
double	TimeBuf3[];

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~V~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Initialization program Buffers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void	InitBufferam(int iBufferSize)
{
	ArrayResize(TimeBuf1,iBufferSize);
	ArrayResize(TimeBuf2,iBufferSize);
	ArrayResize(TimeBuf3,iBufferSize);
	return;
}
void	EmptyBufferam()
{
	ArrayInitialize(TimeBuf1,EMPTY_VALUE);
	ArrayInitialize(TimeBuf2,EMPTY_VALUE);
	ArrayInitialize(TimeBuf3,EMPTY_VALUE);
	return;
}
void	DoneBufferam()
{
	ArrayResize(TimeBuf1,0);
	ArrayResize(TimeBuf2,0);
	ArrayResize(TimeBuf3,0);
	return;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~V~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Program Constants ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int		MaxPeriod=0;
int		CalcCount=0;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Custom indicator initialization function ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int init()
  {
	if (Window<=0) Window=1;
//---- initialization program values  --------------------------------
	MaxPeriod=MathMax(OscPeriod,0);
	InitBufferam(MaxCounter(Counter,MaxPeriod));
	CalcCount=InitCounter(Counter,MaxPeriod);
//---- initialization indicators -------------------------------------
	SetupChartLine(0,FxView1,0,1,"OscTrend"+OscPeriod);// SetIndexStyle(0,DRAW_LINE,STYLE_SOLID,1); SetIndexBuffer(0,ValueBuf0);
	SetupChartLine(1,FxView2,0,1,"HPFilter"+HPPeriod);// SetIndexStyle(0,DRAW_LINE,STYLE_SOLID,1); SetIndexBuffer(0,ValueBuf0);
   IndicatorShortName(IndicatorName+"("+Window+","+OscPeriod+"("+HPPeriod+"))");
  	IndicatorDigits(MarketInfo(Symbol(),MODE_DIGITS));

	SetLevelValues(SlateGray,80,60,50,40,20,0);
//----
   return(0);
  }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~V~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Custom indicator deinitialization function ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int deinit()
  {
//----
	DoneBufferam();	
//----
   return(0);
  }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~V~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Start defination ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int start()
{
	if (!StartCounter(IndicatorName,Counter,CalcCount,MaxPeriod)) return(-1);
//------------------------------------------------------------------------------------
	EmptyBufferam();
//+-------------------------- Begin Cycle ---------------------------------------------------+\\
	string	Tools=Symbol();
	int		Frame=Period();
	double	IxHigh=0;
	double	IxLow=0;
	double	IxOpen=0;
	double	IxClose=0;
	
	for (int Rx=CalcCount-1;Rx>=0;Rx--){
		IxHigh=iHigh(Tools,Frame,iHighest(Tools,Frame,MODE_HIGH,Window,Rx));
		IxLow=iLow(Tools,Frame,iLowest(Tools,Frame,MODE_HIGH,Window,Rx));
		if ((IxHigh-IxLow)>0)	{
			IxOpen=iOpen(Tools,Frame,Window+Rx-1);
			IxClose=iClose(Tools,Frame,Rx);
			TimeBuf1[Rx]=(IxClose-IxOpen)/(IxHigh-IxLow);
		}
		else TimeBuf1[Rx]=0;
	}
	for (Rx=CalcCount-1;Rx>=0;Rx--){
		double Sumer=0;
		double AbsSumer=0;
		for (int Px=OscPeriod-1;Px>=0;Px--){
			Sumer=Sumer+TimeBuf1[Rx+Px];
			AbsSumer=AbsSumer+MathAbs(TimeBuf1[Rx+Px]);
		}
		if (AbsSumer!=0) TimeBuf2[Rx]=Sumer/AbsSumer*100/2+50;
		else TimeBuf2[Rx]=0;
	}
	HPFilter(TimeBuf2,TimeBuf3,HPPeriod,CalcCount);

	if (OscView==true) ArrayCopy(FxView1,TimeBuf2,0,0,CalcCount);
	if (HPView==true) ArrayCopy(FxView2,TimeBuf3,0,0,CalcCount);
	
//----
   return(0);
  }
//-----------------------------------------------------------------------------------------------
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~														 InitCounter																		~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 int InitCounter(int iPreCount,int iMaxPeriod)
{
	// Rule 1
	//if ((Result==0)||(Result>Bars)) Result=Bars;
	int Result=MaxCounter(iPreCount,iMaxPeriod);
	// Rule 2
	if ((Result+iMaxPeriod)>Bars) Result=Bars-iMaxPeriod;
	// Rule 3
	if (Result<iMaxPeriod) Result=0;
	else Result=Result+iMaxPeriod;
	return(Result);
}
//------------------------------------------ StartCounter --------------------------
bool StartCounter(string WindowName,int iPreCount,int& iCalcCount,int iMaxPeriod)
{
	if ((iPreCount>iCalcCount)||(iPreCount==0)) iCalcCount=InitCounter(iPreCount,iMaxPeriod);
	if (iCalcCount==0) 
	{
		Alert(WindowName+" "+Symbol()+"("+Period()+") - Limited Calculate Period");
		return(false);
	}
	return(true);
	//int iBarCount=IndicatorCounted();
	//if (iBarCount>0) return(true);
	//Print("StartCounter");
	return(false);
}
//------------------------------------------ StartCounter --------------------------
int MaxCounter(int iPreCount,int iMaxPeriod)
{
	int Result=iPreCount;
	// Rule 1
	//if ((Result==0)||(Result>Bars)) Result=Bars;
	if (Result==0) Result=Bars-1;
	if (Result<iMaxPeriod) Result=iMaxPeriod;
	return(Result+iMaxPeriod);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~														 Style active Line																~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void SetupChartLine(int Index,double& ViewAy[],int Style,int Width,string Label)
{
	switch(Style)
	{
		case 0 : SetIndexStyle(Index,DRAW_LINE,STYLE_SOLID,Width);break;
		case 1 : SetIndexStyle(Index,DRAW_HISTOGRAM,STYLE_SOLID,Width);break;
		case 2 : SetIndexStyle(Index,DRAW_ARROW,STYLE_SOLID,Width);break;
		default : SetIndexStyle(Index,DRAW_LINE,STYLE_SOLID,Width);break;
	}
	if (Label!="") SetIndexLabel(Index,Label);
	SetIndexBuffer(Index,ViewAy);
	return(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void SetLevelValues(color iColor,double iLevel1,double iLevel2,double iLevel3,double iLevel4,double iLevel5,double iLevel6)
{
	SetLevelStyle(EMPTY,EMPTY,iColor);
	if (iLevel1!=0) SetLevelValue(0,iLevel1);
	if (iLevel2!=0) SetLevelValue(1,iLevel2);
	if (iLevel3!=0) SetLevelValue(2,iLevel3);
	if (iLevel4!=0) SetLevelValue(3,iLevel4);
	if (iLevel5!=0) SetLevelValue(4,iLevel5);
	if (iLevel6!=0) SetLevelValue(5,iLevel6);

	return;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~											HPFilter	- Ôèëüòð Õîäðèêà-Ïðåñêîòòà														~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Hodrick-Prescott Filter-----------------------------------------------------------------+
void HPFilter(double& aySource[],double& ayResult[],int Lambda,int iCount)
{
   double Ak[],Bk[],Ck[],H1,H2,H3,H4,H5,HH1,HH2,HH3,HH4,HH5,HB,HC,Z;
   ArrayResize(Ak,iCount);
   ArrayResize(Bk,iCount);
   ArrayResize(Ck,iCount);
     
   Ak[0]=1.0+Lambda;
   Bk[0]=-2.0*Lambda;
   Ck[0]=Lambda;
   for(int Hx=1;Hx<iCount-2;Hx++)
   {
      Ak[Hx]=6.0*Lambda+1.0;
      Bk[Hx]=-4.0*Lambda;
      Ck[Hx]=Lambda;
   }
   Ak[1]=5.0*Lambda+1;
   Ak[iCount-1]=1.0+Lambda;
   Ak[iCount-2]=5.0*Lambda+1.0;
   Bk[iCount-2]=-2.0*Lambda;
   Bk[iCount-1]=0.0;
   Ck[iCount-2]=0.0;
   Ck[iCount-1]=0.0;
   
   //Forward
   for(Hx=0;Hx<iCount;Hx++)
   {
      Z=Ak[Hx]-H4*H1-HH5*HH2;
      HB=Bk[Hx];
      HH1=H1;
      H1=(HB-H4*H2)/Z;
      Bk[Hx]=H1;
      HC=Ck[Hx];
      HH2=H2;
      H2=HC/Z;
      Ck[Hx]=H2;
      Ak[Hx]=(aySource[Hx]-HH3*HH5-H3*H4)/Z;
      HH3=H3;
      H3=Ak[Hx];
      H4=HB-H5*HH1;
      HH5=H5;
      H5=HC;
   }
   
   //Backward 
   H2=0;
   H1=Ak[iCount-1];
   ayResult[iCount-1]=H1;
   for(Hx=iCount-2;Hx>=0;Hx--)
   {
      ayResult[Hx]=Ak[Hx]-Bk[Hx]*H1-Ck[Hx]*H2;
      H2=H1;
      H1=ayResult[Hx];
   }
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Comments