//+------------------------------------------------------------------+ //| HarmonicPatternFinderV2.mq5 | //| Copyright 2016, André S. Enger. | //| andre_enger@hotmail.com | //| Contribs | //| David Gadelha | //| dgadelha@gmail.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2016, Andre S. Enger." #property link "andre_enger@hotmail.com" #property version "2.0" #property description "Indicator to display existent and emerging harmonic chart patterns." #property indicator_chart_window #property indicator_buffers 2 #property indicator_plots 1 #property indicator_label1 "Zig Zag" #property indicator_type1 DRAW_ZIGZAG #property indicator_color1 clrNONE #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- Describes patterns struct PATTERN_DESCRIPTOR { double ab2xa_min; double ab2xa_max; double bc2ab_min; double bc2ab_max; double cd2bc_min; double cd2bc_max; double ad2xa_min; double ad2xa_max; double cd2xc_min; double cd2xc_max; double xc2xa_min; double xc2xa_max; double cd2ab_min; double cd2ab_max; }; //--- Identifies drawn patterns struct PATTERN_INSTANCE { int patternIndex; int patternBufferIndex; bool bullish; bool overlapping; datetime XDateTime; datetime ADateTime; datetime BDateTime; datetime CDateTime; datetime DDateTime; double X; double A; double B; double C; double D; double PRZ; }; //--- Number keys of patterns enum PATTERN_INDEX { TRENDLIKE1_ABCD=0, TRENDLIKE2_ABCD, PERFECT_ABCD, IDEAL1_ABCD, IDEAL2_ABCD, RANGELIKE_ABCD, ALT127_TRENDLIKE1_ABCD, ALT127_TRENDLIKE2_ABCD, ALT127_PERFECT_ABCD, ALT127_IDEAL1_ABCD, ALT127_IDEAL2_ABCD, ALT127_RANGELIKE_ABCD, REC_TRENDLIKE1_ABCD, REC_TRENDLIKE2_ABCD, REC_PERFECT_ABCD, REC_IDEAL1_ABCD, REC_IDEAL2_ABCD, REC_RANGELIKE_ABCD, GARTLEY, BAT, ALTBAT, FIVEO, BUTTERFLY, CRAB, DEEPCRAB, THREEDRIVES, CYPHER, SHARK, NENSTAR, BLACKSWAN, WHITESWAN, ONE2ONE, NEWCYPHER, NAVARRO200, LEONARDO, KANE, GARFLY, MAXBAT, MAXGARTLEY, MAXBUTTERFLY, GARTLEY113, BUTTERFLY113, ANTI_GARTLEY, ANTI_BAT, ANTI_ALTBAT, ANTI_FIVEO, ANTI_BUTTERFLY, ANTI_CRAB, ANTI_DEEPCRAB, ANTI_THREEDRIVES, ANTI_CYPHER, ANTI_SHARK, ANTI_NENSTAR, ANTI_BLACKSWAN, ANTI_WHITESWAN, ANTI_ONE2ONE, ANTI_NEWCYPHER, ANTI_NAVARRO200, ANTI_LEONARDO, ANTI_KANE, ANTI_GARFLY, ANTI_MAXBAT, ANTI_MAXGARTLEY, ANTI_MAXBUTTERFLY, ANTI_GARTLEY113, ANTI_BUTTERFLY113, }; //--- ZigZag selection enum ZIGZAGTYPE { FASTZZ,//Fast ZZ ALEXSTAL,//Alexstal ZZ SWINGCHART //Swing ZZ }; //--- Constants and macros #define SIZE_PATTERN_BUFFER 10 #define NUM_PATTERNS 66 #define NON_EXISTENT_DATETIME D'19.07.1980 12:30:27' const string _identifier="HPF"; //--- User Inputs input string indicatorSettings="-=Indicator Settings=-"; //-=Indicator Settings=- input ZIGZAGTYPE zztype=ALEXSTAL; //ZigZag type input int zzperiod=12; //AlexStal ZZ period input int zzamplitude=10; //AlexStal ZZ amplitude input int zzminmotion=0; //AlexStal ZZ minimum motion input int SwingSize=200; //Fast ZZ sensitivity in points input int BarsAnalyzed=200; //Max. bars per pattern input int History=1000; //Max. history bars to process input int MaxSamePoints=2; //Max. shared points per pattern input double SlackRange=0.01; //Max. slack for fib ratios (range) input double SlackUnary=0.1; //Max. slack for fib ratios (unary) input string indicatorColors="-=Display Settings=-"; //-=Display Settings=- input color ClrBull=clrLightSkyBlue; //Color for bullish patterns (5 points) input color ClrBear=clrSalmon; //Color for bearish patterns (5 points) input color ClrBull4P=clrBlue; //Color for bullish patterns (4 points) input color ClrBear4P=clrRed; //Color for bearish patterns (4 points) input color ClrBullProjection=clrSeaGreen; //Color for projected bullish patterns input color ClrBearProjection=clrDarkOrange; //Color for projected bearish patterns input color ClrRatio=clrGray; //Color for patterns ratios input bool Fill_Patterns=false; //Fill 5 point patterns found input bool Show_descriptions=true; //Show pattern descriptions input bool Show_PRZ=true; //Show potential reversal zone (PRZ) input bool EmergingPatterns=true; //Show emerging patterns input bool OneAheadProjection=false; //Show "one-ahead" projections input bool showPatternNames=false; //Show comment box input int l_width=2; //Pattern line width (5 points) input int l_width4p=2; //Patterns line width (4 points) input int l_width_proj=2; //Emerging patterns line width input int Font_size=08; //Font size input ENUM_LINE_STYLE Style_5P=STYLE_SOLID; //Style for 5 points patterns input ENUM_LINE_STYLE Style_4P=STYLE_DASH; //Style for 4 points patterns input ENUM_LINE_STYLE Style_Proj=STYLE_DASHDOTDOT; //Style for projections input ENUM_LINE_STYLE Style_Ratio=STYLE_DOT; //Style for ratio lines input ENUM_LINE_STYLE Style_PRZ=STYLE_DASHDOT; //Style for PRZ input string indicatorPatternsQuick="-=Patterns Quick=-"; //-=Patterns Quick=- input bool Show_abcd=true; //Display AB=CD patterns input bool Show_alt127_abcd=true; //Display 1.27 AB=CD patterns input bool Show_rec_abcd=true; //Display Rec. AB=CD patterns input bool Show_patterns=true; //Display normal 5-point patterns input bool Show_antipatterns=false; //Display anti 5-point patterns input string indicatorPatternsIndividual="-=Patterns Individual=-"; //-=Patterns Individual=- input bool Show_trendlike1_abcd=true; //Display Trendlike AB=CD #1 input bool Show_trendlike2_abcd=true; //Display Trendlike AB=CD #2 input bool Show_perfect_abcd=true; //Display Perfect AB=CD input bool Show_ideal1_abcd=true; //Display Ideal AB=CD #1 input bool Show_ideal2_abcd=true; //Display Ideal AB=CD #2 input bool Show_rangelike_abcd=true; //Display Rangelike AB=CD input bool Show_alt127_trendlike1_abcd=true; //Display Trendlike 1.27 AB=CD #1 input bool Show_alt127_trendlike2_abcd=true; //Display Trendlike 1.27 AB=CD #2 input bool Show_alt127_perfect_abcd=true; //Display Perfect 1.27 AB=CD input bool Show_alt127_ideal1_abcd=true; //Display Ideal 1.27 AB=CD #1 input bool Show_alt127_ideal2_abcd=true; //Display Ideal 1.27 AB=CD #2 input bool Show_alt127_rangelike_abcd=true; //Display Rangelike 1.27 AB=CD input bool Show_rec_trendlike1_abcd=true; //Display Rec. Trendlike AB=CD #1 input bool Show_rec_trendlike2_abcd=true; //Display Rec. Trendlike AB=CD #2 input bool Show_rec_perfect_abcd=true; //Display Rec. Perfect AB=CD input bool Show_rec_ideal1_abcd=true; //Display Rec. Ideal AB=CD #1 input bool Show_rec_ideal2_abcd=true; //Display Rec. Ideal AB=CD #2 input bool Show_rec_rangelike_abcd=true; //Display Rec. Rangelike AB=CD input bool Show_gartley=true; //Display Gartley input bool Show_bat=true; //Display Bat input bool Show_altbat=true; //Display Alt. Bat input bool Show_fiveo=true; //Display 5-0 input bool Show_butterfly=true; //Display Butterfly input bool Show_crab=true; //Display Crab input bool Show_deepcrab=true; //Display Deepcrab input bool Show_threedrives=true; //Display Three Drives input bool Show_cypher=true; //Display Cypher input bool Show_shark=true; //Display Shark input bool Show_nenstar=true; //Display Nen Star input bool Show_blackswan=true; //Display Black Swan input bool Show_whiteswan=true; //Display White Swan input bool Show_one2one=true; //Display One2One input bool Show_newCypher=true; //Display New Cypher input bool Show_navarro200=true; //Display Navarro 200 input bool Show_leonardo=true; //Display Leonardo input bool Show_kane=true; //Display Kane input bool Show_garfly=true; //Display Garfly input bool Show_maxbat=true; //Display Max. Bat input bool Show_maxgartley=true; //Display Max. Gartley input bool Show_maxbutterfly=true; //Display Max. Butterfly input bool Show_gartley113=true; //Display Gartley 113 input bool Show_butterfly113=true; //Display Butterfly 113 input bool Show_antigartley=true; //Display Anti Gartley input bool Show_antibat=true; //Display Anti Bat input bool Show_antialtbat=true; //Display Anti Alt. Bat input bool Show_antifiveo=true; //Display Anti 5-0 input bool Show_antibutterfly=true; //Display Anti Butterfly input bool Show_anticrab=true; //Display Anti Crab input bool Show_antideepcrab=true; //Display Anti Deepcrab input bool Show_antithreedrives=true; //Display Anti Three Drives input bool Show_anticypher=true; //Display Anti Cypher input bool Show_antishark=true; //Display Anti Shark input bool Show_antinenstar=true; //Display Anti Nen Star input bool Show_antiblackswan=true; //Display Anti Black Swan input bool Show_antiwhiteswan=true; //Display Anti White Swan input bool Show_antione2one=true; //Display Anti One2One input bool Show_antinewCypher=true; //Display Anti New Cypher input bool Show_antinavarro200=true; //Display Anti Navarro 200 input bool Show_antileonardo=true; //Display Anti Leonardo input bool Show_antikane=true; //Display Anti Kane input bool Show_antigarfly=true; //Display Anti Garfly input bool Show_antimaxbat=true; //Display Anti Max. Bat input bool Show_antimaxgartley=true; //Display Anti Max. Gartley input bool Show_antimaxbutterfly=true; //Display Anti Max. Butterfly input bool Show_antigartley113=true; //Display Anti Gartley 113 input bool Show_antibutterfly113=true; //Display Anti Butterfly 113 //--- Indicator buffer arrays double peaks[],troughs[]; //--- Globals bool _lastDirection; double _lastPeakValue; double _lastTroughValue; int _lastPeak; int _lastTrough; int _patternInstanceCounter; int _maxPatternInstances; int _projectionInstanceCounter; int _maxProjectionInstances; int _drawnProjectionInstanceCounter; int _maxDrawnProjectionInstances; int _zzHandle; PATTERN_INSTANCE _patternInstances[]; PATTERN_INSTANCE _projectionInstances[]; PATTERN_INSTANCE _drawnProjectionInstances[]; PATTERN_DESCRIPTOR _patterns[]; string _patternNames[]; int _patternCounter[]; datetime _patternX[][SIZE_PATTERN_BUFFER]; datetime _patternA[][SIZE_PATTERN_BUFFER]; datetime _patternB[][SIZE_PATTERN_BUFFER]; datetime _patternC[][SIZE_PATTERN_BUFFER]; datetime _patternD[][SIZE_PATTERN_BUFFER]; string com1="",com2="",com3="",com4="",com5="",com6="",com7="",com8="",com9=""; int _timeOfInit; //+------------------------------------------------------------------+ //| Indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping SetIndexBuffer(0,peaks,INDICATOR_DATA); SetIndexBuffer(1,troughs,INDICATOR_DATA); IndicatorSetInteger(INDICATOR_DIGITS,Digits()); PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0.0); //--- memory switch(zztype) { case FASTZZ: _zzHandle=iCustom(NULL,0,"Downloads\\fastzz",SwingSize); break; case ALEXSTAL: _zzHandle=iCustom(NULL,0,"Downloads\\alexstal_zigzagprof",zzperiod,zzamplitude,zzminmotion,true); break; case SWINGCHART: default: _zzHandle=iCustom(NULL,0,"Downloads\\swingchart"); } if(_zzHandle==INVALID_HANDLE) { printf("Error obtaining handle"); return(INIT_FAILED); } MathSrand(GetTickCount()); _timeOfInit=MathRand(); for(int i=ObjectsTotal(0,0,-1)-1; i>=0; i--) { string name=ObjectName(0,i,0,-1); if(StringFind(name,"U "+_identifier)!=-1 || StringFind(name,"D "+_identifier)!=-1) ObjectDelete(0,name); } return PopulatePatterns(); } //+------------------------------------------------------------------+ //| Indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { OnReinit(); Comment(""); ArrayFree(_patterns); ArrayFree(_patternInstances); ArrayFree(_projectionInstances); ArrayFree(_drawnProjectionInstances); ArrayFree(_patternNames); ArrayFree(_patternCounter); ArrayFree(_patternX); ArrayFree(_patternA); ArrayFree(_patternB); ArrayFree(_patternC); ArrayFree(_patternD); } //+------------------------------------------------------------------+ //| Indicator reinitialization function | //+------------------------------------------------------------------+ void OnReinit() { //---- _lastPeak=0; _lastTrough=0; _lastPeakValue=0; _lastTroughValue=0; _patternInstanceCounter=0; _drawnProjectionInstanceCounter=0; ArrayFill(_patternCounter,0,NUM_PATTERNS,0); for(int i=0; i=0; i--) { string name=ObjectName(0,i,0,-1); if(StringFind(name,"U "+_identifier+StringFormat("%x",_timeOfInit))!=-1 || StringFind(name,"D "+_identifier+StringFormat("%x",_timeOfInit))!=-1) ObjectDelete(0,name); } } //+------------------------------------------------------------------+ //| Indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { //--- int start=0; if(prev_calculated>rates_total || prev_calculated<=0) OnReinit(); else start=prev_calculated-1; start=MathMax(1,start); //--- copy data if(BarsCalculated(_zzHandle)lastPeak; if(lastTrough==lastPeak) { int zzDirection=ZigZagDirection(lastPeak); if(zzDirection==0) continue; else if(zzDirection==-1) endsInTrough=true; else if(zzDirection==1) endsInTrough=false; } //--- Remove old projections UndisplayProjections(); //--- Remove old patterns (on ZZ swing continuation) or store them (on new ZZ direction) if(_lastDirection==endsInTrough && !(_lastPeakX)) break; if((XIndex!=AIndex && IsProperValue(troughs[AIndex]) && IsProperValue(peaks[AIndex])) && ((startsInTrough && ZigZagDirection(AIndex)==1 && troughs[AIndex]X))) break; //--- Only check increasing (decreasing) A's double A=startsInTrough ? peaks[AIndex]: troughs[AIndex]; if(!IsProperValue(A) || (startsInTrough && AextremeA)) continue; extremeA=A; //--- For ratios double XA=MathAbs(A-X); if(XA==0) continue; //--- Find B index double extremeB=startsInTrough ? DBL_MAX : DBL_MIN; //--- Skip first BIndex if vertical zz at X and both X and A is on it int bSkip=0; if(XIndex==AIndex) bSkip=1; for(int BIndex=AIndex+bSkip; BIndex<=bar && !IsStopped(); BIndex++) { //--- Ensure that A is the extremum on [A, B], i.e. there is no higher high (lower low) int extremeIndexAB=AIndex==BIndex ? BIndex : BIndex-1; if((!startsInTrough && IsProperValue(troughs[extremeIndexAB]) && troughs[extremeIndexAB]A)) break; if((AIndex!=BIndex && IsProperValue(troughs[BIndex]) && IsProperValue(peaks[BIndex])) && ((!startsInTrough && ZigZagDirection(BIndex)==1 && troughs[BIndex]A))) break; //--- Only check decreasing (increasing) B's double B=startsInTrough ? troughs[BIndex]: peaks[BIndex]; if(!IsProperValue(B) || (startsInTrough && B>extremeB) || (!startsInTrough && Bpattern.ab2xa_max+ab2xaSlack; if(ab2xaCutoff) break; //--- Find C double extremeC=startsInTrough ? DBL_MIN : DBL_MAX; //--- Skip first CIndex if vertical zz at B and both A and B is on it int cSkip=0; if(AIndex==BIndex) cSkip = 1; for(int CIndex=BIndex+cSkip; CIndex<=bar && !IsStopped(); CIndex++) { //--- Ensure that B is the extremum on [B, C], i.e. there is no lower low (higher high) int extremeIndexBC=BIndex==CIndex ? CIndex : CIndex-1; if((startsInTrough && IsProperValue(troughs[extremeIndexBC]) && troughs[extremeIndexBC]B)) break; if((BIndex!=CIndex && IsProperValue(troughs[CIndex]) && IsProperValue(peaks[CIndex])) && ((startsInTrough && ZigZagDirection(CIndex)==1 && troughs[CIndex]B))) break; //--- Only check increasing (decreasing) C's double C=startsInTrough ? peaks[CIndex]: troughs[CIndex]; if(!IsProperValue(C)) continue; if((startsInTrough && CextremeC)) continue; extremeC=C; //--- Second check for vertical ZZ at BC leg and C comes before B if(BIndex==CIndex) { int zzDirection=ZigZagDirection(BIndex); if(zzDirection==0) continue; else if(zzDirection==-1 && startsInTrough) continue; else if(zzDirection==1 && !startsInTrough) continue; } //--- Ratios double BC=MathAbs(C-B); double XC=MathAbs(X-C); if(BC==0) continue; if(XC==0) continue; double bc2abRatio=BC/AB; double xc2xaRatio=XC/XA; //--- Analytical continue: C not far enough by short 'bc2abRatio' or 'xc2xaRatio' bool bc2abContinue=bc2abConstraint; bool xc2xaContinue=xc2xaConstraint; bc2abContinue&=bc2abRatiopattern.bc2ab_max+bc2abSlack; xc2xaCutoff&=xc2xaRatio>pattern.xc2xa_max+xc2xaSlack; if(bc2abCutoff || xc2xaCutoff) break; //--- Check if C is the extreme until end-of-search, only then it should be used to project bool lastExtremeC=true; for(int i=CIndex+1; i<=bar; i++) { if((startsInTrough && IsProperValue(peaks[i]) && peaks[i]>C) || (!startsInTrough && IsProperValue(troughs[i]) && troughs[i]C)) break; if((CIndex!=DIndex && IsProperValue(troughs[DIndex]) && IsProperValue(peaks[DIndex])) && ((!startsInTrough && ZigZagDirection(DIndex)==1 && troughs[DIndex]C))) break; //--- If CIndex is last, use imaginary D for projections bool imaginaryD=((startsInTrough && CIndex==lastPeak && lastTrough<=lastPeak) || (!startsInTrough && CIndex==lastTrough && lastPeak<=lastTrough)); if(imaginaryD && lastPeak==lastTrough) imaginaryD &=(startsInTrough && ZigZagDirection(lastPeak)==1) || (!startsInTrough && ZigZagDirection(lastPeak)==-1); //--- Only check decreasing (increasing) D's double D=startsInTrough ? troughs[DIndex]: peaks[DIndex]; if(!imaginaryD && (!IsProperValue(D) || (startsInTrough && D>extremeD) || (!startsInTrough && DD) || (startsInTrough && IsProperValue(troughs[i]) && troughs[i]nearD) || (!startsInTrough && DnearD) || (!startsInTrough && farDfarD)) break; //--- Match else { //--- Invalidate if overlapping if(Overlaps(patternIndex,time[XIndex],time[AIndex],time[BIndex],time[CIndex],time[DIndex])) continue; //--- 4-point if(Is4PointPattern(patternIndex)) { DisplayPattern(patternIndex,startsInTrough,time[AIndex],A,time[BIndex],B,time[CIndex],C,time[DIndex],D); if(activeSwing) { StorePattern(patternIndex,startsInTrough,0,time[AIndex],time[BIndex],time[CIndex],time[DIndex]); if(Show_PRZ) DisplayPRZ(patternIndex,startsInTrough,time[AIndex],A,time[BIndex],time[CIndex],C,time[DIndex],D,farD); } else StoreOverlaps(patternIndex,0,time[AIndex],time[BIndex],time[CIndex],time[DIndex]); } //--- 5-point else { DisplayPattern(patternIndex,startsInTrough,time[XIndex],X,time[AIndex],A,time[BIndex],B,time[CIndex],C,time[DIndex],D); if(activeSwing) { StorePattern(patternIndex,startsInTrough,time[XIndex],time[AIndex],time[BIndex],time[CIndex],time[DIndex]); if(Show_PRZ) DisplayPRZ(patternIndex,startsInTrough,time[XIndex],X,time[AIndex],A,time[BIndex],time[CIndex],C,time[DIndex],D,farD); } else StoreOverlaps(patternIndex,time[XIndex],time[AIndex],time[BIndex],time[CIndex],time[DIndex]); } } } //--- End DIndex-loop } //--- End CIndex-loop } //--- End BIndex-loop } //--- End AIndex-loop //--- Run same XIndex twice if ZigZag is vertical if(xVerticalZZ) { if(xFirstRun) { XIndex--; xFirstRun=false; } else xFirstRun=true; } } //--- End XIndex-loop //--- Sort projections for(int i=1; i<_projectionInstanceCounter; i++) { _projectionInstances[i].overlapping=false; int j=i; while(j>0 && _projectionInstances[j-1].D>_projectionInstances[j].D) { PATTERN_INSTANCE tmp=_projectionInstances[j]; _projectionInstances[j]=_projectionInstances[j-1]; _projectionInstances[j-1]=tmp; j--; } } _projectionInstances[0].overlapping=false; //--- Display projections bool forward=true; int i=0; while(_projectionInstanceCounter!=0) { bool bullish=_projectionInstances[i].bullish; if((forward && !bullish) || (!forward && bullish)) { datetime XDateTime=_projectionInstances[i].XDateTime; datetime ADateTime=_projectionInstances[i].ADateTime; datetime BDateTime=_projectionInstances[i].BDateTime; datetime CDateTime=_projectionInstances[i].CDateTime; datetime DDateTime=_projectionInstances[i].DDateTime; double X=_projectionInstances[i].X; double A=_projectionInstances[i].A; double B=_projectionInstances[i].B; double C=_projectionInstances[i].C; double D=_projectionInstances[i].D; double farD=_projectionInstances[i].PRZ; //--- Invalidate projection if overlapping other patterns if(Overlaps(patternIndex,XDateTime,ADateTime,BDateTime,CDateTime,NON_EXISTENT_DATETIME)) _projectionInstances[i].overlapping=true; //--- Invalidate projection if overlapping other projections int j=i; while(true) { //--- Loop condition if(forward) { if(j==0) break; else j--; } else { if(j==_projectionInstanceCounter-1) break; else j++; } //--- Overlap check if(!_projectionInstances[j].overlapping && _projectionInstances[j].bullish==bullish) { datetime XDateTimeActive=_projectionInstances[j].XDateTime; datetime ADateTimeActive=_projectionInstances[j].ADateTime; datetime BDateTimeActive=_projectionInstances[j].BDateTime; datetime CDateTimeActive=_projectionInstances[j].CDateTime; datetime DDateTimeActive=_projectionInstances[j].DDateTime; int numMatches=0; if(!Is4PointPattern(patternIndex) && XDateTime==XDateTimeActive) numMatches++; if(ADateTime==ADateTimeActive) numMatches++; if(BDateTime==BDateTimeActive) numMatches++; if(CDateTime==CDateTimeActive) numMatches++; //if(DDateTime==DDateTimeActive) numMatches++; if(numMatches>MaxSamePoints) { _projectionInstances[i].overlapping=true; break; } } } //--- Display projection if(!_projectionInstances[i].overlapping) { if(Is4PointPattern(patternIndex)) DisplayProjection(patternIndex,bullish,ADateTime,A,BDateTime,B,CDateTime,C,DDateTime,D); else DisplayProjection(patternIndex,bullish,XDateTime,X,ADateTime,A,BDateTime,B,CDateTime,C,DDateTime,D); _drawnProjectionInstances[_drawnProjectionInstanceCounter]=_projectionInstances[i]; _drawnProjectionInstanceCounter++; if(_drawnProjectionInstanceCounter>=_maxDrawnProjectionInstances) { _maxDrawnProjectionInstances*=2; if(ArrayResize(_drawnProjectionInstances,_maxDrawnProjectionInstances)<_maxDrawnProjectionInstances) printf("Error allocating array"); } } } //--- Loop condition if(forward) { if(i==_projectionInstanceCounter-1) forward=false; else i++; } else { if(i==0) break; else i--; } } } } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ //| Helper method determines 4 point patterns | //+------------------------------------------------------------------+ bool Is4PointPattern(int patternIndex) { if(patternIndex == TRENDLIKE1_ABCD) return true; if(patternIndex == TRENDLIKE2_ABCD) return true; if(patternIndex == PERFECT_ABCD) return true; if(patternIndex == IDEAL1_ABCD) return true; if(patternIndex == IDEAL2_ABCD) return true; if(patternIndex == RANGELIKE_ABCD) return true; if(patternIndex == ALT127_TRENDLIKE1_ABCD) return true; if(patternIndex == ALT127_TRENDLIKE2_ABCD) return true; if(patternIndex == ALT127_PERFECT_ABCD) return true; if(patternIndex == ALT127_IDEAL1_ABCD) return true; if(patternIndex == ALT127_IDEAL2_ABCD) return true; if(patternIndex == ALT127_RANGELIKE_ABCD) return true; if(patternIndex == REC_TRENDLIKE1_ABCD) return true; if(patternIndex == REC_TRENDLIKE2_ABCD) return true; if(patternIndex == REC_PERFECT_ABCD) return true; if(patternIndex == REC_IDEAL1_ABCD) return true; if(patternIndex == REC_IDEAL2_ABCD) return true; if(patternIndex == REC_RANGELIKE_ABCD) return true; return false; } //+------------------------------------------------------------------+ //| Helper method finds ZigZag direction in before index | //+------------------------------------------------------------------+ int ZigZagDirection(int index) { int lastPeakBefore=FirstNonZeroFrom(index-1,peaks); int lastTroughBefore=FirstNonZeroFrom(index-1,troughs); while(lastPeakBefore==lastTroughBefore) { lastPeakBefore=FirstNonZeroFrom(lastPeakBefore-1,peaks); lastTroughBefore=FirstNonZeroFrom(lastTroughBefore-1,troughs); if(lastPeakBefore==-1 || lastTroughBefore==-1) return 0; } if(lastPeakBefore==-1 || lastTroughBefore==-1) return 0; else if(lastPeakBefore=0; j--) if(IsProperValue(array[j])) return j; return -1; } //+------------------------------------------------------------------+ //| Helper method determines proper value | //+------------------------------------------------------------------+ bool IsProperValue(double value) { return (value!=0 && value!=EMPTY_VALUE); } //+------------------------------------------------------------------+ //| Comment | //+------------------------------------------------------------------+ void ShowComment(string sComment) { if(sComment!="") { com9=com8; //--- discards last comment line com8=com7; //--- and shifts com7=com6; com6=com5; com5=com4; com4=com3; com3=com2; com2=com1; com1=sComment; } Comment("HarmonicPatternFinderV2 © 2016","\n","\n",com1,"\n",com2,"\n",com3,"\n",com4,"\n",com5,"\n",com6,"\n",com7,"\n",com8,"\n",com9,"\n"); } //+------------------------------------------------------------------+ //| Helper method checks if pattern overlaps | //+------------------------------------------------------------------+ bool Overlaps(int k,datetime XDateTime,datetime ADateTime,datetime BDateTime,datetime CDateTime,datetime DDateTime) { bool overlaps=false; //--- Check old patterns in fixed size ring buffer for(int i=0; iMaxSamePoints) return true; } //--- Check active patterns in unlimited size array for(int i=0; i<_patternInstanceCounter; i++) { PATTERN_INSTANCE instance=_patternInstances[i]; int patternIndexActive=_patternInstances[i].patternIndex; if(patternIndexActive!=k) continue; bool bullish=instance.bullish; datetime XDateTimeActive=instance.XDateTime; datetime ADateTimeActive=instance.ADateTime; datetime BDateTimeActive=instance.BDateTime; datetime CDateTimeActive=instance.CDateTime; datetime DDateTimeActive=instance.DDateTime; int numMatches=0; if(!Is4PointPattern(k) && XDateTime==XDateTimeActive) numMatches++; if(ADateTime==ADateTimeActive) numMatches++; if(BDateTime==BDateTimeActive) numMatches++; if(CDateTime==CDateTimeActive) numMatches++; if(DDateTime==DDateTimeActive) numMatches++; if(numMatches>MaxSamePoints) return true; } return false; } //+------------------------------------------------------------------+ //| Helper method stores if pattern overlaps | //+------------------------------------------------------------------+ void StoreOverlaps(int k,datetime XDateTime,datetime ADateTime,datetime BDateTime,datetime CDateTime,datetime DDateTime) { int index=_patternCounter[k]; _patternCounter[k]=(index+1)%SIZE_PATTERN_BUFFER; _patternX[k][index]=XDateTime; _patternA[k][index]=ADateTime; _patternB[k][index]=BDateTime; _patternC[k][index]=CDateTime; _patternD[k][index]=DDateTime; } //+------------------------------------------------------------------+ //| Helper method stores patterns | //+------------------------------------------------------------------+ void StorePattern(int k,bool bullish,datetime XDateTime,datetime ADateTime,datetime BDateTime,datetime CDateTime,datetime DDateTime) { _patternInstances[_patternInstanceCounter].patternIndex=k; _patternInstances[_patternInstanceCounter].bullish=bullish; _patternInstances[_patternInstanceCounter].XDateTime=XDateTime; _patternInstances[_patternInstanceCounter].ADateTime=ADateTime; _patternInstances[_patternInstanceCounter].BDateTime=BDateTime; _patternInstances[_patternInstanceCounter].CDateTime=CDateTime; _patternInstances[_patternInstanceCounter].DDateTime=DDateTime; _patternInstanceCounter++; if(_patternInstanceCounter>=_maxPatternInstances) { _maxPatternInstances*=2; if(ArrayResize(_patternInstances,_maxPatternInstances)<_maxPatternInstances) printf("Error allocating array"); } } //+------------------------------------------------------------------+ //| Helper method stores projections | //+------------------------------------------------------------------+ void StoreProjection(int k,bool bullish, datetime XDateTime,double X, datetime ADateTime,double A, datetime BDateTime,double B, datetime CDateTime,double C, datetime DDateTime,double D, double farD) { _projectionInstances[_projectionInstanceCounter].patternIndex=k; _projectionInstances[_projectionInstanceCounter].bullish=bullish; _projectionInstances[_projectionInstanceCounter].XDateTime=XDateTime; _projectionInstances[_projectionInstanceCounter].ADateTime=ADateTime; _projectionInstances[_projectionInstanceCounter].BDateTime=BDateTime; _projectionInstances[_projectionInstanceCounter].CDateTime=CDateTime; _projectionInstances[_projectionInstanceCounter].DDateTime=DDateTime; _projectionInstances[_projectionInstanceCounter].X=X; _projectionInstances[_projectionInstanceCounter].A=A; _projectionInstances[_projectionInstanceCounter].B=B; _projectionInstances[_projectionInstanceCounter].C=C; _projectionInstances[_projectionInstanceCounter].D=D; _projectionInstances[_projectionInstanceCounter].PRZ=farD; _projectionInstanceCounter++; if(_projectionInstanceCounter>=_maxProjectionInstances) { _maxProjectionInstances*=2; if(ArrayResize(_projectionInstances,_maxProjectionInstances)<_maxProjectionInstances) printf("Error allocating array"); } } //+------------------------------------------------------------------+ //| Helper method displays 4-point PRZ | //+------------------------------------------------------------------+ void DisplayPRZ(int k,bool bullish, datetime ADateTime,double A, datetime BDateTime, datetime CDateTime,double C, datetime DDateTime,double D, double farD) { string unique=UniqueIdentifier(ADateTime,BDateTime,CDateTime,DDateTime); string prefix=(bullish ? "Bullish " : "Bearish "); string prefixName=(bullish ? "U "+_identifier : "D "+_identifier); string name=prefixName+StringFormat("%x",_timeOfInit)+IntegerToString(k)+" PRZ"+unique; ObjectCreate(0,name,OBJ_TREND,0,DDateTime-1,farD,DDateTime,farD); ObjectSetInteger(0,name,OBJPROP_RAY_RIGHT,true); ObjectSetInteger(0,name,OBJPROP_COLOR,bullish ? ClrBull4P : ClrBear4P); ObjectSetInteger(0,name,OBJPROP_STYLE,Style_PRZ); ObjectSetString(0,name,OBJPROP_TOOLTIP,prefix+_patternNames[k]+" PRZ stop "+DoubleToString(farD)); } //+------------------------------------------------------------------+ //| Helper method displays 5-point PRZ | //+------------------------------------------------------------------+ void DisplayPRZ(int k,bool bullish, datetime XDateTime,double X, datetime ADateTime,double A, datetime BDateTime, datetime CDateTime,double C, datetime DDateTime,double D, double farD) { string unique=UniqueIdentifier(XDateTime,ADateTime,BDateTime,CDateTime,DDateTime); string prefix=(bullish ? "Bullish " : "Bearish "); string prefixName=(bullish ? "U "+_identifier : "D "+_identifier); string name=prefixName+StringFormat("%x",_timeOfInit)+IntegerToString(k)+" PRZ"+unique; ObjectCreate(0,name,OBJ_TREND,0,DDateTime-1,farD,DDateTime,farD); ObjectSetInteger(0,name,OBJPROP_RAY_RIGHT,true); ObjectSetInteger(0,name,OBJPROP_COLOR,bullish ? ClrBull: ClrBear); ObjectSetInteger(0,name,OBJPROP_STYLE,Style_PRZ); ObjectSetString(0,name,OBJPROP_TOOLTIP,prefix+_patternNames[k]+" PRZ stop "+DoubleToString(farD)); } //+------------------------------------------------------------------+ //| Helper method displays 4-point patterns | //+------------------------------------------------------------------+ void DisplayPattern(int k,bool bullish, datetime ADateTime,double A, datetime BDateTime,double B, datetime CDateTime,double C, datetime DDateTime,double D) { string unique=UniqueIdentifier(ADateTime,BDateTime,CDateTime,DDateTime); string prefix=(bullish ? "Bullish " : "Bearish "); string prefixName=(bullish ? "U "+_identifier : "D "+_identifier); string name0=prefixName+StringFormat("%x",_timeOfInit)+IntegerToString(k)+" AB"+unique; string name1=prefixName+StringFormat("%x",_timeOfInit)+IntegerToString(k)+" BC"+unique; string name2=prefixName+StringFormat("%x",_timeOfInit)+IntegerToString(k)+" CD"+unique; string pointA=prefixName+StringFormat("%x",_timeOfInit)+IntegerToString(k)+" PA"+unique; string pointB=prefixName+StringFormat("%x",_timeOfInit)+IntegerToString(k)+" PB"+unique; string pointC=prefixName+StringFormat("%x",_timeOfInit)+IntegerToString(k)+" PC"+unique; string pointD=prefixName+StringFormat("%x",_timeOfInit)+IntegerToString(k)+" PD"+unique; //--- Create lines on the chart ObjectCreate(0,name0,OBJ_TREND,0,ADateTime,A,BDateTime,B); ObjectCreate(0,name1,OBJ_TREND,0,BDateTime,B,CDateTime,C); ObjectCreate(0,name2,OBJ_ARROWED_LINE,0,CDateTime,C,DDateTime,D); ObjectSetInteger(0,name0,OBJPROP_COLOR, bullish ? ClrBull4P : ClrBear4P); ObjectSetInteger(0,name1,OBJPROP_COLOR, bullish ? ClrBull4P : ClrBear4P); ObjectSetInteger(0,name2,OBJPROP_COLOR, bullish ? ClrBull4P : ClrBear4P); ObjectSetInteger(0,name0,OBJPROP_SELECTABLE,true); ObjectSetInteger(0,name1,OBJPROP_SELECTABLE,true); ObjectSetInteger(0,name2,OBJPROP_SELECTABLE,true); ObjectSetInteger(0,name0,OBJPROP_WIDTH,l_width4p); ObjectSetInteger(0,name1,OBJPROP_WIDTH,l_width4p); ObjectSetInteger(0,name2,OBJPROP_WIDTH,l_width4p); ObjectSetInteger(0,name0,OBJPROP_STYLE,Style_4P); ObjectSetInteger(0,name1,OBJPROP_STYLE,Style_4P); ObjectSetInteger(0,name2,OBJPROP_STYLE,Style_4P); ObjectSetString(0,name0,OBJPROP_TOOLTIP,prefix+_patternNames[k]+" AB"); ObjectSetString(0,name1,OBJPROP_TOOLTIP,prefix+_patternNames[k]+" BC"); ObjectSetString(0,name2,OBJPROP_TOOLTIP,prefix+_patternNames[k]+" CD"); if(Show_descriptions) { int numOverlapping=0; for(int i=0; i