Candle_Patterns

Author: Copyright � 2008, sx ted
3 Views
0 Downloads
0 Favorites
Candle_Patterns
//+------------------------------------------------------------------+
//|                                              Candle Patterns.mq4 |
//|                                         Copyright © 2008, sx ted |
//|                                           tedhirsch@talktalk.net |
//|                                                       2008.12.16 |
//| Purpose..: Visual and Audio alerts when reversal or continuation |
//|            candle patterns occur.                                |
//| Based On.: Many many thanks to:                                  |
//|            1) Japanese Candlesticks http://www.candlesticker.com |
//|            2) CandleCode by Victor Likhovidov, references to be  |
//|               found at http://www.forexschool.ru                 |
//| Thank you: Big thank you CodersGuru at http://www.forex-tsd.com  |
//|            for coding the gSpeak() function so as to have audio  |
//|            signals.                                              |
//| Setup....: Place files into the following subdirectories:        |
//|                Candle Patterns.mq4 into "\experts\indicators",   |
//|                Candle Patterns.csv into "\experts\files",        |
//|                Candle Patterns.rtd into "\experts\files",        |
//|                Symbols_.csv        into "\experts\files",        |
//|                gSpeak.mqh          into "\experts\include",      |
//|                speak.dll           into "\experts\libraries",    |
//|                candle patterns.tpl into "\templates".            |
//|            Close and then re-start MetaTrader for it to find the |
//|            new files.                                            |
//|            Select "Indicators" -> "Custom" -> "Candle Patterns". |
//|            The "Custom Indicator" window is displayed, select    |
//|            "Common" and enable "Allow DLL imports".              |
//|            "Inputs" are described in file "Candle Patterns.rtd", |
//|            alternatively right click on the chart and select     |
//|            "candle patterns.tpl" from "Templates".               |
//| Note 1...: While testing, the indicator has not yet encountered  |
//|            patterns comprised of four or five candles, please let|
//|            me know on which broker's chart and time frame seen   |
//|            and publish it on the forum as a .GIF image would be  |
//|            super.                                                |
//| Note 2...: Delete the Candle Patterns indicator from the chart   |
//|            before changing the period.                           |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2008, sx ted"
#property link      "tedhirsch@talktalk.net"

//+------------------------------------------------------------------+
//| indicator setup                                                  |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_buffers 2                                       // helps improve memory

//+------------------------------------------------------------------+
//| EX4 imports                                                      |
//+------------------------------------------------------------------+
#include <gSpeak.mqh>

//+------------------------------------------------------------------+
//| input parameters:                                                |
//+-----------0---+----1----+----2----+----3]------------------------+
extern int           MaxBarsToScanForPatterns = 1;                  //  0: display visible patterns only
                                                                    //  1: display pattern of bar 1 only
                                                                    // >1: display patterns up to MaxBars
extern bool                    ConfirmPattern = true;
extern bool                MoveTextOneRowDown = true;
extern bool                           AudioON = true;
extern color                ColorSingleCandle = Aqua;
extern color                ColorMultiCandles = DeepSkyBlue;
extern color       AlternateColorSingleCandle = Yellow;
extern color       AlternateColorMultiCandles = Gold;
extern color                   ColorArrowDown = DarkOrange;
extern color                     ColorArrowUp = Lime;
extern color                        ColorText = LemonChiffon;
extern int                VerticalTextAdjustX = 1;                  // adjust co-ord x of vertical text
extern int               VerticalTextFontSize = 8;                  // for zoom level 3
extern int                     TrendMA_Period = 13;                 // Averaging period for calculation
extern int                      TrendMA_Shift = 15;                 // Shift relative to the current bar
                                                                    // to compare the averages so as to
                                                                    // determine the trend

//+------------------------------------------------------------------+
//| defines                                                          |
//+------------------------------------------------------------------+
#define CALC_ALL                                          -9        // calculate all flag
#define MAX_CANDLES                                        5        // max candles in a pattern
#define ERR_0                                              0.00001  // avoid divide by zero factor
//-------------------------------------------------------------------- Candle and shadow sizes:
#define CandleBodyCount                                    0        // Candle Body Count if size > 0
#define CandleBodyTotal                                    1        // Candle Body aggregate
#define SmallCandleBody                                    2        // Candle Body Small (top threshold)
#define LongCandleBody                                     3        // Candle Body Long (bottom threshold)
#define UpperShadowCount                                   4        // Upper Shadow Count if size > 0
#define UpperShadowTotal                                   5        // Upper Shadow aggregate
#define SmallUpperShadow                                   6        // Upper Shadow Small (top threshold)
#define LongUpperShadow                                    7        // Upper Shadow Long (bottom threshold)
#define BottomShadowCount                                  8        // Lower Shadow Count if size > 0
#define BottomShadowTotal                                  9        // Lower Shadow aggregate
#define SmallBottomShadow                                 10        // Lower Shadow Small (top threshold)
#define LongBottomShadow                                  11        // Lower Shadow Long (bottom threshold)
#define SIZE_CNT                                          12        // array dSize count of elements
#define LT_FACTOR                                          0.31     // Lower Threshold Factor
//-------------------------------------------------------------------- Base Candles:
#define FourPriceDoji                                      0        // 0
#define Umbrella_1                                         1        // 1
#define Umbrella_2                                         2        // 2
#define Doji                                               3        // 3
#define DojiSN                                             4        // 4 Doji with small/normal legs
#define DojiSNL                                            5        // 5 Doji with all kinds of legs
#define InvertedUmbrella_6                                 6        // 6
#define InvertedUmbrella_7                                 7        // 7
#define LongLeggedDoji_8                                   8        // 8   
#define LongLeggedDoji_9                                   9        // 9   
#define SmallBlackCandle                                  10        // A
#define HighWave                                          11        // B     
#define BlackSpinningTop                                  12        // C
#define BlackCandle                                       13        // D
#define BlackCandleDay4LadderBottom                       14        // E
#define BlackDay3ConcealBabySwallow                       15        // F
#define BlackMarubozu                                     16        // G   
#define BlackOpeningMarubozu                              17        // H  
#define BlackOpeningMarubozuLongshadow                    18        // I
#define BlackClosingMarubozu                              19        // J  
#define LongBlackCandle                                   20        // K
#define SmallWhiteCandle                                  21        // L
#define WhiteSpinningTop                                  22        // M  
#define WhiteCandle                                       23        // N
#define WhiteMarubozu                                     24        // O   
#define WhiteClosingMarubozu                              25        // P  
#define WhiteOpeningMarubozu                              26        // Q  
#define LongWhiteCandle                                   27        // R  
#define BlackHammerOrHangingMan                           28        // S  
#define WhiteHammerOrHangingMan                           29        // T              
#define InvertedUmbrella_U                                30        // U   
#define InvertedUmbrella_V                                31        // V
#define BlackInvertedHammerOrStar                         32        // W 
#define WhiteInvertedHammerOrStar                         33        // X                      
//-------------------------------------------------------------------- sPattern: specs & name
#define P_DISPLAY    0 // Display flag:        1=Display,     0=Hide
#define P_TYP        1 // pattern Type:        R=Reversal,    C=Continuation,  X=Reversal/Continuation
#define P_REE        2 // pattern Relevance:   D=Bearish,     U=Bullish,       I=Indecision
#define P_PRV        3 // Previous trend:      D=Bearish,     U=Bullish        X=N/A
#define P_NUM        4 // Number of candles
#define P_CHK        5 // confirmation Check:  refer to ConfirmPattern para
#define P_LEN        6 // Length of name
#define P_NAM        7 // pattern Name
//-------------------------------------------------------------------- arrow shapes:
#define C_DN       "ê" // -22 was 234 for identifying font "Wingdings" character Arrow Down
#define C_UP       "é" // -23 was 233 for identifying font "Wingdings" character Arrow Up
//-------------------------------------------------------------------- Text to Audio:
#define M_BUY      "Buy"
#define M_DN       "Pattern confirmed down"
#define M_REV_DN   "Pattern confirmed reverse down"
#define M_REV_UP   "Pattern confirmed reverse up"
#define M_UP       "Pattern confirmed up"
#define M_SELL     "Sell"
#define M_NULL     ""
//-------------------------------------------------------------------- Trade Type:
#define TT_BUY         0 // Buy
#define TT_SELL        1 // Sell
#define TT_NO_PATTERN -1 // No Pattern found
#define TT_WAIT       -2 // cater for Reversal/Continuation and wait for confirmation
//-------------------------------------------------------------------- font:
#define V_TXT_FONT_SIZE 8 // original font size used while scaling vertical text 

//+------------------------------------------------------------------+
//| global variables to program:                                     |
//+------------------------------------------------------------------+
bool     bAlternateColorMulti,
         bAlternateColorSingle,
         TrendDn,
         TrendUp;
datetime tPreviousTime;
double   dSize[SIZE_CNT],                                           // candle sizes
         dPipsFactor,                                               // price to pips conversion factor
         O[MAX_CANDLES],                                            // Open
         H[MAX_CANDLES],                                            // High
         L[MAX_CANDLES],                                            // Low
         C[MAX_CANDLES],                                            // Close
         B[MAX_CANDLES],                                            // candle body bottom
         T[MAX_CANDLES];                                            // candle body top
int      candle[MAX_CANDLES],                                       // candle code
         iBarsToScan,
         iPattern,                                                  // candle Pattern number         
         iPeriod,      
         iScaleAdjustX,                                             // used for vertical text alignment
         iScaleAdjustX_MN,                                          // PERIOD MN1 basis for pro rata calc              
         iScaleAdjustY,
         iVeryNear,
         iVerySmallBody;
string   sBoxObj,
         sMsg,
         sAudio,
         sPRV,                                                      // Previous Trend Confirmation arrow
         sREE,                                                      // Relevance Confirmation arrow
         sSymbol;
/*-------------------------------------------------------------------- Base Candles:
                             Dec,Base candle code number             , p,c, b , u, l */ 
int      iBaseCandle[96][2]={  0,FourPriceDoji,                     // 0,0,000,00,00         
                               3,Umbrella_1,                        // 0,0,000,00,11           
                               4,InvertedUmbrella_U,                // 0,0,000,01,00          
                               5,Doji,                              // 0,0,000,01,01
                               6,DojiSN,                            // 0,0,000,01,10
                               7,DojiSNL,                           // 0,0,000,01,11
                               8,InvertedUmbrella_V,                // 0,0,000,10,00          
                               9,DojiSN,                            // 0,0,000,10,01
                              10,DojiSN,                            // 0,0,000,10,10
                              11,DojiSNL,                           // 0,0,000,10,11
                              12,InvertedUmbrella_6,                // 0,0,000,11,00          
                              13,DojiSNL,                           // 0,0,000,11,01
                              14,DojiSNL,                           // 0,0,000,11,10
                              15,LongLeggedDoji_8,                  // 0,0,000,11,11         
                              19,Umbrella_2,                        // 0,0,001,00,11           
                              21,DojiSN,                            // 0,0,001,01,01
                              22,DojiSN,                            // 0,0,001,01,10
                              23,DojiSNL,                           // 0,0,001,01,11
                              25,DojiSN,                            // 0,0,001,10,01
                              26,DojiSN,                            // 0,0,001,10,10
                              27,DojiSNL,                           // 0,0,001,10,11
                              28,InvertedUmbrella_7,                // 0,0,001,11,00          
                              29,DojiSNL,                           // 0,0,001,11,01
                              30,DojiSNL,                           // 0,0,001,11,10
                              31,LongLeggedDoji_9,                  // 0,0,001,11,11         
                              39,HighWave,                          // 0,0,010,01,11          
                              43,HighWave,                          // 0,0,010,10,11          
                              45,HighWave,                          // 0,0,010,11,01          
                              46,HighWave,                          // 0,0,010,11,10          
                              47,HighWave,                          // 0,0,010,11,11          
                              56,BlackCandleDay4LadderBottom,       // 0,0,011,10,00 
                              60,BlackDay3ConcealBabySwallow,       // 0,0,011,11,00
                              64,BlackMarubozu,                     // 0,0,100,00,00          
                              65,BlackOpeningMarubozu,              // 0,0,100,00,01         
                              66,BlackOpeningMarubozu,              // 0,0,100,00,10         
                              67,BlackOpeningMarubozuLongshadow,    // 0,0,100,00,11     
                              68,BlackClosingMarubozu,              // 0,0,100,01,00         
                              69,LongBlackCandle,                   // 0,0,100,01,01         
                              70,LongBlackCandle,                   // 0,0,100,01,10         
                              71,LongBlackCandle,                   // 0,0,100,01,11         
                              72,BlackClosingMarubozu,              // 0,0,100,10,00         
                              73,LongBlackCandle,                   // 0,0,100,10,01         
                              74,LongBlackCandle,                   // 0,0,100,10,10         
                              75,LongBlackCandle,                   // 0,0,100,10,11         
                              76,BlackClosingMarubozu,              // 0,0,100,11,00         
                              77,LongBlackCandle,                   // 0,0,100,11,01         
                              78,LongBlackCandle,                   // 0,0,100,11,10         
                              79,LongBlackCandle,                   // 0,0,100,11,11         
                             147,Umbrella_2,                        // 0,1,001,00,11           
                             149,DojiSN,                            // 0,1,001,01,01
                             150,DojiSN,                            // 0,1,001,01,10
                             151,DojiSNL,                           // 0,1,001,01,11
                             153,DojiSN,                            // 0,1,001,10,01
                             154,DojiSN,                            // 0,1,001,10,10
                             155,DojiSNL,                           // 0,1,001,10,11
                             156,InvertedUmbrella_7,                // 0,1,001,11,00          
                             157,DojiSNL,                           // 0,1,001,11,01
                             158,DojiSNL,                           // 0,1,001,11,10
                             159,LongLeggedDoji_9,                  // 0,1,001,11,11         
                             167,HighWave,                          // 0,1,010,01,11          
                             171,HighWave,                          // 0,1,010,10,11          
                             173,HighWave,                          // 0,1,010,11,01          
                             174,HighWave,                          // 0,1,010,11,10          
                             175,HighWave,                          // 0,1,010,11,11          
                             192,WhiteMarubozu,                     // 0,1,100,00,00          
                             193,WhiteClosingMarubozu,              // 0,1,100,00,01         
                             194,WhiteClosingMarubozu,              // 0,1,100,00,10         
                             195,WhiteClosingMarubozu,              // 0,1,100,00,11         
                             196,WhiteOpeningMarubozu,              // 0,1,100,01,00         
                             197,LongWhiteCandle,                   // 0,1,100,01,01         
                             198,LongWhiteCandle,                   // 0,1,100,01,10         
                             199,LongWhiteCandle,                   // 0,1,100,01,11         
                             200,WhiteOpeningMarubozu,              // 0,1,100,10,00         
                             201,LongWhiteCandle,                   // 0,1,100,10,01         
                             202,LongWhiteCandle,                   // 0,1,100,10,10         
                             203,LongWhiteCandle,                   // 0,1,100,10,11         
                             204,WhiteOpeningMarubozu,              // 0,1,100,11,00         
                             205,LongWhiteCandle,                   // 0,1,100,11,01         
                             206,LongWhiteCandle,                   // 0,1,100,11,10         
                             207,LongWhiteCandle,                   // 0,1,100,11,11         
                             291,BlackHammerOrHangingMan,           // 1,0,010,00,11         
                             293,SmallBlackCandle,                  // 1,0,010,01,01         
                             298,BlackSpinningTop,                  // 1,0,010,10,10         
                             299,BlackSpinningTop,                  // 1,0,010,10,11         
                             300,BlackInvertedHammerOrStar,         // 1,0,010,11,00        
                             302,BlackSpinningTop,                  // 1,0,010,11,10         
                             303,BlackSpinningTop,                  // 1,0,010,11,11         
                             309,BlackCandle,                       // 1,0,011,01,01          
                             419,WhiteHammerOrHangingMan,           // 1,1,010,00,11         
                             421,SmallWhiteCandle,                  // 1,1,010,01,01         
                             426,WhiteSpinningTop,                  // 1,1,010,10,10         
                             427,WhiteSpinningTop,                  // 1,1,010,10,11         
                             428,WhiteInvertedHammerOrStar,         // 1,1,010,11,00        
                             430,WhiteSpinningTop,                  // 1,1,010,11,10         
                             431,WhiteSpinningTop,                  // 1,1,010,11,11         
                             437,WhiteCandle                        // 1,1,011,01,01         
                            }; 
//-------------------------------------------------------------------- Candle Patterns:
string sPattern[91][8];
                     
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
void init() {
  //                     Period    ,TextSize,ChartHeight,
  int iTextRatios[9][3]={PERIOD_M1 ,       5,         20,           // TextSize based on Pattern number
                         PERIOD_M5 ,      21,         70,           // 40 and scaled using the Crosshair
                         PERIOD_M15,      32,        110,           // and custom indicator CP_TextSize.
                         PERIOD_M30,      35,        120,           // 
                         PERIOD_H1 ,      35,        120,           // ChartHeight is the height of chart
                         PERIOD_H4 ,     139,        470,           // in points, with no sub-windows,
                         PERIOD_D1 ,     285,        960,           // when Pattern 40 was scaled,
                         PERIOD_W1 ,     552,       1864,           // corresponds to PriceMaxVisible()
                         PERIOD_MN1,    1729,       5850            // minus PriceMinVisible().
                        },
      i, x;
              
  ObjectsDeletePrefixed("CP_");
  candle[0]=CALC_ALL;                                               // load all flag
  dPipsFactor=MathPow(10, Digits);
  dSize[0]=CALC_ALL;                                                // calculate average for all bars flag
  iPattern=TT_NO_PATTERN;
  iPeriod=Period();
  sBoxObj="";
  sMsg="";
  sAudio="";
  sPRV="";
  sREE="";   
  sSymbol=Symbol();
  tPreviousTime=D'01.01.2008';
  
  if(StringArrayLoad("Candle Patterns.csv", sPattern, 8)<1)
    sMsg=StringConcatenate(sMsg,"Error "+GetLastError()+" reading file Candle Patterns.csv\n");  
  
  if(AudioON) {
    if(IsDllsAllowed()==false) sMsg=StringConcatenate(sMsg,"Check \"Allow DLL imports\" to enable program\n");
    string sSymbols[][2];
    x=StringArrayLoad("Symbols_.csv", sSymbols, 2);
    if(x<1) sMsg=StringConcatenate(sMsg,"Error "+GetLastError()+" reading file Symbols_.csv\n");  
    for(i=0; i<x; i++) {
      if(sSymbols[i][0]==sSymbol) break;
    }
    if(i<x) sAudio=sSymbols[i][1];
    else    sMsg=StringConcatenate(sMsg,"Symbol not found\n");
    string sPeriods[9][2]={   "1", "1 minute",
                              "5", "5 minutes",
                             "15", "15 minutes",
                             "30", "30 minutes",
                             "60", "1 hour",
                            "240", "4 hour",
                           "1440", "Daily",
                          "10080", "Weekly",
                          "43200", "Monthly"
                         }; 
    for(i=0; i<9; i++)  {
      if(sPeriods[i][0]==DoubleToStr(iPeriod,0)) break;
    }
    if(i<9) sAudio=StringConcatenate(sAudio," ",sPeriods[i][1]," ");
    else    sMsg=StringConcatenate(sMsg,"Period not found\n");
  }
    
  if(MaxBarsToScanForPatterns == 1) {
    CreateLabelObject("CP_CONFIRM_PRIOR_TREND", 1, 76, MoveTextOneRowDown*10);
    CreateLabelObject("CP_CONFIRM_RELEVANCE"  , 1, 61, MoveTextOneRowDown*10);
    CreateLabelObject("CP_TYPE"               , 1, 46, MoveTextOneRowDown*10);
    CreateLabelObject("CP_PRIOR_TREND"        , 1, 31, MoveTextOneRowDown*10);
    CreateLabelObject("CP_RELEVANCE"          , 1, 16, MoveTextOneRowDown*10);
    CreateLabelObject("CP_CONFIRMATION"       , 1,  1, MoveTextOneRowDown*10);
    CreateLabelObject("CP_NAME"               , 0,  0, MoveTextOneRowDown*10);
  }
  else {
    if(WindowsTotal() > 1) Alert("Labels may overwrite candles if sub-windows open!");
    // determine factors for adjustment of vertical text so that labels
    // do not overlay candles, if possible, as MT4 co-ordinates refer
    // to the center of label object's (horizontal by design)
    iScaleAdjustX=-1;
    iScaleAdjustX_MN=-1;
    for(i=0; i<9; i++) {                                            // for all chart timeframe's
      if(iTextRatios[i][0] == iPeriod) {
        iScaleAdjustX=iTextRatios[i][1];
        iScaleAdjustY=iTextRatios[i][2];
      }
      if(iTextRatios[i][0] == PERIOD_MN1) iScaleAdjustX_MN=iTextRatios[i][1];
    }
    if(iScaleAdjustX == -1 || iScaleAdjustX_MN == -1) sMsg=StringConcatenate(sMsg,"Period not found\n");
    iBarsToScan=MathMin(Bars-MAX_CANDLES,MathMax(MaxBarsToScanForPatterns,WindowBarsPerChart()));
    if(iBarsToScan < MAX_CANDLES+1) sMsg=StringConcatenate(sMsg,"Bars < ",MAX_CANDLES+1,"\n");
    for(i=iBarsToScan; i>1; i--) {
      iPattern=Pattern(i);
      if((iPattern >= 0) && (sPattern[iPattern][P_DISPLAY] == "1")) DisplayPatterns(iPattern, i);
    }
  }
  if(sMsg!="") Alert(sMsg);
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void deinit() {
  ObjectsDeletePrefixed("CP_");
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
void start() {
  color  cColor=ColorArrowUp;
  int    i, x;
  string sChr=C_UP, obj;
  
  if(sMsg!="") return;
  
  if((MaxBarsToScanForPatterns != 1) && (Bars > WindowFirstVisibleBar())) { // Bars > WndLeft
    // Wait for tick and redraw all visible vertical text as chart may have changed height
    i=1;
    int    iWndLeft=WindowFirstVisibleBar();
    double dWndTop=WindowPriceMax(),
           dWndBot=WindowPriceMin(),
           dPriceMax=PriceMaxVisible(),
           dPriceMin=PriceMinVisible();
    if(dPriceMax > dWndTop) dWndTop=dPriceMax;
    if(dPriceMin < dWndBot) dWndBot=dPriceMin;
    while(i <= iWndLeft) {
      obj="CP_"+Time[i];
      if((ObjectFind(obj) >= 0) && (ObjectType(obj) == OBJ_TEXT)) MoveLabel(obj, dWndTop, dWndBot, dPriceMax, dPriceMin);
      i++;
    }
    WindowRedraw(); // force redraw of current chart after moving of objects
  }
  
  if(tPreviousTime == Time[0]) return; // only start analysis on complete bars
  if(Bars < MAX_CANDLES+1) return;

  if(MaxBarsToScanForPatterns == 1) {
    // switch off any previous confirming arrows
    DisplayLabelObject("CP_CONFIRM_PRIOR_TREND", " ", ColorText);
    DisplayLabelObject("CP_CONFIRM_RELEVANCE"  , " ", ColorText);
    
    // remember last pattern number for confirmation of previous candle pattern
    x=iPattern;
  
    // check if newly formed bar 1 matches a candle pattern   
    iPattern=Pattern(1);
    
    PatternConfirm(x);
    
    // delete hilite of previous pattern
    ObjectDelete("CP_BOX");
    // check if a new candle pattern has been found
    if((iPattern >= 0) && (sPattern[iPattern][P_DISPLAY] == "1")) {
      DisplayPattern1(iPattern, 1);
      // display indication of current trend with arrow Up or arrow Down
      if(TrendDn) {
        sChr=C_DN;
        cColor=ColorArrowDown;
      }
      DisplayLabelObject("CP_PRIOR_TREND", sChr, cColor);
      sPRV=sChr;

      /* 
      display indication of Relevance (new direction):
      TYP |REE| PRV | Action
      ----+---+-----+---------------------------------
       C  | D |  D  | Sell                                 
       C  | U |  U  | Buy                                  
       R  | D |  U  | Sell                                 
       R  | D |  X  | Sell                                 
       R  | I |  Xup| Sell Patterns 1/2/3/4                
       R  | I |  Xdn| Buy  Patterns 1/2/3/4                
       R  | U |  D  | Buy                                  
       R  | U |  X  | Buy  Pattern 51                      
       X  | D |  X  | Sell Patterns 46-49 on Relevance     
       X  | I |  X  | Wait                                 
       X  | U |  X  | Buy  Patterns 85-88 on Relevance
      */     
      if((sPattern[iPattern][P_REE] == "U") || (sPattern[iPattern][P_REE] == "I" && sPattern[iPattern][P_TYP] == "R" && TrendDn)) {
        sMsg=M_BUY;
        sChr=C_UP;
        cColor=ColorArrowUp;
      }
      else if((sPattern[iPattern][P_REE] == "D") || (sPattern[iPattern][P_REE] == "I" && sPattern[iPattern][P_TYP] == "R" && TrendUp)) {
        sMsg=M_SELL;
        sChr=C_DN;
        cColor=ColorArrowDown;
      }
      else sChr=sPattern[iPattern][P_REE]; // "I" (Indecision)
      DisplayLabelObject("CP_RELEVANCE", sChr, cColor);
      sREE=sChr;

      // display indication of Pattern Type: R=Reversal, C=Continuation, X=Reversal/Continuation
      DisplayLabelObject("CP_TYPE", sPattern[iPattern][P_TYP], cColor);
      // display Confirmation required: Pattern Type R/C=_Q, X=_S
      if(sPattern[iPattern][P_TYP] == "X") sChr=" ";
      else                                 sChr="?";
      DisplayLabelObject("CP_CONFIRMATION", sChr, cColor);
      sMsg=StringConcatenate(sPattern[iPattern][P_NAM]," ",sMsg);
      if(AudioON) gSpeak(StringConcatenate(sAudio,sPattern[iPattern][P_NAM]));
    }
    else {                                                          // pattern not found
      sMsg=" ";
      sPRV=" ";
      sREE=" ";
      DisplayLabelObject("CP_TYPE"        , " ", ColorArrowDown);
      DisplayLabelObject("CP_PRIOR_TREND" , " ", ColorArrowDown);
      DisplayLabelObject("CP_RELEVANCE"   , " ", ColorArrowDown);
      DisplayLabelObject("CP_CONFIRMATION", " ", ColorArrowDown);
    }
    // display Pattern Name & stats
    ObjectSetText("CP_NAME",sMsg,11,"Verdana",ColorText);
  }
  else {
          
    // delete objects beyond range requested by <iBarsToScan>
    obj="CP_"+Time[iBarsToScan];
    if(ObjectFind(obj) >= 0) ObjectDelete(obj);
    obj="CP_B"+Time[iBarsToScan];
    if(ObjectFind(obj) >= 0) ObjectDelete(obj);
      
    // remember last pattern number for confirmation of previous candle pattern
    x=iPattern;
  
    // check if newly formed bar 1 matches a candle pattern   
    iPattern=Pattern(1);
    
    PatternConfirm(x);
  
    if((iPattern >= 0) && (sPattern[iPattern][P_DISPLAY] == "1")) {
      DisplayPatterns(iPattern, 1);
      if(AudioON) gSpeak(StringConcatenate(sAudio,sPattern[iPattern][P_NAM]));
    }
  }
  tPreviousTime=Time[0];
  sMsg="";
}

//+------------------------------------------------------------------+
//| CreateLabelObject                                                |
//+------------------------------------------------------------------+
void CreateLabelObject(string obj, int iCorner, int x, int y) {
  ObjectCreate(obj, OBJ_LABEL, 0, 0, 0);
  ObjectSet(obj, OBJPROP_CORNER   , iCorner);
  ObjectSet(obj, OBJPROP_XDISTANCE, x      );
  ObjectSet(obj, OBJPROP_YDISTANCE, y      );
}

//+------------------------------------------------------------------+
//| DisplayLabelObject                                               |
//+------------------------------------------------------------------+
void DisplayLabelObject(string obj, string sChr, color cColor) {
  int y=1, iFontSize=14;
  string sFont="Verdana";
  if(sChr == "?" ) { y=0; iFontSize=15; sFont="Verdana"  ; }
  if(sChr == C_DN) { y=5; iFontSize=13; sFont="Wingdings"; }
  if(sChr == C_UP) { y=1; iFontSize=13; sFont="Wingdings"; }
  ObjectSet(obj, OBJPROP_YDISTANCE, MoveTextOneRowDown*10+y);
  ObjectSetText(obj, sChr, iFontSize, sFont, cColor);
}

//+------------------------------------------------------------------+
//| Display Pattern formed at Bar 1                                  |
//+------------------------------------------------------------------+
void DisplayPattern1(int iPattern, int iBar) {
  double dPadY, h,l;
  int    iCandles, x, y;
  
  // determine number of candles found in pattern
  iCandles=StrToInteger(sPattern[iPattern][P_NUM]);
    
  // find position of highest price in the candle pattern
  y=ArrayMaximum(H,iCandles);
  // find position of lowest price in the candle pattern
  x=ArrayMinimum(L,iCandles);
  // convert pip values back to prices for drawing object on chart
  h=H[y]/(ERR_0+dPipsFactor);
  l=L[x]/(ERR_0+dPipsFactor);
  // calculate some padding between the candle pattern and the rectangular box that will hilite it
  dPadY=(PriceMaxVisible() - PriceMinVisible()) * MathPow(10, Digits) / 30 * Point;
    
  // Hilite the candles forming the pattern in coloured box
  ObjectCreate("CP_BOX",OBJ_RECTANGLE,0,Time[iBar+iCandles],h+dPadY,Time[iBar-1],l-dPadY);
  ObjectSet("CP_BOX",OBJPROP_COLOR,AlternateColorSingleCandle);
  // set background drawing flag for object, so as to only draw perimeter
  ObjectSet("CP_BOX",OBJPROP_BACK,false);
}

//+------------------------------------------------------------------+
//| DisplayPatterns()                                                |
//+------------------------------------------------------------------+
void DisplayPatterns(int iPattern, int iBar) {
  color    cColor=ColorSingleCandle;
  datetime t;
  double   dWndTop=WindowPriceMax(),
           dWndBot=WindowPriceMin(),
           dChartHeight=dWndTop-dWndBot,   
           dPriceMax=PriceMaxVisible(),
           dPriceMin=PriceMinVisible(), dPadY, dY, h, l;
  string   obj;
  int      i, iLen, iCandles, x, y;

  if(dPriceMax > dWndTop) dWndTop=dPriceMax;
  if(dPriceMin < dWndBot) dWndBot=dPriceMin;
  // determine number of candles found in pattern
  iCandles=StrToInteger(sPattern[iPattern][P_NUM]);
  // find position of highest price in the candle pattern
  y=ArrayMaximum(H,iCandles);
  // find position of lowest price in the candle pattern
  x=ArrayMinimum(L,iCandles);
  // convert pip values back to prices for drawing object on chart
  h=H[y]/(ERR_0+dPipsFactor);
  l=L[x]/(ERR_0+dPipsFactor);
  // calculate some padding between the candle pattern and the rectangular box that will hilite it
  dPadY=(dPriceMax - dPriceMin) * MathPow(10, Digits) / 30 * Point;
  if(iCandles == 1) {
    bAlternateColorSingle=!bAlternateColorSingle;
    if(bAlternateColorSingle) cColor=AlternateColorSingleCandle;
  }
  else {
    bAlternateColorMulti=!bAlternateColorMulti;
    if(bAlternateColorMulti) cColor=AlternateColorMultiCandles;
    else                     cColor=ColorMultiCandles;
    sBoxObj="CP_B"+Time[iBar];
    // Hilite the candles forming the pattern in colored box
    ObjectCreate(sBoxObj,OBJ_RECTANGLE,0,Time[iBar+iCandles],h+dPadY,Time[iBar-1],l-dPadY);
    ObjectSet(sBoxObj,OBJPROP_COLOR,cColor);
    // set background drawing flag for object, so as to only draw perimeter
    ObjectSet(sBoxObj,OBJPROP_BACK,false);
  }
  // calculate x and y co-ordinates of middle of the string to feed to MT4 ObjectCreate(),
  // only "Arial" font can be used for vertical text in MT4 at present.
  iLen=StrToInteger(sPattern[iPattern][P_LEN]);
  if(dPriceMax-High[iBar] > Low[iBar]-dPriceMin)
    dY=High[iBar]+NormalizeDouble(VerticalTextFontSize/V_TXT_FONT_SIZE*iLen*iScaleAdjustX/iScaleAdjustX_MN*dChartHeight/iScaleAdjustY/2, Digits);
  else
    dY=Low[iBar]-NormalizeDouble(VerticalTextFontSize/V_TXT_FONT_SIZE*iLen*iScaleAdjustX/iScaleAdjustX_MN*dChartHeight/iScaleAdjustY/2, Digits);
  obj="CP_"+Time[iBar];
  // display the text vertically
  ObjectCreate(obj, OBJ_TEXT, 0, Time[iBar+VerticalTextAdjustX], dY);
  ObjectSetText(obj, sPattern[iPattern][P_NAM], VerticalTextFontSize, "Arial", cColor);
  ObjectSet(obj, OBJPROP_ANGLE, 90);
  // keep track of label text width for refresh by storing it in unused OBJECT PROPERTY TIME2 slot
  ObjectSet(obj, OBJPROP_TIME2, iLen);
  // verify that current single pattern is not on right side of just completed box (done on previous bar)
  if(iCandles == 1 && sBoxObj != "") {
    if(ObjectGet(sBoxObj,OBJPROP_TIME2) == Time[iBar]) {
      // keep track of box y co-ordinates for moving label on right
      // hand side out of box if possible for more readable output
      ObjectSet(obj, OBJPROP_PRICE2, ObjectGet(sBoxObj, OBJPROP_PRICE1));
      ObjectSet(obj, OBJPROP_PRICE3, ObjectGet(sBoxObj, OBJPROP_PRICE2));
      // move label on right border of just completed box (on previous bar) if required
      MoveLabel(obj, dWndTop, dWndBot, dPriceMax, dPriceMin);
      WindowRedraw(); // force redraw of current chart after moving of objects
      sBoxObj="";
    }
  }
  else if(iCandles > 1) {
    // keep track of box y co-ordinates for moving labels out of box if possible for more readable output
    i=iBar;
    while(true) {
      obj="CP_"+Time[i];
      if(ObjectFind(obj) < 0 || ObjectGet(obj,OBJPROP_TIME1) < Time[iBar+iCandles+VerticalTextAdjustX])
        break;
      if(ObjectType(obj) == OBJ_TEXT) {
        if(h+dPadY > ObjectGet(obj,OBJPROP_PRICE2))
          ObjectSet(obj, OBJPROP_PRICE2, h+dPadY);
        if(l-dPadY < ObjectGet(obj,OBJPROP_PRICE3) || ObjectGet(obj,OBJPROP_PRICE3) == 0)
          ObjectSet(obj, OBJPROP_PRICE3, l-dPadY);
        MoveLabel(obj, dWndTop, dWndBot, dPriceMax, dPriceMin);
      }
      i++;
    }
    WindowRedraw(); // force redraw of current chart after moving of objects
  }
}

//+------------------------------------------------------------------+
//| Function..: MoveLabel                                            |
//| Purpose...: Move labels out of box if possible (if present) or   |
//|             above or below candles for more readable output.     |
//+------------------------------------------------------------------+
void MoveLabel(string obj, double dWndTop, double dWndBot, double dPriceMax, double dPriceMin) {
  int    x   =iBarShift(sSymbol,iPeriod,ObjectGet(obj,OBJPROP_TIME1))-VerticalTextAdjustX;
  double dHi =ObjectGet(obj,OBJPROP_PRICE2),
         dLo =ObjectGet(obj,OBJPROP_PRICE3),
         dLen=NormalizeDouble(VerticalTextFontSize/V_TXT_FONT_SIZE*ObjectGet(obj,OBJPROP_TIME2)*
              iScaleAdjustX/iScaleAdjustX_MN*(dWndTop-dWndBot)/iScaleAdjustY, Digits),
         dY;
         
  if(dHi != 0) {
    if(High[x] > dHi && High[x]+dLen < dPriceMax)
      dY=High[x]+dLen/2.0;
    else if(Low[x] < dLo && Low[x]-dLen > dPriceMin)
      dY=Low[x]-dLen/2.0;
    else if(dHi+dLen < dPriceMax)
      dY=dHi+dLen/2.0;
    else if(dLo-dLen > dPriceMin)
      dY=dLo-dLen/2.0;
  }         
  if(dY == 0) {
    if(dPriceMax-High[x] > Low[x]-dPriceMin)
      dY=High[x]+dLen/2.0;
    else
      dY=Low[x]-dLen/2.0;
  }
  ObjectMove(obj,0,Time[x+VerticalTextAdjustX],dY);          
}

//+------------------------------------------------------------------+
//| ObjectsDeletePrefixed                                            |
//+------------------------------------------------------------------+
void ObjectsDeletePrefixed(string sPrefix) {
  for(int i=ObjectsTotal()-1; i>=0; i--) {
    if(StringFind(ObjectName(i),sPrefix)==0) ObjectDelete(ObjectName(i));
  }
  Comment("");  
}

//+------------------------------------------------------------------+
//| Candle Pattern                                                   |
//+------------------------------------------------------------------+
int Pattern(int iBar) {
  double b, u, l;
  int    x=1, y=1, i, iPos;
    
  //------------------------------------------------------------------ Candle sizes:
  if(dSize[0]==CALC_ALL) {                                          // calculate average of all bars flag
    ArrayInitialize(dSize,0);
    x=2;
    y=iBars(sSymbol,iPeriod) - 2;
  } 
  for(i=x; i <= y; i++) {
    // Candle Body size
    b=MathAbs(iClose(sSymbol,iPeriod,i)-iOpen(sSymbol,iPeriod,i))*dPipsFactor;
    if(b > 0) {
      dSize[CandleBodyCount]+=1;
      dSize[CandleBodyTotal]+=b;
    }
    // Upper Shadow size
    b=(iHigh(sSymbol,iPeriod,i)-MathMax(iClose(sSymbol,iPeriod,i),iOpen(sSymbol,iPeriod,i)))*dPipsFactor;
    if(b > 0) {
      dSize[UpperShadowCount]+=1;
      dSize[UpperShadowTotal]+=b;
    }
    // Bottom Shadow size 
    b=(MathMin(iClose(sSymbol,iPeriod,i),iOpen(sSymbol,iPeriod,i))-iLow(sSymbol,iPeriod,i))*dPipsFactor;
    if(b > 0) {
      dSize[BottomShadowCount]+=1;
      dSize[BottomShadowTotal]+=b;
    }
  }
  // set Lower & Upper Thresholds of Candle Body
  if(dSize[CandleBodyCount] > 0) {
    // Candle Body Small (top threshold)
    dSize[SmallCandleBody]=dSize[CandleBodyTotal]*2/dSize[CandleBodyCount]*LT_FACTOR;
    // Candle Body Long (bottom threshold)
    dSize[LongCandleBody]=dSize[SmallCandleBody]*(1-LT_FACTOR)/LT_FACTOR;
  }
  // set Lower & Upper Thresholds of Upper Candle Shadows
  if(dSize[UpperShadowCount] > 0) {
    // Upper Shadow Small (top threshold)
    dSize[SmallUpperShadow]=dSize[UpperShadowTotal]*2/dSize[UpperShadowCount]*LT_FACTOR;
    // Upper Shadow Long (bottom threshold)
    dSize[LongUpperShadow]=dSize[SmallUpperShadow]*(1-LT_FACTOR)/LT_FACTOR;
  }
  // set Lower & Upper Thresholds of Lower Candle Shadows
  if(dSize[BottomShadowCount] > 0) {
    // Bottom Shadow Small (top threshold)
    dSize[SmallBottomShadow]=dSize[BottomShadowTotal]*2/dSize[BottomShadowCount]*LT_FACTOR;
    // Bottom Shadow Long (bottom threshold)
    dSize[LongBottomShadow]=dSize[SmallBottomShadow]*(1-LT_FACTOR)/LT_FACTOR;
  }
  // Determine what is "Very Near" for Candle Comparisons
  if(dSize[SmallCandleBody] > 30) iVeryNear=1; else iVeryNear=0;
  // state definition of "Very small" body
  if(dSize[SmallCandleBody] > 30) iVerySmallBody=1; else iVerySmallBody=0;
  //------------------------------------------------------------------ shuffle array elements down
  for(i=MAX_CANDLES-1; i>0; i--) {                                  // by 1 and save re-calculating
    O[i]=O[i-1];
    H[i]=H[i-1];
    L[i]=L[i-1];
    C[i]=C[i-1];
    B[i]=B[i-1];
    T[i]=T[i-1];
    candle[i]=candle[i-1];
  }
  //------------------------------------------------------------------ Load Prices converted to pips:
  if(candle[0]==CALC_ALL) y=MAX_CANDLES;                            // load all flag
  else                    y=1;
  for(i=0; i < y; i++) {
    O[i]=iOpen(sSymbol,iPeriod,iBar+i)*dPipsFactor;                 // Open
    H[i]=iHigh(sSymbol,iPeriod,iBar+i)*dPipsFactor;                 // High
    L[i]=iLow(sSymbol,iPeriod,iBar+i)*dPipsFactor;                  // Low
    C[i]=iClose(sSymbol,iPeriod,iBar+i)*dPipsFactor;                // Close
    B[i]=MathMin(O[i],C[i]);                                        // Bottom of candle body
    T[i]=MathMax(O[i],C[i]);                                        // Top of candle body
  }
  /*------------------------------------------------------------------ Determine base candle code number:
    |   H    H=High of candle
    |u       u=upper shadow size 
  *-*-* T    T=Top of candle body     Max(O, C) O=Open of candle, C=Close of candle
  |   |b     b=candle body size
  *-*-* B    B=Bottom of candle body  Min(O, C)
    |l       l=lower shadow size
    |   L    L=Low of candle
  */
    
  // candle body size
  b=T[0]-B[0];
  
  // upper shadow size
  u=H[0]-T[0];
  
  // lower shadow size                                                                                                                                                                                                                                                   
  l=B[0]-L[0];
    
  /* Determine binary code for each candle:

  | Bit 8             |    7   | 6 | 5 | 4 |   3   |   2  |   1  |   0   |
  *-------------------+--------+---*---*---+-------*------+------*-------*
  | Candle Check Type | Colour |    Body   | Upper Shadow | Lower Shadow | */

  // bit 8: two different checks are made to determine candle:
  // when bit8=0 then b/u/l (body, upper shadow or lower shadow) are defined by size & variable x is used,
  // when bit8=1 then b is defined by size, u & l are defined by comparison codes & variable y is used
  y=256;
  
  // bit 7: colour of the candle: 0=black/Doji, 1=white
  if(C[0] > O[0]) x=128;
  else            x=0;
  
  // bits 6-4: candle body code: 000=No body, 001=Very small, 010=Small, 011=Normal, 100=Long
  if(b >= dSize[LongCandleBody])       x+=64;
  else if(b >= dSize[SmallCandleBody]) x+=48;
  else if(b > iVerySmallBody)          x+=32;
  else if(b > 0)                       x+=16;
  
  // bits 3-2: upper shadow to Body relation: 01: 0 < u <= b, 10: b < u < 2b, 11: u >= 2b
  if(u >= 2*b)   y+=12;
  else if(u > b) y+= 8;
  else if(u > 0) y+= 4;
        
  // bits 1-0: lower shadow to Body relation: 01: 0 < l <= b, 10: b < l < 2b, 11: l >= 2b
  if(l >= 2*b)   y+=3;
  else if(l > b) y+=2;
  else if(l > 0) y+=1;
  
  // check if candle with bit8=1 matches
  iPos=ArrayBsearch(iBaseCandle,x+y);
  if(iBaseCandle[iPos][0] != x+y) {
    // bits 3-2: upper shadow size: 00=No shadow, 01=Small, 10=Normal, 11=Long
    if(u >= dSize[LongUpperShadow])        x+=12;
    else if(u >= dSize[SmallUpperShadow])  x+= 8;
    else if(u > 0)                         x+= 4;
    // bits 1-0: lower shadow size: 00=No shadow, 01=Small, 10=Normal, 11=Long
    if(l >= dSize[LongBottomShadow])       x+=3;
    else if(l >= dSize[SmallBottomShadow]) x+=2;
    else if(l > 0)                         x+=1;
    // check if candle with bit8=0 matches
    iPos=ArrayBsearch(iBaseCandle,x);
    if(iBaseCandle[iPos][0] != x) {
      candle[0]=TT_NO_PATTERN;
      return(TT_NO_PATTERN);
    }
  }
  candle[0]=iBaseCandle[iPos][1];
  //------------------------------------------------------------------ Determine trend:
  TrendUp=(iMA(sSymbol,iPeriod,TrendMA_Period,0,MODE_SMA,PRICE_CLOSE,iBar)-
           iMA(sSymbol,iPeriod,TrendMA_Period,0,MODE_SMA,PRICE_CLOSE,iBar+TrendMA_Shift)>0);
  TrendDn=!TrendUp;  
  //------------------------------------------------------------------ Candle pattern:
  switch(candle[0]) {
    case SmallBlackCandle:                                          // A
         // Bullish Homing Pigeon (2 candles)
         if(TrendDn && (candle[1]==LongBlackCandle) && (B[1]<B[0]) && (T[1]>T[0])) return(65);
         // Bearish Harami (2 candles)
         if(TrendUp && (candle[1]==LongWhiteCandle) && (T[1]>T[0]) && (B[1]<B[0])) return(36);
         // Small Black Candle (1 candle)
         return(9);
    case SmallWhiteCandle:                                          // L
         if(TrendDn) {
           // Bullish Unique 3 River Bottom (3 candles)
           if((candle[2]==LongBlackCandle) && (candle[1]==BlackHammerOrHangingMan) &&
             (L[1]<L[2]) && (T[1]<T[2]) && (B[1]>B[2]) && (T[0]<B[1])) return(71);
           // Bullish Harami (2 candles)
           if((candle[1]==LongBlackCandle) && (T[1]>T[0]) && (B[1]<B[0])) return(77);
           // Bearish In Neck (2 candles)
           if((candle[1]==LongBlackCandle) && (T[0]==B[1] || T[0]<=B[1]+iVeryNear)) return(38);
           // Bearish On Neck (2 candles)
           if((candle[1]==LongBlackCandle) && (T[0]==L[1] || T[0]==L[1]-iVeryNear)) return(39);
         }
         // Bearish Deliberation (3 candles)
         if(TrendUp && (candle[2]==LongWhiteCandle) && (candle[1]==LongWhiteCandle) &&
           (T[1]>T[2]) && (B[0]>=T[1])) return(29);
         // Small White Candle (1 candle)
         return(8);
    case BlackCandle:                                               // D
         if(TrendUp) {
           // Bullish Upside Gap 3 Methods (3 candles)
           if((candle[2]==LongWhiteCandle) && (candle[1]==LongWhiteCandle) && (T[2]<B[1]) &&
             (O[0]<T[1]) && (O[0]>B[1]) && (B[0]<T[2]) && (B[0]>B[2])) return(81);
           // Bullish Upside Tasuki Gap (3 candles)
           if((candle[2]==LongWhiteCandle) && (candle[1]==LongWhiteCandle) && (T[2]<B[1]) &&
             (O[0]<T[1]) && (O[0]>B[1]) && (B[0]<B[1]) && (B[0]>B[2])) return(82);
           // Bearish Abandoned Baby (3 candles)
           if((candle[2]==LongWhiteCandle) && (candle[1]==Doji || candle[1]==DojiSN || candle[1]==DojiSNL) &&
             (H[2]<L[1]) && (L[1]>T[0])) return(14);
           // Bearish Evening Star (3 candles)
           if((candle[2]==LongWhiteCandle) && (candle[1]==SmallBlackCandle || candle[1]==SmallWhiteCandle) &&
             (T[2]<B[1]) && (T[0]<B[1]) && (C[0]<T[2]) && (C[0]>B[2])) return(15);
           // Bearish Evening Doji Star (3 candles)
           if((candle[2]==WhiteCandle) && (candle[1]==Doji || candle[1]==DojiSN || candle[1]==DojiSNL) &&
             (T[2]<B[1]) && (B[1]>T[0]) && (B[0]<T[2]) && (B[0]>B[2])) return(16);
           // Bearish 3 Inside Down (3 candles)
           if((candle[2]==LongWhiteCandle) && (candle[1]==SmallBlackCandle) && (T[2]>T[1]) &&
             (B[2]<B[1]) && (B[0]<B[2])) return(18);
           // Bearish 3 Outside Down (3 candles)
           if((candle[2]==Doji || candle[2]==DojiSN || candle[2]==DojiSNL || candle[2]==SmallWhiteCandle) &&
             (candle[1]==LongBlackCandle) && (T[1]>T[2]) && (B[1]<B[2]) && (B[0]<B[1])) return(19);
           // Bearish Upside Gap 2 Crows (3 candles)
           if((candle[2]==LongWhiteCandle) && (candle[1]==BlackCandle) && (B[1]>T[2]) &&
             (T[0]>T[1]) && (B[0]<B[1]) && (B[0]>T[2])) return(20);
           // Bearish 2 Crows (3 candles)
           if((candle[2]==LongWhiteCandle) && (candle[1]==BlackCandle) && (B[1]>T[2]) &&
             (T[0]<T[1]) && (T[0]>B[1]) && (B[0]<T[2]) && (B[0]>B[2])) return(31);
           // Bearish Dark Cloud Cover (2 candles)
           if((candle[1]==LongWhiteCandle) && (T[1]<T[0]) && (B[0]<(T[1]+B[1])/2) && (B[0]>B[1])) return(12);
         }
         // Bullish Matching Low (2 candles)
         if(TrendDn && (candle[1]==LongBlackCandle) && ((B[0]==B[1]-iVeryNear) ||
           (B[0]==B[1]) || (B[0]==B[1]+iVeryNear))) return(66);
         // Black Candle (1 candle)
         return(11);
    case WhiteCandle:                                               // N
         if(TrendDn) {
           // Bullish Ladder Bottom (5 candles)
           if((candle[4]==LongBlackCandle) && (candle[3]==LongBlackCandle) &&
             (candle[2]==LongBlackCandle) && (candle[1]==BlackCandleDay4LadderBottom) &&
             (O[4]>O[3]) && (C[4]>C[3]) && (O[3]>O[2]) && (C[3]>C[2]) &&
             (B[2]>B[1]) && (T[1]<B[0])) return(73);
           // Bullish Abandoned Baby (3 candles)
           if((candle[2]==LongBlackCandle) && (O[1]==C[1]) && (L[2]>H[1]) && (H[1]<L[0])) return(52);
           // Bullish Morning Doji Star (3 candles)
           if((candle[2]==LongBlackCandle) && (O[1]==C[1]) &&
             (B[2]>T[1]) && (T[1]<B[0]) && (T[0]>B[2]) && (T[0]<T[2])) return(53);
           // Bullish Morning Star (3 candles)
           if((candle[2]==LongBlackCandle) &&
             ((candle[1]==SmallBlackCandle) || (candle[1]==SmallWhiteCandle)) &&
             (B[2]>T[1]) && (T[1]<B[0]) && (T[0]>B[2]) && (T[0]<T[2])) return(54);
           // Bullish 3 Inside Up (3 candles)
           if((candle[2]==LongBlackCandle) && (candle[1]==SmallWhiteCandle) &&
             (B[2]<B[1]) && (T[2]>T[1]) && (B[1]<B[0]) && (T[0]>T[2])) return(55);
           // Bullish 3 Outside Up (3 candles)
           if(((candle[2]==Doji) || (candle[2]==DojiSN) || (candle[2]==DojiSNL) ||
             (candle[2]==SmallBlackCandle)) && (candle[1]==LongWhiteCandle) &&
             (B[2]>B[1]) && (T[2]<T[1]) && (T[0]>T[1])) return(56);
           // Bearish Downside Gap 3 Methods (3 candles)
           if((candle[2]==LongBlackCandle) && (candle[1]==LongBlackCandle) &&
             (T[1]<B[2]) && (T[0]>B[2]) && (B[0]<T[1])) return(40);
           // Bearish Downside Tasuki Gap (3 candles)
           if((candle[2]==LongBlackCandle) && (candle[1]==LongBlackCandle) &&
             (B[2]>T[1]) && (B[0]<T[1] && B[0]>B[1]) && (T[0]>T[1] && T[0]<B[2])) return(41);
           // Bearish Side By Side White Lines (3 candles)
           if((candle[2]==BlackCandle) && (candle[1]==WhiteCandle) &&
             (B[2]>T[1]) && (B[0]<=B[1]+iVeryNear && B[0]>=B[1]-iVeryNear)) return(42);
           // Bearish Thrusting (2 candles)
           if((candle[1]==BlackCandle || candle[1]==LongBlackCandle) &&
             (B[0]<B[1]) && (T[0]>B[1] && T[0]<(T[1]+B[1])/2)) return(44);
         }
         if(TrendUp) {
           // Bullish Mat Hold (5 candles)
           if((candle[4]==LongWhiteCandle) &&
             ((candle[3]==SmallBlackCandle) || (candle[3]==SmallWhiteCandle)) &&
             ((candle[2]==SmallBlackCandle) || (candle[2]==SmallWhiteCandle)) &&
             ((candle[1]==SmallBlackCandle) || (candle[1]==SmallWhiteCandle)) &&
             (T[4]<B[3]) && (B[4]<B[2]) && (B[4]<B[1]) && (B[1]<B[0]) &&
             (B[3]>B[2]) && (B[2]>B[1]) && (H[4]<H[0]) && (H[3]<H[0]) &&
             (H[2]<H[0]) && (H[1]<H[0])) return(79);
           // Bullish Side By Side White Lines (3 candles)
           if((candle[2]==WhiteCandle) && (candle[1]==WhiteCandle) &&
             (T[2]<B[1]) && (T[1]==T[0]) && (B[1]==B[0])) return(78);
         }
         // White Candle (1 candle)
         return(10);
    case LongBlackCandle:                                           // K
         if(TrendUp) {
           // Bearish Breakaway (5 candles)
           if((candle[4]==LongWhiteCandle) && (candle[3]==WhiteCandle) &&
             (candle[2]==BlackCandle || candle[2]==WhiteCandle) && (candle[1]==WhiteCandle) &&
             (B[3]>T[4]) && (T[2]>T[3]) && (T[1]>T[2]) && (B[0]<B[3]) && (B[0]>T[4])) return(32);
           // Bullish 3 Line Strike (4 candles)
           if((candle[3]==LongWhiteCandle) && (candle[2]==LongWhiteCandle) &&
             (candle[1]==LongWhiteCandle) && (T[3]<T[2]) && (T[2]<T[1]) &&
             (T[1]<T[0]) && (B[0]<B[3])) return(84);
           // Bearish 3 Black Crows (3 candles)
           if((candle[2]==LongBlackCandle) && (candle[1]==LongBlackCandle) && (B[1]<B[2]) &&
             (B[0]<B[1]) && (T[1]<T[2]) && (T[1]>B[2]) && (T[0]<T[1]) && (T[0]>B[1])) return(17);
           // Bearish Dark Cloud Cover (2 candles)
           if((candle[1]==LongWhiteCandle) && (T[1]<T[0]) && (B[0]<(T[1]+B[1])/2) && (B[0]>B[1])) return(12);
           // Bearish Engulfing (2 candles)
           if((candle[1]==Doji || candle[1]==DojiSN || candle[1]==DojiSNL || candle[1]==SmallWhiteCandle) &&
             (T[0]>T[1]) && (B[0]<B[1])) return(23);
           // Bearish Meeting Lines (2 candles)
           if((candle[1]==LongWhiteCandle) && (B[0]<=T[1]+iVeryNear && B[0]>=T[1]-iVeryNear)) return(27);
         }
         // Bearish Falling 3 Methods (5 candles)
         if(TrendDn && (candle[4]==LongBlackCandle) &&
           (candle[3]==SmallBlackCandle || candle[3]==SmallWhiteCandle) &&
           (candle[2]==SmallBlackCandle || candle[2]==SmallWhiteCandle) && 
           (candle[1]==SmallBlackCandle || candle[1]==SmallWhiteCandle) &&
           (T[3]>B[4]) && (T[3]<T[4]) && (T[2]>B[4]) && (T[2]<T[4]) &&
           (T[1]>B[4]) && (T[1]<T[4]) && (T[2]>T[3]) && (T[1]>T[2]) &&
           (T[0]<T[1]) && (T[0]>B[1]) && (B[0]<B[4])) return(37);
         // Long Black Candle (1 candle)
         return(46);
    case LongWhiteCandle:                                           // R
         if(TrendDn) {
           // Bullish Breakaway (5 candles)
           if((candle[4]==LongBlackCandle) && (candle[3]==BlackCandle) &&
             ((candle[2]==BlackCandle) || (candle[2]==WhiteCandle)) && (candle[1]==BlackCandle) &&
             (B[4]>T[3]) && (T[3]>T[2]) && (B[3]>B[2]) && (T[2]>T[1]) &&
             (B[2]>B[1]) && (B[1]<B[0]) && (T[0]>T[3]) && (T[0]<B[4])) return(72);
           // Bearish 3 Line Strike (4 candles)
           if((candle[3]==LongBlackCandle) && (candle[2]==LongBlackCandle) &&
             (candle[1]==LongBlackCandle) && (B[3]>B[2]) && (B[2]>B[1]) &&
             (B[1]>B[0]) && (T[0]>T[3])) return(45);
           // Bullish 3 White Soldiers (3 candles)
           if((candle[2]==LongWhiteCandle) && (candle[1]==LongWhiteCandle) &&
             (T[2]<T[1]) && (B[2]<B[1]) && (T[2]>B[1]) && (T[1]<T[0]) &&
             (B[1]<B[0]) && (T[1]>B[0])) return(57);
           // Bullish Piercing Line (2 candles)
           if((candle[1]==LongBlackCandle) && (B[0]<L[1]) &&
             (((B[1]+T[1])/2 < T[0]) && (T[0] < T[1]))) return(50);
           // Bullish Engulfing (2 candles)
           if(((candle[1]==Doji) || (candle[1]==DojiSN) || (candle[1]==DojiSNL) ||
             (candle[1]==SmallBlackCandle)) && (B[1]>B[0]) && (T[1]<T[0])) return(61);
           // Bullish Meeting Lines (2 candles)
           if((candle[1]==LongBlackCandle) && ((T[0]==B[1]-iVeryNear) ||
             (T[0]==B[1]) || (T[0]==B[1]+iVeryNear))) return(67);
           // Bearish Thrusting (2 candles)
           if((candle[1]==BlackCandle || candle[1]==LongBlackCandle) &&
             (B[0]<B[1]) && (T[0]>B[1] && T[0]<(T[1]+B[1])/2)) return(44);
         }
         if(TrendUp) {
           // Bullish Rising 3 Methods (5 candles)
           if((candle[4]==LongWhiteCandle) &&
             ((candle[3]==SmallBlackCandle) || (candle[3]==SmallWhiteCandle)) &&
             ((candle[2]==SmallBlackCandle) || (candle[2]==SmallWhiteCandle)) &&
             ((candle[1]==SmallBlackCandle) || (candle[1]==SmallWhiteCandle)) &&
             (L[4]<L[3]) && (L[4]<L[2]) && (L[4]<L[1]) && (B[3]>B[2]) &&
             (B[2]>B[1]) && (B[1]<B[0]) && (T[4]<T[0]) && (T[3]<T[2]) &&
             (T[2]<T[0]) && (T[1]<T[0])) return(80);
           // Bearish Advance Block (3 candles)
           if((candle[2]==LongWhiteCandle) && (candle[1]==LongWhiteCandle) && (T[1]>T[2]) &&
             (T[0]>T[1]) && (B[1]>B[2]) && (B[1]<T[2]) && (B[0]>B[1]) && (B[0]<T[1]) &&
             ((T[2]-B[2])>(T[1]-B[1])) && ((T[1]-B[1])>(T[0]-B[0]))) return(28);
         }
         // Long White Candle (1 candle)
         return(85);
    case FourPriceDoji:                                             // 0
         return(0);
    case Umbrella_1:                                                // 1
         // Bullish Dragonfly Doji (1 candle)
         if(TrendDn) return(59);
         // Bearish Dragonfly Doji (1 candle)
         if(TrendUp) return(21);
         // Umbrella (1 candle)
         return(3);
    case Umbrella_2:                                                // 2
         // Umbrella (1 candle)
         return(3);
    case Doji:                                                      // 3
    case DojiSN:                                                    // 4
         if(TrendDn) {
           // Bullish Tri Star (3 candles)
           if(((candle[2]==Doji) || (candle[2]==DojiSN) || (candle[2]==DojiSNL)) &&
             ((candle[1]==Doji) || (candle[1]==DojiSN)) && (T[1]<B[2]) && (T[1]<B[0])) return(70);
           // Bullish Harami Cross (2 candles)
           if((candle[1]==LongBlackCandle) && (B[1]<B[0]) && (T[1]>T[0])) return(64);
           // Bullish Doji Star (2 candles)
           if((candle[0]!=DojiSNL) && (candle[1]==LongBlackCandle) && (B[1]>T[0])) return(63);
         }
         if(TrendUp) {
           // Bearish Tri Star (3 candles)
           if((candle[2]==Doji || candle[2]==DojiSN || candle[2]==DojiSNL) &&
             (candle[1]==Doji || candle[1]==DojiSN || candle[1]==DojiSNL) &&
             (B[1]>T[2]) && (B[1]>T[0])) return(30); 
           // Bearish Doji Star (2 candles)
           if((candle[1]==LongWhiteCandle) && (B[0]>T[1])) return(25);
           // Bearish Harami Cross (2 candles)
           if((candle[1]==LongWhiteCandle) && (T[1]>T[0]) && (B[1]<B[0])) return(26);
         }
         // Doji (1 candle)
         return(5);
    case DojiSNL:                                                   // 5
         if(TrendDn) {
           // Bullish Tri Star (3 candles)
           if(((candle[2]==Doji) || (candle[2]==DojiSN) || (candle[2]==DojiSNL)) &&
             ((candle[1]==Doji) || (candle[1]==DojiSN)) && (T[1]<B[2]) && (T[1]<B[0])) return(70);
           // Bullish Harami Cross (2 candles)
           if((candle[1]==LongBlackCandle) && (B[1]<B[0]) && (T[1]>T[0])) return(64);
           // Bullish Doji Star (2 candles)
           if((candle[0]!=DojiSNL) && (candle[1]==LongBlackCandle) && (B[1]>T[0])) return(63);
         }
         if(TrendUp) {
           // Bearish Tri Star (3 candles)
           if((candle[2]==Doji || candle[2]==DojiSN || candle[2]==DojiSNL) &&
             (candle[1]==Doji || candle[1]==DojiSN || candle[1]==DojiSNL) &&
             (B[1]>T[2]) && (B[1]>T[0])) return(30);
           // Bearish Harami Cross (2 candles)
           if((candle[1]==LongWhiteCandle) && (T[1]>T[0]) && (B[1]<B[0])) return(26);
         }
         // Doji (1 candle)
         return(5);
    case InvertedUmbrella_6:                                        // 6
         // Bullish Gravestone Doji (2 candles)
         if(TrendDn && (candle[1]==BlackCandle) && (B[2]>B[1]) && (T[1]>T[0])) return(62);
         // Bearish Gravestone Doji (2 candles)
         if(TrendUp && (candle[1]==WhiteCandle) && (T[1]>T[2]) && (B[0]>T[1])) return(24);
         // Inverted Umbrella (1 candle)
         return(4);   
    case InvertedUmbrella_U:                                        // U
    case InvertedUmbrella_V:                                        // V
         // Bullish Gravestone Doji (2 candles)
         if(TrendDn && (candle[1]==BlackCandle) && (B[2]>B[1]) && (T[1]>T[0])) return(62);
         break;
    case InvertedUmbrella_7:                                        // 7
         // Inverted Umbrella (1 candle)
         return(4);
    case LongLeggedDoji_8:                                          // 8
    case LongLeggedDoji_9:                                          // 9
         // Bullish Long Legged Doji (1 candle)
         if(TrendDn && (T[0]<B[1])) return(60);
         // Bearish Long Legged Doji (1 candle)
         if(TrendUp && (B[0]>T[1])) return(22);
         // Long Legged Doji (1 candle)
         return(2);
    case HighWave:                                                  // B
         return(1);
    case BlackSpinningTop:                                          // C
         return(7);
    case BlackCandleDay4LadderBottom:                               // E
    case BlackDay3ConcealBabySwallow:                               // F
         // Black Candle (1 candle)
         return(11);
    case BlackMarubozu:                                             // G
         // Bullish Concealing Baby Swallow (4 candles)
         if(TrendDn && (candle[3]==BlackMarubozu) && (candle[2]==BlackMarubozu) &&
           (candle[1]==BlackDay3ConcealBabySwallow) && (B[3]>B[2]) &&
           (B[2]>T[1]) && (H[1]>B[2]) && (H[1]<T[2]) && (B[0]<L[1]) && (T[0]>H[1])) return(58);
         // Bullish 3 Star in the South (3 candles)
         if(TrendDn && (candle[2]==BlackOpeningMarubozuLongshadow) &&
           (candle[1]==BlackOpeningMarubozu) && (O[1]>C[2]) &&
           (L[1]>L[2]) && (H[0]<H[1]) && (L[0]>L[1])) return(69);
         // Bearish Kicking Pattern (2 candles)
         if((candle[1]==WhiteMarubozu) && (B[1]>T[0])) return(13);
         // Black Marubozu (1 candle)
         return(47);
    case BlackOpeningMarubozu:                                      // H
    case BlackOpeningMarubozuLongshadow:                            // I
         // Bearish Seperating Lines (2 candles)
         if(TrendDn && (candle[1]==LongWhiteCandle) &&
           (T[0]<=B[1]+iVeryNear && T[0]>=B[1]-iVeryNear)) return(43);
         // Bearish Belt Hold (1 candle)
         if(TrendUp && (B[0]>T[1])) return(33);
         // Black Opening Marubozu (1 candle)
         return(49);
    case BlackClosingMarubozu:                                      // J
         // Bullish Stick Sandwich (3 candles) 
         if(TrendDn && (candle[2]==BlackClosingMarubozu) && (candle[1]==WhiteCandle) &&
           (B[2]<B[1]) && (B[0]==B[2])) return(68);
         // Black Closing Marubozu (1 candle)
         return(48);
    case WhiteSpinningTop:                                          // M
         // Bearish Deliberation (3 candles)
         if(TrendUp && (candle[2]==LongWhiteCandle) && (candle[1]==LongWhiteCandle) &&
           (T[1]>T[2]) && (B[0]>=T[1])) return(29);
         // White Spinning Top (1 candle)
         return(6);
    case WhiteMarubozu:                                             // O
         // Bullish Kicking Pattern (2 candles)
         if((candle[1]==BlackMarubozu) && (H[1]<L[0])) return(51);
         // White Marubozu (1 candle)
         return(86);   
    case WhiteClosingMarubozu:                                      // P
         // White Closing Marubozu (1 candle)
         return(87); 
    case WhiteOpeningMarubozu:                                      // Q
         // Bullish Seperating Lines (2 candles)
         if(TrendUp && (candle[1]==LongBlackCandle) && 
           (B[0]<=T[1]+iVeryNear && B[0]>=T[1]-iVeryNear)) return(83);
         // Bullish Belt Hold (1 candle)
         if(TrendDn && (B[1]>T[0])) return(74);
         // White Opening Marubozu (1 candle)
         return(88);
    case BlackHammerOrHangingMan:                                   // S
    case WhiteHammerOrHangingMan:                                   // T
         // Bullish Hammer (1 candle)
         if(TrendDn && (B[1]>T[0])) return(75);
         // Bearish Hanging Man (1 candle)
         if(TrendUp && (B[0]>T[1])) return(34);
         break;              
    case BlackInvertedHammerOrStar:                                 // W
    case WhiteInvertedHammerOrStar:                                 // X
         // Bullish Inverted Hammer (2 candles)
         if(TrendDn && (candle[1]==BlackCandle) && (B[1]>T[0])) return(76);
         // Bearish Shooting Star (2 candles)
         if(TrendUp && (candle[1]==WhiteCandle) && (B[0]>T[1])) return(35);
         break;
    default: break; 
  }
  return(TT_NO_PATTERN);
}  

//+------------------------------------------------------------------+
//| PatternConfirm(iPreviousPatternNumber)                           |
//+------------------------------------------------------------------+
void PatternConfirm(int x) {
  string sMsg="";
  
  // check if previous pattern trend forecast can be confirmed
  if(ConfirmPattern && (x != TT_NO_PATTERN) && (sPattern[x][P_DISPLAY] == "1")) {
    if(sPattern[x][P_CHK] == "0") sMsg=M_NULL;
    // check 1: Lower Close
    else if(sPattern[x][P_CHK] == "1" && (C[0] < C[1])) sMsg=M_DN;
    // check 2: Black Candle or Lower Close
    else if(sPattern[x][P_CHK] == "2" && (C[0] < O[0] || C[0] < C[1])) sMsg=M_DN;
    //check 3: Black Candle && Lower Close
    else if(sPattern[x][P_CHK] == "3" && (C[0] < O[0] && C[0] < C[1])) sMsg=M_DN;
    //check 4: Lower Open OR Black Candle && Lower Close
    else if(sPattern[x][P_CHK] == "4" && (O[0] < O[1] || (C[0] < O[0] && C[0] < C[1]))) sMsg=M_DN;
    // check 5: White Candle or Higher Close
    else if(sPattern[x][P_CHK] == "5" && (C[0] > O[0] || C[0] > C[1])) sMsg=M_UP;
    // check 6: White Candle && Higher Close
    else if(sPattern[x][P_CHK] == "6" && (C[0] > O[0] && C[0] > C[1])) sMsg=M_UP;
    // check 7: Higher Open OR White Candle && Higher Close
    else if(sPattern[x][P_CHK] == "7" && (O[0] > O[1] || (C[0] > O[0] && C[0] > C[1]))) sMsg=M_UP;
    // check 8: Opposite move to the one which occured on the previous day, trend up then reverse down
    else if(sPattern[x][P_CHK] == "8" && (C[1] > O[1] && C[0] < O[0])) sMsg=M_REV_DN;
    // check 8: Opposite move to the one which occured on the previous day, trend down then reverse up      
    else if(sPattern[x][P_CHK] == "8" && (C[1] < O[1] && C[0] > O[0])) sMsg=M_REV_UP;
    else sMsg=M_NULL;
    if((sMsg != M_NULL) && (MaxBarsToScanForPatterns == 1)) {
      DisplayLabelObject("CP_CONFIRM_PRIOR_TREND", sPRV, ColorText);
      DisplayLabelObject("CP_CONFIRM_RELEVANCE"  , sREE, ColorText);
    }
    if(sMsg != M_NULL && AudioON) gSpeak(StringConcatenate(sAudio,sPattern[iPattern][P_NAM]," ",sMsg));
  }
}

//+------------------------------------------------------------------+
//| PriceMaxVisible()                                                |
//+------------------------------------------------------------------+
double PriceMaxVisible() {
  int iCount=WindowBarsPerChart(),
      iStart=MathMax(WindowFirstVisibleBar()-iCount,1),
      iPriceMax=iHighest(NULL,0,MODE_HIGH,iCount,iStart);
  return(High[iPriceMax]);
}

//+------------------------------------------------------------------+
//| PriceMinVisible()                                                |
//+------------------------------------------------------------------+
double PriceMinVisible() {
  int iCount=WindowBarsPerChart(),
      iStart=MathMax(WindowFirstVisibleBar()-iCount,1),
      iPriceMin=iLowest(NULL,0,MODE_LOW,iCount,iStart);
  return(Low[iPriceMin]);
}

//+------------------------------------------------------------------+
//| StringArrayLoad()                                                |
//+------------------------------------------------------------------+
int StringArrayLoad(string sFile, string& A[][], int iColumns) 
  {
    int handle = FileOpen(sFile, FILE_CSV|FILE_READ, ";"), i, iStart, iPos;
//----
    if(handle < 1) 
      {
        Alert("File:", sFile, " error "+GetLastError());
        return(-1);
      }
    string sLine;
    int iRows = ArrayRange(A,0), iLinesRead = 0;
//----
    while(FileIsEnding(handle) == false) 
      {
        sLine = FileReadString(handle);
        iStart = StringLen(sLine);
        //----
        if(iStart < 1 || StringSubstr(sLine,0,2) == "//") 
            continue; // empty strings or comment lines dropped
        //----
        if(iLinesRead >= iRows) 
          {
            if(ArrayResize(A,iRows+1) == 0 ) 
              {
                Alert("StringArrayLoad() error ", GetLastError());
                return(-1);
              }
            iRows += 1;
          }
        //----
        if(StringFind(sLine, ",,", 0) >= 0 || StringSubstr(sLine, iStart - 1, 1) == ",") 
          {
            Alert("File:", sFile, " Line:", iLinesRead, " NULL value");
            break;
          }
        sLine = sLine + ",";
        iStart = 0;
        //----
        for(i = 0; i < iColumns; i++) 
          {
            iPos = StringFind(sLine, ",", iStart);
            A[iLinesRead][i] = StringSubstr(sLine, iStart, iPos - iStart);
            iStart = iPos + 1;
          }
        iLinesRead++;
      }
    FileClose(handle);
    return (iLinesRead);
  }
//+------------------------------------------------------------------+

Comments