Overview
This script is a technical analysis tool designed for the MetaTrader platform to help traders identify momentum and trend direction in financial markets. It uses a logic based on the "Fisher" indicator principle, which focuses on identifying when a market is moving upward or downward by analyzing the relative position of current prices compared to recent historical price extremes.
Core Logic and Workflow
The script operates through a step-by-step calculation process to transform raw price data into a visual trend signal:
1. Data Gathering and Range Analysis
The tool first looks back at a specific number of previous bars (defined by the RangePeriods setting). Within this timeframe, it identifies the highest high and the lowest low. By doing this, the script establishes a "trading zone" for that period.
2. Price Positioning For every new price candle, the script calculates where the current price sits relative to that "trading zone."
- If the price is near the top of the high/low range, it assigns a high positive value.
- If the price is near the bottom, it assigns a low negative value. The goal here is to normalize the price into a standardized scale (ranging between -1 and +1).
3. Multi-Stage Smoothing To prevent the indicator from reacting too violently to "market noise" or tiny, insignificant price fluctuations, the script applies two distinct layers of smoothing:
- Price Smoothing: It smooths the relative position of the price.
- Index Smoothing: It takes that smoothed position and applies a secondary smoothing pass. This ensures that the resulting trend line is fluid rather than jagged.
4. The Fisher Transformation The script applies a mathematical logarithmic transformation to the smoothed data. This specific calculation is designed to exaggerate the "stretch" of the move, making it easier for traders to see when a trend is gaining significant strength or losing steam.
5. Visual Output and Trend Identification Finally, the script interprets the results into a visual histogram:
- Upward Trend: If the final calculated value is positive, the tool displays a light blue histogram above the zero line.
- Downward Trend: If the final value is negative, it displays a red histogram below the zero line.
Automated Alerts
The script includes an intelligent notification system. It monitors for "Zero Crossings"—the specific moment when the momentum shifts from positive to negative (or vice versa). When these critical turning points occur, the script can trigger an automatic alert to notify the user in real-time, highlighting a potential shift in market direction.
//+------------------------------------------------------------------+
//| Fisher_m11.mq4 |
//| Copyright © forexjr
//| http://home.arcor.de/cam06/fisher |
//+------------------------------------------------------------------+
#property copyright "Copyright © 23.07.2006 MartinG "
#property link "http://home.arcor.de/cam06/fisher"
#property indicator_separate_window
//#property indicator_minimum -1
//#property indicator_maximum 1
#property indicator_buffers 3
#property indicator_color2 LightSkyBlue
#property indicator_color3 Red
#property indicator_width2 4
#property indicator_width3 4
int LeftNum1=56;
int LeftNum2=56;
extern int RangePeriods=120;//was 30
extern double PriceSmoothing=0.67; // =0.67 bei Fisher_m10
extern double IndexSmoothing=0.5; // =0.50 bei Fisher_m10
string ThisName="Fisher_kuskus";
int DrawStart;
//---- buffers
double ExtMapBuffer1[];
double ExtMapBuffer2[];
double ExtMapBuffer3[];
double ExtMapBuffer4[];
int flagval1 = 0;
int flagval2 = 0;
extern bool AlertON=true;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
//---- indicators
IndicatorBuffers(4);
SetIndexLabel(0,"Star");
SetIndexStyle(0,DRAW_NONE);
SetIndexBuffer(0,ExtMapBuffer1);
SetIndexStyle(1,DRAW_HISTOGRAM);
SetIndexBuffer(1,ExtMapBuffer2);
SetIndexStyle(2,DRAW_HISTOGRAM);
SetIndexBuffer(2,ExtMapBuffer3);
SetIndexStyle(3,DRAW_NONE);
SetIndexBuffer(3,ExtMapBuffer4);
string Text=ThisName;
Text=Text+" (rPeriods "+RangePeriods;
Text=Text+", pSmooth "+DoubleToStr(PriceSmoothing,2);
Text=Text+", iSmooth "+DoubleToStr(IndexSmoothing,2);
Text=Text+") ";
IndicatorShortName(Text);
SetIndexLabel(1,NULL);
SetIndexLabel(2,NULL);
DrawStart=2*RangePeriods+4; // DrawStart= BarNumber calculated from left to right
SetIndexDrawBegin(1,DrawStart);
SetIndexDrawBegin(2,DrawStart);
if (PriceSmoothing>=1.0)
{
PriceSmoothing=0.9999;
Alert("Fish61: PriceSmothing factor has to be smaller 1!");
}
if (PriceSmoothing<0)
{
PriceSmoothing=0;
Alert("Fish61: PriceSmothing factor mustn''t be negative!");
}
if (IndexSmoothing>=1.0)
{
IndexSmoothing=0.9999;
Alert("Fish61: PriceSmothing factor has to be smaller 1!");
}
if (IndexSmoothing<0)
{
IndexSmoothing=0;
Alert("Fish61: PriceSmothing factor mustn''t be negative!");
}
//----
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//----
//----
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int start()
{
if (Bars<DrawStart)
{
Alert("Fish84: Not enough Bars loaded to calculate FisherIndicator with RangePeriods=",RangePeriods);
return(-1);
}
//----
int counted_bars=IndicatorCounted();
if (counted_bars<0) return(-1);
if (counted_bars>0) counted_bars--;
//----
int Position=Bars-counted_bars; // Position = BarPosition calculated from right to left
int LeftNum1=Bars-Position; // when more bars are loaded the Position of a bar changes but not its LeftNum
if (LeftNum1<RangePeriods+1)Position=Bars-RangePeriods-1;
while(Position>=0)
{
CalculateCurrentBar(Position);
Position--;
}
//----
return(0);
}
//+------------------------------------------------------------------+
//| Single Bar Calculation function |
//+------------------------------------------------------------------+
int CalculateCurrentBar(int pos)
{
double LowestLow, HighestHigh, GreatestRange, MidPrice;
double PriceLocation, SmoothedLocation, FishIndex, SmoothedFish;
//----
LowestLow = Low[Lowest(NULL,0,MODE_LOW,RangePeriods,pos)];
HighestHigh = High[Highest(NULL,0,MODE_HIGH,RangePeriods,pos)];
if (HighestHigh-LowestLow<0.1*Point)HighestHigh=LowestLow+0.1*Point;
GreatestRange=HighestHigh-LowestLow;
MidPrice = (High[pos]+Low[pos])/2;
// PriceLocation in current Range
if (GreatestRange!=0)
{
PriceLocation=(MidPrice-LowestLow)/GreatestRange;
PriceLocation= 2.0*PriceLocation - 1.0; // -> -1 < PriceLocation < +1
}
// Smoothing of PriceLocation
ExtMapBuffer4[pos]=PriceSmoothing*ExtMapBuffer4[pos+1]+(1.0-PriceSmoothing)*PriceLocation;
SmoothedLocation=ExtMapBuffer4[pos];
if (SmoothedLocation> 0.99) SmoothedLocation= 0.99; // verhindert, dass MathLog unendlich wird
if (SmoothedLocation<-0.99) SmoothedLocation=-0.99; // verhindert, dass MathLog minuns unendlich wird
// FisherIndex
if(1-SmoothedLocation!=0) FishIndex=MathLog((1+SmoothedLocation)/(1-SmoothedLocation));
else Alert("Fisher129: Unauthorised state with bar number ",Bars-pos);
// Smoothing of FisherIndex
ExtMapBuffer1[pos]=IndexSmoothing*ExtMapBuffer1[pos+1]+(1.0-IndexSmoothing)*FishIndex;
if (Bars-pos<DrawStart)ExtMapBuffer1[pos]=0;
SmoothedFish=ExtMapBuffer1[pos];
if (SmoothedFish>0) // up trend
{
ExtMapBuffer2[pos]=SmoothedFish;
ExtMapBuffer3[pos]=0;
}
else // else down trend
{
ExtMapBuffer2[pos]=0;
ExtMapBuffer3[pos]=SmoothedFish;
}
if ((ExtMapBuffer2[pos] > 0) && (ExtMapBuffer3[pos+1] < 0.0))
{
if (pos == 1 && flagval1==0)
{
flagval1=1;
flagval2=0;
if (AlertON) Alert("Fisher Crossing zero line up\n Time=",TimeToStr(TimeCurrent(),TIME_DATE)," ",TimeHour(TimeCurrent()),":",TimeMinute(TimeCurrent()),"\n Symbol=",Symbol()," Period=",Period());
}
}
else if ((ExtMapBuffer2[pos] < 0) && (ExtMapBuffer3[pos+1] > 0.0))
{
if (pos == 1 && flagval2==0)
{
flagval2=1;
flagval1=0;
if (AlertON) Alert("Fisher Crossing zero line down\n Time=",TimeToStr(TimeCurrent(),TIME_DATE)," ",TimeHour(TimeCurrent()),":",TimeMinute(TimeCurrent()),"\n Symbol=",Symbol()," Period=",Period());
}
}
//----
return(0);
}
//+------------------------------------------------------------------+
Comments