//+------------------------------------------------------------------+
//|                                         PIN Bar Locator v5.8.mq4 |
//|                                         Copyright © 2012, gib768 |
//|                                             Email: gib@gmail.com |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2012, gib768"
#property link      "http://www.metaquotes.net"

#property indicator_chart_window

#import "kernel32.dll"
   int GetTimeZoneInformation(int& a0[]);
#import


#define VERSION      "5.8"

#define TICKS       "IIIIIIIIII"
#define CLOCKS      "Â·¸¹º»¼½¾¿ÀÁÂ·¸¹º»¼½¾¿ÀÁ"     // clock icons
#define UP          0                  // Trend UP
#define DOWN        1                  // Trend DOWN
#define RANGING     2                  // Trend RANGING
#define TIME_URL    "http://tycho.usno.navy.mil/cgi-bin/timer.pl"    // from here we get the UTC time

//---- input parameters
extern bool      MarkDoubleTops=true;
extern bool      MarkDoubleBottoms=true;
extern bool      MarkPinBars=true;
extern int       PinBarBodySizePercent=15;
extern bool      MarkDoji=true;
extern bool      DisplayInfo=true;                 // display 15m, 1h, 4h and daily trend, spread and bar time left
extern bool      ShowSteepness=true;            // display steepness for 10EMA


//---- global variables
int tickpos=0;         // pointer for the tickbar
int trend15m, trend30m, trend1h, trend4h, trend1d;      // trends for the EMA 30/50
color trendcolor[3] = { Green, Red, DimGray };    // colors for trend arrows
string trendarrow[3] = { "ñ", "ò", "ó"};
int trendXcorrection[3] = { 0, 1, 1};
int GMTlocaloffset=0;                    // holds the GMT offset in hours
int GMTbrokeroffset=0;                    // holds the GMT offset of the broker

datetime localtime;        // local computer time 
datetime gmttime;          // GMT Time
datetime brokertime;       // broker time

int GMTlocal() {
   int tz[43];
   switch (GetTimeZoneInformation(tz)) {
      case 0: return (NormalizeDouble(tz[0] / (-60.0),0));
      case 1: return (NormalizeDouble(tz[0] / (-60.0),0));
      case 2: return (NormalizeDouble((tz[0] + tz[42]) / (-60.0),0));
   }
   return (0);
}


int GMTbroker() {
   int tdiff = (TimeCurrent() - TimeLocal()) / 60;
   int off = MathRound(tdiff / 30.0);
   tdiff = 30 * off;
   return (GMTlocal() + tdiff / 60.0);
}


void ShowInfo() {
   double spread;
   datetime bartimeleft;
   int Y=0;
   color trendcol=DimGray;
   string time;
   
   UpdateTimes();       // sync clocks
   Write("Info01", 0,  0, "ggggggggggggg", 16, LightGray, "Webdings");
   Write("Div01", 0, 12, "__________________________________", 11, Gray);
   for (int i=0;i<6;i++)
      Write("Info1"+i, 0, 22+21*i, "ggggggggggggg", 16, WhiteSmoke, "Webdings");
   Write("Div02", 0, 139,"__________________________________", 11, Gray);
   Write("Info20", 9, 5, "PIN Bar Locator v"+VERSION, 11, Silver, "Arial");
   Write("Info21", 8, 4, "PIN Bar Locator v"+VERSION, 11, Navy, "Aril");
   Write("Ticker", 232,3, StringSubstr(TICKS, 0, tickpos), 11, Green, "Impact");
   tickpos++; if (tickpos>StringLen(TICKS)-1) tickpos=1;
   
   // show time and GMT informations
   Write("Time01", 30,26, StringSubstr(CLOCKS, TimeHour(localtime), 1), 30, DimGray, "Wingdings");
   Write("Time02", 118,26,StringSubstr(CLOCKS, TimeHour(gmttime), 1), 30, Black, "Wingdings");
   Write("Time03", 206,26,StringSubstr(CLOCKS, TimeHour(brokertime),1), 30, DimGray, "Wingdings");
   Write("Time11", 33,66, TimeToStr(localtime, TIME_MINUTES), 9, DimGray, "Arial");
   Write("Time12",120,66, TimeToStr(gmttime, TIME_MINUTES), 9, Black, "Arial");
   Write("Time13",209,66, TimeToStr(brokertime, TIME_MINUTES), 9, DimGray, "Arial");
   if (localtime>gmttime) time="+"; else time="-";
   Write("Time21",12, 80, "Local (GMT"+time+GMTlocaloffset+")", 8, SlateGray, "Arial");
   Write("Time22",123,80, "GMT", 8, SlateGray, "Arial");
   if (brokertime>gmttime) time="+"; else time="-";
   Write("Time23",186,80, "Broker (GMT"+time+GMTbrokeroffset+")", 8, SlateGray, "Arial");
   Write("Time24", 0, 88,"__________________________________", 11, Gray);
   
   Y=Y+84;
   // show trends          012345678901234567890123456789
   Write("Info22", 120,28+Y, "15m  30m  1h  4h  1d", 9, SlateGray);
   if (trend15m == trend30m && trend30m == trend1h && trend1h == trend4h && trend4h == trend1d)
      trendcol = trendcolor[trend15m];
   Write("Info23", 8, 39+Y, "EMA Trend:", 10, trendcol, "Arial");
   Write("Trend15m", 122, 40+trendXcorrection[trend15m]+Y, trendarrow[trend15m], 11, trendcolor[trend15m], "Wingdings");
   Write("Trend30m",156, 40+trendXcorrection[trend30m]+Y, trendarrow[trend30m], 11, trendcolor[trend30m], "Wingdings");
   Write("Trend1h",190, 40+trendXcorrection[trend1h]+Y, trendarrow[trend1h], 11, trendcolor[trend1h], "Wingdings");
   Write("Trend4h",218, 40+trendXcorrection[trend4h]+Y, trendarrow[trend4h], 11, trendcolor[trend4h], "Wingdings");
   Write("Trend1d",246, 40+trendXcorrection[trend1d]+Y, trendarrow[trend1d], 11, trendcolor[trend1d], "Wingdings");
}


void UpdateTimes() {
   localtime = TimeLocal();
   if (GMTlocaloffset>0) gmttime= localtime-(GMTlocaloffset*3600);
      else gmttime = localtime+(GMTlocaloffset*3600);
   brokertime = TimeCurrent();
}


void UpdateTrends() {
   double ema35, ema50, price;
   
   // get SMA + EMA for M15
   ema35 = iMA(NULL, PERIOD_M15, 35, 0, MODE_EMA, PRICE_CLOSE, 0);
   ema50 = iMA(NULL, PERIOD_M15, 50, 0, MODE_EMA, PRICE_CLOSE, 0);
   price = iClose(NULL, PERIOD_M15, 0);
   if (price > ema35 && price > ema50) trend15m = UP;
   else if (price < ema35 && price < ema50 ) trend15m = DOWN;
   else trend15m = RANGING;
   
   // get SMA + EMA for M30
   ema35 = iMA(NULL, PERIOD_M30, 35, 0, MODE_EMA, PRICE_CLOSE, 0);
   ema50 = iMA(NULL, PERIOD_M30, 50, 0, MODE_EMA, PRICE_CLOSE, 0);
   price = iClose(NULL, PERIOD_M30, 0);
   if (price > ema35 && price > ema50) trend30m = UP;
   else if (price < ema35 && price < ema50 ) trend30m = DOWN;
   else trend30m = RANGING;

   // get SMA + EMA for H1
   ema35 = iMA(NULL, PERIOD_H1, 35, 0, MODE_SMA, PRICE_CLOSE, 0);
   ema50 = iMA(NULL, PERIOD_H1, 50, 0, MODE_EMA, PRICE_CLOSE, 0);
   price = iClose(NULL, PERIOD_H1, 0);
   if (price > ema35 && price > ema50) trend1h = UP;
   else if (price < ema35 && price < ema50 ) trend1h = DOWN;
   else trend1h = RANGING;

   // get SMA + EMA for H4
   ema35 = iMA(NULL, PERIOD_H4, 35, 0, MODE_EMA, PRICE_CLOSE, 0);
   ema50 = iMA(NULL, PERIOD_H4, 50, 0, MODE_EMA, PRICE_CLOSE, 0);
   price = iClose(NULL, PERIOD_H4, 0);
   if (price > ema35 && price > ema50) trend4h = UP;
   else if (price < ema35 && price < ema50 ) trend4h = DOWN;
   else trend4h = RANGING;
      
   // get SMA + EMA for D1
   ema35 = iMA(NULL, PERIOD_D1, 35, 0, MODE_EMA, PRICE_CLOSE, 0);
   ema50 = iMA(NULL, PERIOD_D1, 50, 0, MODE_EMA, PRICE_CLOSE, 0);
   price = iClose(NULL, PERIOD_D1, 0);
   if (price > ema35 && price > ema50) trend1d = UP;
   else if (price < ema35 && price < ema50 ) trend1d = DOWN;
   else trend1d = RANGING;
}


void CheckPerfectPinBars(int shift) {
   if (Open[shift+1] == Close[shift+1]) {
//      if ( (Open[shift+1] <= Open[shift+2] && Open[shift+1] >= Close[shift+2]) || (Open[shift+1] >= Open[shift+2] && Open[shift+1] <= Close[shift+2]))
      if ( Open[shift+2] < Close[shift+2] )        // short candle
         ShowPinBar(shift);
         
      else if ( Open[shift+2] > Close[shift+2] )   // long candle
         ShowPinBar(shift);
   }
}


void CheckPinBars (int shift) {
   int size;
   double y;
   if (shift <1) return (0);
   size = MeasurePercentBodySize(shift);
   if (size <= PinBarBodySizePercent && size != 0) {
      ObjectCreate("Pinbar"+shift, OBJ_TEXT, 0, Time[shift], Low[shift]+(1*Point));
      ObjectSet("Pinbar"+shift, OBJPROP_BACK, true);
      ObjectSetText("Pinbar"+shift, "l", 8, "Wingdings", Black);
   }
}


int MeasurePercentBodySize(int shift) {       // measure the size of the body of the whole candle in percent
   double candlesize, bodysize, diff;
   candlesize=(High[shift]-Low[shift])/Point;      // get total candle size
   bodysize=(Open[shift]-Close[shift])/Point;      // get candle body size
   if (bodysize <0) bodysize *= -1;               // make sure, the body size is positive
   if (bodysize == 0 || candlesize == 0) return (0);
   return (NormalizeDouble(MathRound((bodysize/candlesize)*100),0));
}


bool CheckDoubleTop(int shift) {
   double bar2, bar1;
   bar2 = High[shift+2];      // high bar -2
   bar1 = High[shift+1];      // high bar -1
   if (bar2 == bar1) {
      ShowDoubleTop(shift);
   }
}


void CheckDoubleBottom(int shift) {
   double bar2, bar1;
   bar2 = Low[shift+2];      // low bar -2
   bar1 = Low[shift+1];      // low bar -1
   if (bar2 == bar1) {
      ShowDoubleBottom(shift);
   }
}


void ShowDoubleTop(int shift) {
   double X = High[shift+2]+(15*Point/10);
   ObjectCreate("DoubleTop"+shift, OBJ_RECTANGLE, 0, Time[shift+2], X, Time[shift+1], X);
   ObjectSet("DoubleTop"+shift, OBJPROP_BACK, false); // don't draw in background
   ObjectSet("DoubleTop"+shift, OBJPROP_WIDTH, 3); // thick line ;-)
   ObjectSet("DoubleTop"+shift, OBJPROP_COLOR, Blue); 
}


void ShowDoubleBottom(int shift) {
   double X = Low[shift+2]-(15*Point/10);
   ObjectCreate("DoubleBottom"+shift, OBJ_RECTANGLE, 0, Time[shift+2], X, Time[shift+1], X);
   ObjectSet("DoubleBottom"+shift, OBJPROP_BACK, false); // don't draw in background
   ObjectSet("DoubleBottom"+shift, OBJPROP_WIDTH, 3); // thick line ;-)
   ObjectSet("DoubleBottom"+shift, OBJPROP_COLOR, Blue); 
}


void ShowPinBar(int shift) {   
   if (ObjectFind("Doji"+shift) != -1) ObjectDelete("Doji"+shift);
   ObjectCreate("Doji"+shift, OBJ_ELLIPSE, 0, Time[shift+1], High[shift+1], Time[shift+1], Low[shift+1]);
   ObjectSet("Doji"+shift, OBJPROP_SCALE, 0.7);
   ObjectSet("Doji"+shift, OBJPROP_COLOR, White);
   ObjectSet("Doji"+shift, OBJPROP_WIDTH, 4);
   ObjectSet("Doji"+shift, OBJPROP_BACK, true);
}

void Write(string name, int x, int y, string text, int size, color col, string font="Lucida Console") {
   if (ObjectFind(name)==-1) ObjectCreate(name, OBJ_LABEL, 0, 0, 0);
   ObjectSetText(name, text, size, font, col);
   ObjectSet(name, OBJPROP_CORNER, 0);
   ObjectSet(name, OBJPROP_BACK, false);
   ObjectSet(name, OBJPROP_XDISTANCE, x);
   ObjectSet(name, OBJPROP_YDISTANCE, y);
}

void CleanUp() {
   ObjectsDeleteAll(0);
}

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init() {
   Print("PIN Bar Locator v"+VERSION+" loaded.");
   if(IsDllsAllowed()==false) {
      Alert("DLL calls are not allowed. Please enable DLL in MT4");
      return(0);
   }
   CleanUp();
   GMTlocaloffset=GMTlocal();
   GMTbrokeroffset=GMTbroker();
   return(0);
}


//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit() {
   CleanUp();
   return(0);
}


//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start() {
   int    limit;
   int    counted_bars=IndicatorCounted();

   //---- last counted bar will be recounted
   if(counted_bars<0) return (-1);
   if(counted_bars>0) counted_bars--;
   limit=Bars-counted_bars;
   if (limit > 10000) limit = 10000;
   
   UpdateTrends();
   
   for (int i=0; i<limit; i++) {                        // process all bars in the chart
      if (MarkDoubleTops) CheckDoubleTop(i);           // detect double tops
      if (MarkDoubleBottoms) CheckDoubleBottom(i);      // detect double bottoms
      if (MarkDoji) CheckPerfectPinBars(i);                 // show doji bars
      if (MarkPinBars) CheckPinBars(i);
      if (DisplayInfo) ShowInfo();     
   }
   return(0);
  }
//+------------------------------------------------------------------+