Overview of Logic and Functionality
This script is a sophisticated technical analysis tool designed to identify market trends and generate potential trade signals. It operates by combining several advanced mathematical filters, price action patterns, and volatility measurements to "clean" the market noise and highlight significant movements. Instead of relying on a single indicator, it uses a multi-layered approach to confirm whether a trend is actually shifting or if the price is simply experiencing temporary fluctuations.
Core Analytical Components
To reach its conclusions, the script processes data through three primary engines:
1. Trend Identification (The Foundation) The tool uses two different methods to determine the "true" underlying direction of the market:
- Hodrick-Prescott Filter: A sophisticated mathematical method used to separate a time series into a trend component and a cyclical component. It is excellent for smoothing out short-term noise while preserving long-term movements.
- Extratrend Dynamics: An alternative method that calculates harmonic curves based on historical price data, helping to visualize the momentum of the market.
2. Volatility and Boundaries (Sigma Bands) The script calculates "Sigma Bands" (Standard Deviation levels). These act as dynamic boundaries around the trend lines. By identifying when prices deviate significantly from the mean (the 1st and 2nd standard deviations), the tool can help determine if a move is becoming overextended or if it is staying within a normal range of volatility.
3. Signal Confirmation (The Decision Makers) Before displaying a "Buy" or "Sell" arrow on the chart, the script cross-references three different types of market behavior:
- Heiken Ashi Reversals: It looks at modified candlestick patterns to detect changes in momentum. A signal is only considered if the current candle type contradicts the previous one.
- Demark Pivots: This identifies "pivot points"—local highs and lows where the price has stabilized relative to the surrounding bars.
- Tom Strignano Catapult: Based on specific trading techniques, this looks for "catapult" entries where price action breaks out of a defined historical level.
Signal Logic and Execution
The script follows a rigorous "voting" system to ensure high-quality signals:
- Conflict Resolution: If different methods provide conflicting information (e.g., one suggests a Buy while another suggests a Sell), the script applies a hierarchy of importance. For instance, certain technical patterns are given priority over others to decide which signal takes precedence.
- Majority Voting: In complex scenarios where multiple signals occur simultaneously, the tool calculates a "majority vote" to determine the final output.
- Trend Confirmation: Even if a primary signal is generated, the script performs a final check against the underlying trend curve (calculated by the HPF or Extratrend). A "Buy" signal is only displayed if it aligns with an upward trend, and a "Sell" signal is only shown during a downward trend.
User Experience Features
- Power Management: The script includes a "PowerSaver" mode that limits how often the complex calculations are run, ensuring it doesn't slow down your computer during high-activity periods.
- Alert System: It can be configured to trigger audio and visual alerts the moment a confirmed signal is detected, allowing for real-time monitoring without constantly staring at the charts.
- Visual Customization: Users can toggle the visibility of various bands, trend lines, and historical data points to tailor the visual display to their specific trading style.
// #4X 2010 Sigma Bands \¦/
// Knowledge of the ancients (ò ó)
//______________________o0o___(_)___o0o_____
//___¦Xard777¦_____¦_____¦_____¦_____¦_2010_¦
#define Sell -1
#define Buy 1
#define Any 10
#define Nothing 0
#define Down -1
#define Up 1
extern bool showTrueHistory = false;
extern int smooth = 0;
extern int BarShift = 0; // for visual back testing purposes. Automatic self-backtesting is completly different story...
// Extratrend settings
extern int ExtratrendBars = 240;
extern int HarmDivider = 20; // ExtratrendBars/HarmDivider = extratrendHarmonics. I found it easier to adjust the Extratrend
// Hodrick-Prescott Filter settings
extern bool useHPF = false; // if not, Extratrend will be used.
extern int switchToHPFon = 0; // time frame value to switch HPF on automatically. 0 = no switch.
extern int PastBars = 1000; //Number of PastBars to smooth 10 000 is much too much I guess..
extern int FiltPer = 20; //Equivalent to SMA period. It was 12 in the original code, I find 16 more accurate for my purposes. Or even 20...
extern bool EnableTradeSignals = false; // when enabled, arrows will be plot and alarm trigered if enabled
extern bool UseFractalTriggers = false; // this enables trade triger when fractal level is surpassed
extern bool UseHaReversals = true;
bool UseInternalHA = true; // it looks it works just right but let's leave it for some time to observe...
extern bool UseDemarkPivots = true;
extern bool UseTomCatapult = true;
extern bool UseTomTimeFrame = true; // Tom Strignano works on H1
extern bool ShowAllEntryPoints = false; // this is for testing purposes. If ShowAllEntryPoints = true, it will show all entry points unfiltered.
extern bool maskWithSigmaOnHPF = false;
extern bool EnableAlarm = false;
extern bool UseClosedCandle = false; // triggers alarm on current or closed bar.
// Demark pivots settings
extern int LevDP = 2; // Demar Pint Levels; 2 = central bar will be higher (lower) then 2 PastBars on the left side and 2 PastBars on the right one.
// standart deviation
extern bool Show1stBand = true; // show 1st deviation
extern bool Show2ndBand = true; // show 2nd deviation
extern double kstd = 1.83924;//1.63108;//1.5; // 1st deviation
extern double kstd2 = 2.45323;//2.2; // or 2.5... 2nd deviation
// PowerSaver
extern int PowerSaver = 15; // in seconds - to reduce CPU usage it will calculate every n seconds instead of every tick. 0 = realtime.
int UpArrowSymbol = 221;
int DownArrowSymbol = 222;
int result, prevResult;
int timeFrame, targetTimeFrame;
string timeFrameName;
string symbol;
datetime previousBarTime = 0;
// indicator stuff
#property indicator_chart_window
#property indicator_buffers 8 //10 - I can't have any more...
#property indicator_color1 Gold
#property indicator_color2 Blue
#property indicator_color3 Blue
#property indicator_color4 Gold
#property indicator_width1 1
#property indicator_width2 1
#property indicator_width3 2
#property indicator_width4 2
// internal Heiken Ashi stuff
int currentBarCount, previousBarCount;
double HaLow[], HaHigh[],HaOpen[],HaClose[];
// so called Fractals stuff
double FractalUpArrow[];
double FractalDownArrow[];
double FractalUpLevel[];
double FractalDownLevel[];
//---- base indicator buffers
double BuySignalBuffer[];
double SellSignalBuffer[];
double TrendUp[];
double TrendDown[];
// Hodrick-Prescott Filter stuff
double priceData[];
double LambdaBuf[7];
// Extratrend stuff
int extratrendHarmonics; // used to be external, now calculated internally
double FreqTOL =0.0002;//Tolerance of frequency calculation FreqTOL > 0.001 may not converge
#import "Extratrend.dll"
void calculateExtratrendDll(int bars, int harmonics, double freqTOL, double priceArray[], double& curve[]);
void prepareHPFDLL(int filtPer, double& lambdaBuf[]);
void HPFDLLnoLambda(int filtPer, int bars, int startIndex, double& lambdaBuf[], double prices[], double& curve[]);
void sigmaBands(int bars, double kstd1, double kstd2, double priceArray[], double& curveArray[], double& firstHigh[], double& firstLow[], double& secondHigh[], double& secondLow[]);
#import
// HPF and Extratrend common buffer and variables
double extrapolatedCurve[];
int barsRequired, nobs;
// standart deviation stuff
double sqh[],sql[],sqh2[],sql2[]; // main indicator bufers
double fh[], fl[], sh[], sl[]; // temp buffers
double firstBand, secondBand;
#property indicator_color5 Yellow//Orange
#property indicator_color6 Yellow//Orange
#property indicator_color7 Yellow//Orange
#property indicator_color8 Yellow//Orange
#property indicator_style5 1
#property indicator_style6 1
#property indicator_style7 1
#property indicator_style8 1
double nonRepaintingCurve[];
int currentCPUtime = 0, previousCPUtime = 0, powerSaverInterval;
//----------------------------------------------------------
int init()
{
// some input settings check up
if (PastBars < 20) PastBars = 20; // doesn't make sense to calculate it on shorter period. However, it works even on that short period!
if (FiltPer < 6) FiltPer = 6; // bellow 6 it's just a noise...
if (!EnableTradeSignals) EnableAlarm = false; // otherwise doesn't make any sense
result = Nothing; // signal trigger result. I don't remember why I made it global variable, but let's leave it if it works...
prevResult = Nothing;
if (kstd < 0.5) kstd = 0.5; // just to ensure no 0 or negative value passed
if (kstd2 <= kstd) kstd2 = 2*kstd; // as above
IndicatorBuffers(8);
//---- drawing settings
SetIndexStyle(0,DRAW_ARROW);
SetIndexStyle(1,DRAW_ARROW);
//SetIndexStyle(2,DRAW_LINE,STYLE_SOLID,2);
//SetIndexStyle(3,DRAW_LINE,STYLE_SOLID,2);
SetIndexStyle(2,DRAW_NONE);//change to DRAW_LINE for middle line
SetIndexStyle(3,DRAW_NONE);//change to DRAW_LINE for middle line
SetIndexArrow(0, UpArrowSymbol);
SetIndexArrow(1, DownArrowSymbol);
SetIndexBuffer(0,BuySignalBuffer);
SetIndexBuffer(1,SellSignalBuffer);
SetIndexBuffer(2,TrendUp);
SetIndexBuffer(3,TrendDown);
SetIndexShift(2,-BarShift); // I manipulate price array for the Hodrick-Prescott Filter. Base array gets shifted data so I have to shift the rest accordingly
SetIndexShift(3,-BarShift);
//---- name for DataWindow and indicator subwindow label
IndicatorShortName("Scalpel 3.5.5");
SetIndexLabel(0,"Scalpel 3.5.5 Bull Reversal");
SetIndexLabel(1,"Scalpel 3.5.5 Bear Reversal");
SetIndexLabel(2,"Scalpel 3.5.5 Uptrend");
SetIndexLabel(3,"Scalpel 3.5.5 Downtrend");
symbol = Symbol();
timeFrame = Period();
switch (timeFrame)
{
case(PERIOD_M1): timeFrameName = "M1"; break;
case(PERIOD_M5): timeFrameName = "M5"; break;
case(PERIOD_M15): timeFrameName = "M15"; break;
case(PERIOD_M30): timeFrameName = "M30"; break;
case(PERIOD_H1): timeFrameName = "H1"; break;
case(PERIOD_H4): timeFrameName = "H4"; break;
case(PERIOD_D1): timeFrameName = "D1"; break;
case(PERIOD_W1): timeFrameName = "W1"; break;
case(PERIOD_MN1): timeFrameName = "MN1"; break;
}
if (UseTomTimeFrame) targetTimeFrame = PERIOD_H1; else targetTimeFrame = timeFrame;
prepareHPFDLL(FiltPer, LambdaBuf); // ok. use or not, it's just several microseconds...
// this is just makeshift - I only check if no negative values or 0 meaning current timeframe...
// but I don;t check for the timeframe value validity. Anything greater than 0 will pass...
if (switchToHPFon <= 0) switchToHPFon = 0; // this way I don'ty have to check for the time frame value validity :-)
else {if (timeFrame <= switchToHPFon) useHPF = true;}
if (useHPF)
{
// Hodrick-Prescott Filter stuff
if (FiltPer <1) FiltPer = 1;
if(PastBars < 100) PastBars = 100;
//ArrayResize(priceData,PastBars);
//ArrayResize(extrapolatedCurve,PastBars);
barsRequired = PastBars;
nobs = PastBars;
}
else
{
// Extratrend stuff
if (ExtratrendBars < 20)
{
ExtratrendBars = 241; // tak na wszelki wypadek.
Print("Invalid ExtratrendBars settings. Reverting to default.");
}
if (HarmDivider < 1)
{
HarmDivider = 15; // tak na wszelki wypadek.
Print("Invalid HarmDivider settings. Reverting to default.");
}
extratrendHarmonics=ExtratrendBars/HarmDivider;
//ArrayResize(priceData,ExtratrendBars);
//ArrayResize(extrapolatedCurve,ExtratrendBars);
barsRequired = ExtratrendBars;
nobs = ExtratrendBars;
}
// array initializations
ArrayResize(priceData,nobs);
ArrayInitialize(priceData,NULL);
ArrayResize(extrapolatedCurve,nobs);
ArrayInitialize(extrapolatedCurve,EMPTY_VALUE);
ArrayResize(nonRepaintingCurve, nobs);
ArrayInitialize(nonRepaintingCurve,EMPTY_VALUE);
// no need to resize and initialize sigma bands buffers. They are not of that importance. BTW: they get initialized by default.
if (showTrueHistory)
{
// I need more bars to make real walkthrough
if (useHPF) barsRequired = PastBars*2;
else
{
barsRequired = ExtratrendBars*2;
}
}
barsRequired += BarShift;
// standard deviation
if(Show1stBand)
{
ArrayResize(fh,nobs);
ArrayResize(fl,nobs);
firstBand = kstd;
}
else firstBand = 0;
if(Show2ndBand)
{
ArrayResize(sh,nobs);
ArrayResize(sl,nobs);
secondBand = kstd2;
}
else secondBand = 0;
SetIndexBuffer(4, sqh);
SetIndexBuffer(5, sql);
SetIndexBuffer(6, sqh2);
SetIndexBuffer(7, sql2);
SetIndexShift(4,-BarShift); // I manipulate price array for the Hodrick-Prescott Filter. Base buffer gets shifted data so I have to shift the rest accordingly
SetIndexShift(5,-BarShift);
SetIndexShift(6,-BarShift);
SetIndexShift(7,-BarShift);
SetIndexLabel(4,"1st High");
SetIndexLabel(5,"1st Low");
SetIndexLabel(6,"2nd High");
SetIndexLabel(7,"2nd Low");
SetIndexStyle(4, DRAW_LINE);
SetIndexStyle(5, DRAW_LINE);
SetIndexStyle(6, DRAW_LINE);
SetIndexStyle(7, DRAW_LINE);
SetIndexEmptyValue(4, 0.0); // EMPTY_VALUE?
SetIndexEmptyValue(5, 0.0);
SetIndexEmptyValue(6, 0.0);
SetIndexEmptyValue(7, 0.0);
// Internal Heiken Ashi
previousBarCount = 0;
if (UseHaReversals)
{
ArrayResize(HaLow,Bars);
ArrayResize(HaHigh,Bars);
ArrayResize(HaOpen,Bars);
ArrayResize(HaClose,Bars);
ArrayInitialize(HaLow, EMPTY_VALUE);
ArrayInitialize(HaHigh, EMPTY_VALUE);
ArrayInitialize(HaOpen, EMPTY_VALUE);
ArrayInitialize(HaClose, EMPTY_VALUE);
ArraySetAsSeries(HaLow, true);
ArraySetAsSeries(HaHigh, true);
ArraySetAsSeries(HaOpen, true);
ArraySetAsSeries(HaClose, true);
}
// so called Fractal stuff
if (UseFractalTriggers)
{
ArrayResize(FractalUpArrow,Bars);
ArrayResize(FractalDownArrow,Bars);
ArrayResize(FractalUpLevel,Bars);
ArrayResize(FractalDownLevel,Bars);
ArrayInitialize(FractalUpArrow, EMPTY_VALUE);
ArrayInitialize(FractalDownArrow, EMPTY_VALUE);
ArrayInitialize(FractalUpLevel, EMPTY_VALUE);
ArrayInitialize(FractalDownLevel, EMPTY_VALUE);
ArraySetAsSeries(FractalUpArrow, true);
ArraySetAsSeries(FractalDownArrow, true);
ArraySetAsSeries(FractalUpLevel, true);
ArraySetAsSeries(FractalDownLevel, true);
}
// PowerSaver
if (PowerSaver <=0) PowerSaver = 0;
int timeFrameSeconds = timeFrame*60;
if (PowerSaver >timeFrameSeconds) PowerSaver = timeFrameSeconds; // it doesn't make sense to calcucate less frequently.
powerSaverInterval = PowerSaver*1000; // I need miliseconds
//Print("PowerSaver ", PowerSaver, " powerSaverInterval ", powerSaverInterval);
return(0);
}
//----------------------------------------------------------
int deinit()
{
return(Nothing);
}
//----------------------------------------------------------
// Tom Strignano Catapult entry
double TomCatapultHigh(int bar)
{
int targetBar;
if (UseTomTimeFrame) // check only round hour bars for signal conditions while current bar for passing threshold
{
datetime barTime = Time[bar];
// let's strip it from minutes and seconds easy way
barTime -= (TimeMinute(barTime)*60+TimeSeconds(barTime));
targetBar = iBarShift(symbol,targetTimeFrame,barTime, true);
}
else targetBar = bar;
if (iOpen(symbol,targetTimeFrame,targetBar+1) < iClose(symbol,targetTimeFrame,targetBar+1)&&
iOpen(symbol,targetTimeFrame,targetBar+2) > iClose(symbol,targetTimeFrame,targetBar+2)&&
iLow(symbol,targetTimeFrame,targetBar+1) > iLow(symbol,targetTimeFrame,targetBar+2) &&
//iClose(symbol,targetTimeFrame,bar) < iLow(symbol,targetTimeFrame,targetBar+2))
Close[bar] < iLow(symbol,targetTimeFrame,targetBar+2))
{
return (iHigh(symbol,targetTimeFrame,targetBar));
}
else return(Nothing);
}
//----------------------------------------------------------
double TomCatapultLow(int bar) // Long entry
{
int targetBar;
if (UseTomTimeFrame) // check only round hour bars for signal conditions while current bar for passing threshold
{
datetime barTime = Time[bar];
// let's strip it from minutes and seconds easy way
barTime -= (TimeMinute(barTime)*60+TimeSeconds(barTime));
targetBar = iBarShift(symbol,targetTimeFrame,barTime, true);
}
else targetBar = bar;
if (iOpen(symbol,targetTimeFrame,targetBar+1) > iClose(symbol,targetTimeFrame,targetBar+1)&&
iOpen(symbol,targetTimeFrame,targetBar+2) < iClose(symbol,targetTimeFrame,targetBar+2)&&
iHigh(symbol,targetTimeFrame,targetBar+1) < iHigh(symbol,targetTimeFrame,targetBar+2) &&
//iClose(symbol,targetTimeFrame,targetBar) > iHigh(symbol,targetTimeFrame,targetBar+2))
Close[bar] > iHigh(symbol,targetTimeFrame,targetBar+2))
{
return (iLow(symbol,targetTimeFrame,targetBar));
}
else return(Nothing);
}
//----------------------------------------------------------
// Demark Pivots calculation - I don't even know the original author. Kara Software Corp, GreenDog, whoever he/she is - contact me regarding your code usage
double DemHigh(int cnt, int sh)
{
if (High[cnt]>=High[cnt+sh] && High[cnt]>High[cnt-sh])
{
if (sh>1) return(DemHigh(cnt,sh-1));
else return(High[cnt]);
}
else return(Nothing);
}
//----------------------------------------------------------
double DemLow(int cnt, int sh)
{
if (Low[cnt]<=Low[cnt+sh] && Low[cnt]<Low[cnt-sh])
{
if (sh>1) return(DemLow(cnt,sh-1));
else return(Low[cnt]);
}
else return(Nothing);
}
//----------------------------------------------------------
int checkConfirmation(int bar) // check the trend direction. Very simple yet very accurate :-)
{
if (showTrueHistory)
{
if (bar == 0) bar = UseClosedCandle; // bar 0 is always open. If I check only closed candles, I should omit it;
else bar = 0; // the curve is already shifted. I need only the first value
}
if (useHPF) bar -= BarShift; // workaround...
if (extrapolatedCurve[bar] > extrapolatedCurve[bar+1]) return(Up);
else if (extrapolatedCurve[bar] < extrapolatedCurve[bar+1]) return(Down);
return (Nothing);
}
//----------------------------------------------------------
int checkConditions(int bar) // this will require some cleanup. Basically I check Heiken Ashi candles for reversal and Demark for pivots.
{
if (!EnableTradeSignals) return (Nothing); // not signal if no any needed
double Value3,Value4;
int HaCandle, prevHaCandle;
int confirmation;
int HaSignal = Nothing, DemSignal = Nothing, TomSignal = Nothing;
if (UseHaReversals)
{
if (UseInternalHA)
{
// check if the candle is up or down bar
Value3 = HaOpen[bar];
Value4 = HaClose[bar];
if (Value3 > Value4) // down bar
HaCandle = Sell;
else // up bar
HaCandle = Buy;
// now check the previous one
Value3 = HaOpen[bar+1];
Value4 = HaClose[bar+1];
if (Value3 > Value4)
prevHaCandle = Sell;
else
prevHaCandle = Buy;
}
else
{
// check if the candle is up or down bar
Value3 = iCustom(symbol, timeFrame, "Heiken Ashi", Red, White, Red, White, 2, bar);
Value4 = iCustom(symbol, timeFrame, "Heiken Ashi", Red, White, Red, White, 3, bar);
if (Value3 > Value4) // down bar
HaCandle = Sell;
else // up bar
HaCandle = Buy;
// now check the previous one
Value3 = iCustom(symbol, timeFrame, "Heiken Ashi", Red, White, Red, White, 2, bar+1);
Value4 = iCustom(symbol, timeFrame, "Heiken Ashi", Red, White, Red, White, 3, bar+1);
if (Value3 > Value4)
prevHaCandle = Sell;
else
prevHaCandle = Buy;
}
// if the two candles are opposite, we have a possible reversal
HaSignal = Nothing;
if (HaCandle == Buy && prevHaCandle == Sell) HaSignal = Buy;
if (HaCandle == Sell && prevHaCandle == Buy) HaSignal = Sell;
}
// Demark pivots
if (UseDemarkPivots)
{
if (DemHigh(bar,LevDP) > 0) DemSignal=Sell;
if (DemLow(bar,LevDP) > 0) DemSignal=Buy;
}
// Tom Strignano
if(UseTomCatapult)
{
if (TomCatapultHigh(bar) > 0) TomSignal=Sell;
if (TomCatapultLow(bar) > 0) TomSignal=Buy;
}
// Now I have to mix the signals
int finalSignal = Nothing;
// let's make it classic bit parade, I'll optimize it later on;
if (HaSignal == Nothing && DemSignal == Nothing && TomSignal == Nothing) return (Nothing); //000
if (HaSignal == Nothing && DemSignal == Nothing && TomSignal != Nothing) finalSignal = TomSignal; //001
if (HaSignal == Nothing && DemSignal != Nothing && TomSignal == Nothing) finalSignal = DemSignal; //010
if (HaSignal == Nothing && DemSignal != Nothing && TomSignal != Nothing) //011
{
// in case of conflict, Tom wins
finalSignal = TomSignal;
}
if (HaSignal != Nothing && DemSignal == Nothing && TomSignal == Nothing) finalSignal = HaSignal; //100
if (HaSignal != Nothing && DemSignal == Nothing && TomSignal != Nothing) //101
{
// in case of conflict, Tom wins
finalSignal = TomSignal;
}
if (HaSignal != Nothing && DemSignal != Nothing && TomSignal == Nothing) //110
{
// in case of conflict, Demark wins
finalSignal = DemSignal;
}
if (HaSignal != Nothing && DemSignal != Nothing && TomSignal != Nothing) //111
{
// now I check for majority vote
double sum = HaSignal + DemSignal + TomSignal;
sum /=3;
if (sum > 0) finalSignal = Buy;
if (sum < 0) finalSignal = Sell;
// alternate Tom wins
// finalSignal = TomSignal;
}
if (finalSignal !=Nothing)
{
if (!ShowAllEntryPoints) confirmation = checkConfirmation(bar); else confirmation = Any; // this is for testing purposes. If ShowAllEntryPoints = true, it will show all entry points unfiltered.
if ((finalSignal == Buy && (confirmation == Buy || confirmation == Any)) || (finalSignal == Sell && (confirmation == Sell || confirmation == Any))) return (finalSignal);
else return (Nothing);
}
return (Nothing);
}
//----------------------------------------------------------
int start()
{
currentCPUtime = GetTickCount();
if (PowerSaver <=0 || currentCPUtime >= previousCPUtime+powerSaverInterval)
{
//Print("previousCPUtime ", previousCPUtime, " currentCPUtime ", currentCPUtime);
if (Bars < barsRequired) return(Nothing);
int counted_bars=IndicatorCounted();
//---- check for possible errors
if(counted_bars<0) return(-1);
if(counted_bars>0) counted_bars--;
int i, currentBarResult = Nothing;
double currentBar, previousBar;
bool up = false;
// ....................................
// Heiken Ashi and Fractal level stuff
// at the moment it is calculated across all bars available. But It can be shortened to match the Extratrend/HPF.
if (UseHaReversals || UseFractalTriggers)
{
currentBarCount = Bars;
if (currentBarCount > previousBarCount)
{
if (ArraySize(HaLow) < currentBarCount)
{
if (UseHaReversals)
{
increaseArray(HaLow,currentBarCount,EMPTY_VALUE);
increaseArray(HaHigh,currentBarCount,EMPTY_VALUE);
increaseArray(HaOpen,currentBarCount,EMPTY_VALUE);
increaseArray(HaClose,currentBarCount,EMPTY_VALUE);
}
if (UseFractalTriggers)
{
increaseArray(FractalUpArrow,currentBarCount,EMPTY_VALUE);
increaseArray(FractalDownArrow,currentBarCount,EMPTY_VALUE);
increaseArray(FractalUpLevel,currentBarCount,EMPTY_VALUE);
increaseArray(FractalDownLevel,currentBarCount,EMPTY_VALUE);
}
}
previousBarCount = currentBarCount;
}
double haOpen, haHigh, haLow, haClose;
int pos;
int ExtCountedBars=IndicatorCounted();
// I need some more bars to recalculate if Fractals used
if (UseFractalTriggers)
{
if(ExtCountedBars<=2) pos=Bars-ExtCountedBars-3;
else
{
ExtCountedBars--;
pos=Bars-ExtCountedBars-1;
}
}
else
{
if (ExtCountedBars>0) ExtCountedBars--;
pos=Bars-ExtCountedBars-1;
}
if (pos > barsRequired) pos = barsRequired+1; // I don't need full history.
bool bFound;
double dCurrent;
while(pos>=0)
{
// Heiken Ashi
haOpen=(HaOpen[pos+1]+HaClose[pos+1])/2;
haClose=(Open[pos]+High[pos]+Low[pos]+Close[pos])/4;
haHigh=MathMax(High[pos], MathMax(haOpen, haClose));
haLow=MathMin(Low[pos], MathMin(haOpen, haClose));
if (haOpen<haClose)
{
HaLow[pos]=haLow;
HaHigh[pos]=haHigh;
}
else
{
HaLow[pos]=haHigh;
HaHigh[pos]=haLow;
}
HaOpen[pos]=haOpen;
HaClose[pos]=haClose;
// Fractals - again, I don't need full history - about 200 bars should be OK.
if (pos>=2 && pos < 200)
{
//----Fractals up
bFound=false;
dCurrent=High[pos];
if(dCurrent>High[pos+1] && dCurrent>High[pos+2] && dCurrent>High[pos-1] && dCurrent>High[pos-2])
{
bFound=true;
FractalUpArrow[pos]=dCurrent;
}
//----6 bars Fractal
if(!bFound && (Bars-pos-1)>=3)
{
if(dCurrent==High[pos+1] && dCurrent>High[pos+2] && dCurrent>High[pos+3] &&
dCurrent>High[pos-1] && dCurrent>High[pos-2])
{
bFound=true;
FractalUpArrow[pos]=dCurrent;
}
}
//----7 bars Fractal
if(!bFound && (Bars-pos-1)>=4)
{
if(dCurrent>=High[pos+1] && dCurrent==High[pos+2] && dCurrent>High[pos+3] && dCurrent>High[pos+4] &&
dCurrent>High[pos-1] && dCurrent>High[pos-2])
{
bFound=true;
FractalUpArrow[pos]=dCurrent;
}
}
//----8 bars Fractal
if(!bFound && (Bars-pos-1)>=5)
{
if(dCurrent>=High[pos+1] && dCurrent==High[pos+2] && dCurrent==High[pos+3] && dCurrent>High[pos+4] && dCurrent>High[pos+5] &&
dCurrent>High[pos-1] && dCurrent>High[pos-2])
{
bFound=true;
FractalUpArrow[pos]=dCurrent;
}
}
//----9 bars Fractal
if(!bFound && (Bars-pos-1)>=6)
{
if(dCurrent>=High[pos+1] && dCurrent==High[pos+2] && dCurrent>=High[pos+3] && dCurrent==High[pos+4] && dCurrent>High[pos+5] &&
dCurrent>High[pos+6] && dCurrent>High[pos-1] && dCurrent>High[pos-2])
{
bFound=true;
FractalUpArrow[pos]=dCurrent;
}
}
//----Fractals down
bFound=false;
dCurrent=Low[pos];
if(dCurrent<Low[pos+1] && dCurrent<Low[pos+2] && dCurrent<Low[pos-1] && dCurrent<Low[pos-2])
{
bFound=true;
FractalDownArrow[pos]=dCurrent;
}
//----6 bars Fractal
if(!bFound && (Bars-pos-1)>=3)
{
if(dCurrent==Low[pos+1] && dCurrent<Low[pos+2] && dCurrent<Low[pos+3] &&
dCurrent<Low[pos-1] && dCurrent<Low[pos-2])
{
bFound=true;
FractalDownArrow[pos]=dCurrent;
}
}
//----7 bars Fractal
if(!bFound && (Bars-pos-1)>=4)
{
if(dCurrent<=Low[pos+1] && dCurrent==Low[pos+2] && dCurrent<Low[pos+3] && dCurrent<Low[pos+4] &&
dCurrent<Low[pos-1] && dCurrent<Low[pos-2])
{
bFound=true;
FractalDownArrow[pos]=dCurrent;
}
}
//----8 bars Fractal
if(!bFound && (Bars-pos-1)>=5)
{
if(dCurrent<=Low[pos+1] && dCurrent==Low[pos+2] && dCurrent==Low[pos+3] && dCurrent<Low[pos+4] && dCurrent<Low[pos+5] &&
dCurrent<Low[pos-1] && dCurrent<Low[pos-2])
{
bFound=true;
FractalDownArrow[pos]=dCurrent;
}
}
//----9 bars Fractal
if(!bFound && (Bars-pos-1)>=6)
{
if(dCurrent<=Low[pos+1] && dCurrent==Low[pos+2] && dCurrent<=Low[pos+3] && dCurrent==Low[pos+4] && dCurrent<Low[pos+5] &&
dCurrent<Low[pos+6] && dCurrent<Low[pos-1] && dCurrent<Low[pos-2])
{
bFound=true;
FractalDownArrow[pos]=dCurrent;
}
}
// Levels
FractalUpLevel[pos] = FractalUpArrow[pos];
if(FractalUpLevel[pos] == EMPTY_VALUE) FractalUpLevel[pos] = FractalUpLevel[pos+1];
FractalDownLevel[pos] = FractalDownArrow[pos];
if(FractalDownLevel[pos] == EMPTY_VALUE) FractalDownLevel[pos] = FractalDownLevel[pos+1];
}
else
{
FractalUpLevel[pos] = FractalUpLevel[pos+1];
FractalDownLevel[pos] = FractalDownLevel[pos+1];
}
pos--;
}
}
// ....................................
if (showTrueHistory)
{
// now how many bars to process in the current loop
int barsToProcess = Bars-counted_bars;
if (barsToProcess > nobs) barsToProcess = nobs;
//for (i=BarShift;i<barsToProcess+BarShift;i++)
//Print ("barsToProcess ", barsToProcess-1);
//for (i=0;i<barsToProcess;i++)
//int loopcount = 0;
for (i=barsToProcess-1;i>=0;i--) // I need to go with the time, not backward...
{
//loopcount ++;
ArrayCopy(priceData, Close, 0, i+BarShift, nobs);
if (useHPF) HPFDLLnoLambda(FiltPer, nobs, 0, LambdaBuf, priceData, extrapolatedCurve);
else calculateExtratrendDll(ExtratrendBars, extratrendHarmonics, FreqTOL, priceData, extrapolatedCurve);
nonRepaintingCurve[i] = extrapolatedCurve[0]; // na razie tak... potem trzeba bedzie dorobic obejscie 0...
if (Show1stBand || Show2ndBand)
{
sigmaBands(nobs, firstBand, secondBand, priceData, extrapolatedCurve, fh, fl, sh, sl);
if(Show1stBand)
{
ArrayCopy(sqh, fh, i, 0, 1); // jeden, czy dwa?
ArrayCopy(sql, fl, i, 0, 1);
}
if(Show2ndBand)
{
ArrayCopy(sqh2, sh, i, 0, 1);
ArrayCopy(sql2, sl, i, 0, 1);
}
}
// end of standart deviation
// this is only for visual control
int currentBarIndex = 0;
if (i == 0) currentBarIndex = UseClosedCandle; // bar 0 is always open. If I check only closed candles, I should omit it;
currentBar = extrapolatedCurve[currentBarIndex];
previousBar = extrapolatedCurve[currentBarIndex+1];
if(currentBar >= previousBar) up = true; else up = false;
if (up)
{
TrendUp[i] = currentBar;
if(i > 0 && TrendUp[i+1] == EMPTY_VALUE) TrendDown[i] = currentBar; else TrendDown[i] = EMPTY_VALUE;
}
else
{
TrendDown[i] = currentBar;
if(i > 0 && TrendDown[i+1] == EMPTY_VALUE) TrendUp[i] = currentBar; else TrendUp[i] = EMPTY_VALUE;
}
if (i>= BarShift) // this gives me some pain... two methods of indexing...
{
result = checkConditions(i);
if (i==UseClosedCandle) currentBarResult = result; // I save it here for alarm usage...
if (result == Buy) BuySignalBuffer[i] = Low[i]; else BuySignalBuffer[i] = EMPTY_VALUE;
if (result == Sell) SellSignalBuffer[i] = High[i];else SellSignalBuffer[i] = EMPTY_VALUE;
}
}
//Print ("bars caulculated ",loopcount);
}
else
{
ArrayCopy(priceData, Close, 0, BarShift, nobs);
if (useHPF) HPFDLLnoLambda(FiltPer, nobs, 0, LambdaBuf, priceData, extrapolatedCurve);
else calculateExtratrendDll(ExtratrendBars, extratrendHarmonics, FreqTOL, priceData, extrapolatedCurve);
// standart deviation
if (Show1stBand || Show2ndBand)
{
sigmaBands(nobs, firstBand, secondBand, priceData, extrapolatedCurve, fh, fl, sh, sl);
if(Show1stBand)
{
ArrayCopy(sqh, fh, 0, 0, nobs);
ArrayCopy(sql, fl, 0, 0, nobs);
}
if(Show2ndBand)
{
ArrayCopy(sqh2, sh, 0, 0, nobs);
ArrayCopy(sql2, sl, 0, 0, nobs);
}
}
// end of standart deviation
for(i=0; i<nobs; i++) // frankly, it should be walked other way, with time, not against...
{
// this is only for visual control only
currentBar = extrapolatedCurve[i];
previousBar = extrapolatedCurve[i+1];
if(currentBar >= previousBar) up = true; else up = false;
if (up)
{
TrendUp[i] = currentBar;
if(i > 0 && TrendUp[i-1] == EMPTY_VALUE) TrendDown[i] = currentBar; else TrendDown[i] = EMPTY_VALUE;
}
else
{
TrendDown[i] = currentBar;
if(i > 0 && TrendDown[i-1] == EMPTY_VALUE) TrendUp[i] = currentBar; else TrendUp[i] = EMPTY_VALUE;
}
result = checkConditions(i+BarShift);
if (i==UseClosedCandle) currentBarResult = result; // I save it here for alarm usage...
if (result == Buy) BuySignalBuffer[i+BarShift] = Low[i+BarShift]; else BuySignalBuffer[i+BarShift] = EMPTY_VALUE;
if (result == Sell) SellSignalBuffer[i+BarShift] = High[i+BarShift];else SellSignalBuffer[i+BarShift] = EMPTY_VALUE;
}
}
//result = currentBarResult; // recalling saved value
// alarm
if (currentBarResult != Nothing && currentBarResult != prevResult)
{
if (EnableAlarm)
{
string altertText;
if (currentBarResult == Buy) altertText = "Buy ";
if (currentBarResult == Sell) altertText = "Sell ";
altertText = StringConcatenate("Scalpel: ", altertText, Symbol (), " ",timeFrameName);
Alert(altertText);
Print("-----------------------------------");
altertText = ">>>>>>> " + altertText;
Print(altertText);
Print("-----------------------------------");
}
}
prevResult = currentBarResult;
previousCPUtime = GetTickCount();
}
//---- end of main loop
return(0);
}
//----------------------------------------------------------
bool increaseArray(double& array[], int targetSize, double blankValue)
{
int currentSize = ArraySize(array);
if (targetSize <= currentSize) return (false);
if (blankValue != NULL || blankValue != EMPTY_VALUE) blankValue = EMPTY_VALUE;
double tempArray[];
ArrayResize(tempArray, currentSize);
bool reversedOrder = ArrayGetAsSeries(array);
if (reversedOrder) ArraySetAsSeries(array, false);
ArrayCopy(tempArray, array, 0, 0, WHOLE_ARRAY);
ArrayResize(array, targetSize);
ArrayInitialize(array, blankValue);
ArrayCopy(array, tempArray, 0, 0, WHOLE_ARRAY);
if (reversedOrder) ArraySetAsSeries(array, true);
return(true);
}
Comments