//===================================================================================================
// Instructions on how to use FFCal.mq4 library function to make your EA avoid trading around News
// 2013-08-23 by Capella at http://worldwide-invest.org/
// Note: Each instruction is numbered, starting with 1, etc.
//
// 1) Copy FFCal.mq4 to /expert/indicators and compile it to ex4
//
// 2) Add the following sections at the top before any declarations 

// -------- This import a Windows DLL-function used to fetch your timezone ----------------------
#import "kernel32.dll"
   int GetTimeZoneInformation (int& a0[]);
#import
//------------------------------------------------------------------------------------------------

// ------- This module that contains Internet-related functions used by Windows application ----------
#import "wininet.dll"
	#define INTERNET_FLAG_PRAGMA_NOCACHE    0x00000100 // Forces the request to be resolved by the origin server, even if a cached copy exists on the proxy.
	#define INTERNET_FLAG_NO_CACHE_WRITE    0x04000000 // Does not add the returned entity to the cache. 
	#define INTERNET_FLAG_RELOAD            0x80000000 // Forces a download of the requested file, object, or directory listing from the origin server, not from the cache.
	int InternetOpenA (string sAgent, int lAccessType, string sProxyName = "",	string sProxyBypass = "", int lFlags = 0);
	int InternetOpenUrlA (int hInternetSession, string sUrl, string sHeaders = "", int lHeadersLength = 0, int lFlags = 0, int lContext = 0);
	int InternetReadFile (int hFile, string sBuffer, int lNumBytesToRead,	int& lNumberOfBytesRead[]);
	int InternetCloseHandle (int hInet);
#import
//-------------------------------------------------------------------------------------------------

// 3) Add the following section of declaration at the end of your other EXTERNALs -----------------------

//----- News filter setup contains 2 news filters (Use_TSD_News_Filter) for 8 majors and (UseFFNewsFilter) for any currency --------- 

//extern int here and above is your other externals constants and variables...
extern string  I_ = "GMT Offset";               // Automatic or Manual GMT-Offset calculation
extern bool    Use_Auto_GMT_Offset = TRUE;   	// Should be set to FALSE during backtests
extern int     Manual_GMT_Offset = 0;				// Hours your broker server is from GMT/UTC
extern string  I__ = "News filter for this chart";// A news filter that uses FFCal indicator to check for news for the 2 currencies on this chart
extern bool    Use_FF_News_Filter = FALSE;		// A News filter that uses FFCal-indicator for the currencies on the current chart
extern int     MinsBeforeNews = 60; 				// How many minutes before news to wait news from any currency
extern int     MinsAfterNews  = 30;					// How many minutes after news to wait news from any currency
extern int     NewsImpact = 3;						// News impact, where 1 = Low, 2 = Medium, 3 = High. Default = 3
extern string  I___ = "8 Currency News filter";	// TSD News filter
extern bool    Use_TSD_News_Filter = TRUE;   	// News filter function News() which does NOT use FFCal at covers news for all 8 majors
extern bool    High_Impact = TRUE; 					// News have 3 impacts, Low, Medium or High
extern int     MinsUntilNextHighNews = 90;		// How many minutes before news to wait when High News
extern int     MinsSincePrevHighNews = 90;		// How many minutes after news to wait when High News
extern bool    Medium_Impact = TRUE;				// News have 3 impacts, High, Medium and Low
extern int     MinsUntilNextMediumNews = 90; 	// How many minutes before news to wait when Medium News
extern int     MinsSincePrevMediumNews = 90; 	// How many minutes after news to wait when Medium News
extern bool    Low_Impact = FALSE;					// News have 3 impacts, High, medium and Low. Low impacts are normally not considered
extern int     MinsUntilNextLowNews = 60;			// How many minutes before news to wait when Low News
extern int     MinsSincePrevLowNews = 60;			// How many minutes after news to wait when Low News
extern string  I____ = "Currencies to Filter";	// Select the Currency which News should be filtered for
extern bool    USD = TRUE;								// Should be set to TRUE to check for news for this currency, otherwise FALSE
extern bool    EUR = FALSE;							// -"-
extern bool    GBP = FALSE;							// -"-					
extern bool    JPY = FALSE;							// -"-
extern bool    AUD = FALSE;							// -"-
extern bool    CAD = FALSE;							// -"-
extern bool    CHF = FALSE;							// -"-
extern bool    NZD = FALSE;							// -"-
extern string 	I_____ = "TSD Calendar";			// News calendar for the 8 currency filter
extern int     TSD_CalendarID = 4;  				// TSD News Calendar ID reference on the TSD Homepage
extern string  TSD_Calendar_URL = "http://calendar.forex-tsd.com/calendar.php?csv=1&date=";  // URL for fetching News calendar


// 4) Add the following global declarations at the end of your other global ditto ------------

//int your global variables are listed here and above
int hSession_IEType;
int hSession_Direct;
int Internet_Open_Type_Preconfig = 0;
int Internet_Open_Type_Direct = 1;
int Internet_Open_Type_Proxy = 3;
int Buffer_LEN = 80;
int NewsTotal;
int NewsRatings[1000];
double GMTOffset = 0;
string TSDNews;
string FFNews;
datetime NewsTimes[1000];
datetime dtBarTime;


// 5) In your start() function, the following code should be added...

void start()
{
   string space = "";   // used to format numbers
	bool TimeToTrade = TRUE;  // We assume that it's time to trade
	// add your local variable declarations for your start() function here
	
   if (Use_Auto_GMT_Offset) 
	{
      if (!IsTesting() && !IsOptimization() && !IsVisualMode()) 
			GMTOffset = GetGMTOffset();
      else 
			GMTOffset = Manual_GMT_Offset;
   }
   else 
		GMTOffset = Manual_GMT_Offset;
		
	// Check with Newsfilter if it's still ok to trade. NewsTIme check news for ANY currency, while News() check specific currencies
   if (NewsTime() || News()) 	// if either NewsTime OR News signals that we have news (True) then it's not time to trade
		TimeToTrade = FALSE;		

	// if you have other instructions that should be executed every tick, then place it here, for instance
	Print ("Awaiting news...");
	// finding trading signals, sending OrderModify commands
		
	if (TimeToTrade == TRUE)
	{
		// Insert your market or pending order instructions that you have in your current start() here
		Print ("It's now OK to send order as there are no important news...");
	}	
		
   // Print out some info at the upper left corner
   if (Minute() < 10) 
      space = "0";
   Comment ("GMT Time   : ",DoubleToStr(MathMod(24 + Hour() - GMTOffset, 24), 0) + ":" + space + Minute(),"\n",
   "GMT Offset : ", GMTOffset, "\n", "TSD News   : ", TSDNews, "\n", "FF  News   : ",FFNews,"\n");	

}

// 6 Your init() and deinit() functions should be placed below here
void init()
{
	//
}

void deinit()
{
	//
}

// 6) Add the following functions to the end of your EA

//--------------------------- Calculate GMT Offset hours --------------------
double GetGMTOffset() 
{
	int timediff;
	int division;
	double ret_value;
	
   timediff = (TimeCurrent() - TimeLocal()) / 60;
   division = MathRound (timediff / 30.0);
   timediff = 30 * division;
   ret_value = TimeZoneLocal() + timediff / 60.0;
   return (ret_value);
}
//-----------------------------------------------------------------------------------------

//------------------------------- function to calculate timezone -------------------------
double TimeZoneLocal() 
{
   int array[43];

   switch (GetTimeZoneInformation(array)) 
   {
   case 0:
      return (array[0] / (-60.0));
   case 1:
      return (array[0] / (-60.0));
   case 2:
      return ((array[0] + array[42]) / (-60.0));
   }
   return (0);
}
//-------------------------------------------------------------------------------------------------------

//--------------------------------- function NewsTime calls FFCal -----------------------------------------
bool NewsTime() 
{
	static int PrevMinute = -1;
	
	int minutesSincePrevEvent;
	int minutesUntilNextEvent;
	int impactOfNextEvent;
   bool News = FALSE;   // Default is that it signals OK for trading

   if (Use_FF_News_Filter && !IsTesting() && !IsOptimization() && !IsVisualMode()) 
	{
      if (Use_FF_News_Filter && Minute() != PrevMinute) 
		{
         PrevMinute = Minute();
         minutesSincePrevEvent = iCustom (NULL, 0, "FFCal", TRUE, TRUE, TRUE, TRUE, TRUE, 1, 0);
         minutesUntilNextEvent = iCustom (NULL, 0, "FFCal", TRUE, TRUE, TRUE, TRUE, TRUE, 1, 1);
         if ((minutesUntilNextEvent <= MinsBeforeNews) || (minutesSincePrevEvent <= MinsAfterNews)) 
			{
            impactOfNextEvent = iCustom (NULL, 0, "FFCal", TRUE, TRUE, TRUE, TRUE, TRUE, 2, 1);
            if (impactOfNextEvent >= NewsImpact) 
				{
               News = TRUE;  // We have news, so signal NO for trading
               FFNews = "Avoiding news - impact " + impactOfNextEvent + " in " + minutesUntilNextEvent + " minutes";
            }
            else 
					FFNews = "No News to filter!";
            }
         }
      }
   else 
		FFNews = "News filter off!";   
   return (News);
}
//-----------------------------------------------------------------------------------------


//-------------------------------- function News() ----------------------------------------------
bool News() 
{
	int i;
	datetime BeforeNews;
	datetime AfterNews;
	
   if (Use_TSD_News_Filter && !IsTesting() && !IsOptimization() && !IsVisualMode()) 
	{   
      Check_News_Calendar();     
      for (i = 0 ; i <= NewsTotal; i++) 
		{
         if (NewsRatings[i] == 3) 
			{
				BeforeNews = NewsTimes[i] - MinsUntilNextHighNews * 60;
				AfterNews = NewsTimes[i] + MinsSincePrevHighNews * 60; 
         } 
         else if (NewsRatings[i] == 2) 
			{
				BeforeNews = NewsTimes[i] - MinsUntilNextMediumNews * 60;
				AfterNews = NewsTimes[i] + MinsSincePrevMediumNews * 60; 
         } 
			else if (NewsRatings[i] == 1) 
			{
				BeforeNews = NewsTimes[i] - MinsUntilNextLowNews * 60;
				AfterNews = NewsTimes[i] + MinsSincePrevLowNews * 60;
         }        
         if ((TimeCurrent() >= BeforeNews && TimeCurrent() <= AfterNews)) 
			{   
				if (High_Impact && NewsRatings[i] == 3) 
				{
					TSDNews = "Avoiding High Impact News!";
					return (TRUE);
            }
            if (Medium_Impact && NewsRatings[i] == 2) 
			   {
			   	TSDNews = "Avoiding Medium Impact News!";
               return (TRUE);
            }
            if (Low_Impact && NewsRatings[i] == 1) 
			   {
               TSDNews = "Avoiding Low Impact News!";
               return (TRUE);
            }
         }            
      }
      TSDNews = "No News to filter!";
      return (FALSE);           
   }
   else 
      TSDNews = "News Filter off!";
   return(false);
}
//-----------------------------------------------------------------------------------------


//-------------------------------- function CheckNewsCalendar() ----------------------------------

void Check_News_Calendar() 
{
   static datetime prevTime;
   datetime cTime = iTime (NULL, PERIOD_D1, 0);
	string cName;
   
	// We only need to update the calendar once a day
   if ((TimeCurrent() > cTime && cTime > prevTime)) 
	{               
		cName = Download_ForexTSD_Calendar();  
		if (cName != "") 
		{   
			Read_ForexTSD_Calendar(cName);       
			prevTime = cTime;
		}       
   }  
   return (0);
}
//-----------------------------------------------------------------------------------------

//-------------------------------- function Download_ForexTSD_Calendar --------------------------
string Download_ForexTSD_Calendar() 
{
   string result = "";       
   string OldStartMonth;
	string OldStart_Day;
   string StartMonth;
	string Start_Day;  
   datetime StartDay = iTime (NULL, PERIOD_D1, 0);
   datetime OldStartDay = iTime (NULL, PERIOD_D1, 1);
   string OldStartYear = TimeYear (OldStartDay);
   string OldCalName = "ForexTSD_" + OldStartYear + "-" + OldStartMonth + "-" + OldStart_Day + ".csv";   
   int handle = FileOpen (OldCalName, FILE_CSV | FILE_READ, ';');
   string StartYear = TimeYear(StartDay);
   string StartTime = StartYear + StartMonth + Start_Day;      
   string NewsWebAdress = TSD_Calendar_URL + StartTime + "&calendar[]=" + TSD_CalendarID;
   string CalName = "ForexTSD_" + StartYear + "-" + StartMonth + "-" + Start_Day + ".csv";     

	if (TimeMonth (OldStartDay) > 9) 
		OldStartMonth = TimeMonth (OldStartDay);
   else 
		OldStartMonth = "0" + TimeMonth (OldStartDay);
   if (TimeDay (OldStartDay) > 9) 
		OldStart_Day = TimeDay (OldStartDay);
   else 
		OldStart_Day = "0" + TimeDay (OldStartDay);
   
   if (handle > 0) 
	{ 
		FileClose (handle); 
		FileDelete (OldCalName); 
	}
           
   if (TimeMonth(StartDay) > 9) 
		StartMonth = TimeMonth (StartDay);
   else 
		StartMonth = "0" + TimeMonth (StartDay);   
   if (TimeDay(StartDay) > 9) 
		Start_Day = TimeDay (StartDay);
   else 
		Start_Day = "0" + TimeDay (StartDay);   
   
   handle = FileOpen (CalName, FILE_CSV | FILE_READ, ';');
   if (handle < 0) 
	{
		GrabWeb(NewsWebAdress, result);      
		if (result != "") 
		{         
			handle = FileOpen (CalName, FILE_CSV | FILE_WRITE, ';');         
			if (handle > 0) 
			{
				FileWrite (handle, result);
				FileClose (handle);
			}
		} 
		else 
			CalName = "";     
   } 
	else 
		FileClose (handle);
   return (CalName);   
}
//-----------------------------------------------------------------------------------------


//----------------------- function Read_ForexTSD_Calendar ---------------------------------

void Read_ForexTSD_Calendar (string fName) 
{
   string sDate[1000];          // Date   
   string sRating[1000];        // Rating
   string sActual[1000];        // Actual value
   string sForecast[1000];      // Forecast value
   string sPrevious[1000];      // Previous value
   string sTime[1000];          // Time
   string sDescription[1000];   // Description
   string sCurrency[1000];      // Currency affected              
   int handle = FileOpen (fName, FILE_CSV | FILE_READ, ';');
   int i = 0;
	datetime News_Time; 
	 
	if (handle < 1) 
	{
		Print ("File not found ", GetLastError());
		return (FALSE);
   }   

   while (!FileIsEnding(handle)) 
	{
		sDate[i] = FileReadString (handle);          
		sTime[i] = FileReadString (handle);         
		sCurrency[i] = FileReadString (handle);      
		sDescription[i] = FileReadString (handle);   
		sRating[i] = FileReadString (handle);        
		sActual[i] = FileReadString (handle);       
		sForecast[i] = FileReadString (handle);      
		sPrevious[i] = FileReadString (handle);                
   
		if ((sCurrency[i] == "USD") && (!USD)) continue;            
		if ((sCurrency[i] == "EUR") && (!EUR)) continue;            
		if ((sCurrency[i] == "GBP") && (!GBP)) continue;                      
		if ((sCurrency[i] == "JPY") && (!JPY)) continue;
		if ((sCurrency[i] == "AUD") && (!AUD)) continue;
		if ((sCurrency[i] == "CAD") && (!CAD)) continue;                     
		if ((sCurrency[i] == "CHF") && (!CHF)) continue;  
		if ((sCurrency[i] == "NZD") && (!NZD)) continue;   
     
		News_Time = StrToTime (sDate[i] + " " + sTime[i]) + GMTOffset * 3600;      
		sTime[i] = StringSubstr (TimeToStr (News_Time), 11, 5);
		NewsTimes[i] = News_Time;
		NewsRatings[i] = StrToInteger (sRating[i]);
		i++;
   }
   NewsTotal = i;   
   return(0);
}
//-----------------------------------------------------------------------------------------

// ------------------------- function GrabWeb needed to read from web pages -------------
bool GrabWeb(string strUrl, string& strWebPage) 
{

	int hInternet;
	int iResult;
	int lReturn[]	= {1};
	string sBuffer	= "                                                                                                                                                                                                                                                           ";	// 255 spaces
	int bytes;
	
	hInternet = InternetOpenUrlA (hSession (FALSE), strUrl, "0", 0,INTERNET_FLAG_NO_CACHE_WRITE | 
	INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD, 0);
								
	if (hInternet == 0) 
		return (FALSE);

	//Print("Reading URL: " + strUrl);	   //added by MN	
	iResult = InternetReadFile(hInternet, sBuffer, Buffer_LEN, lReturn);
	
	if (iResult == 0) 
		return (FALSE);
	bytes = lReturn[0];

	strWebPage = StringSubstr (sBuffer, 0, lReturn[0]);
	
	// If there's more data then keep reading it into the buffer
	while (lReturn[0] != 0)	
	{
		iResult = InternetReadFile(hInternet, sBuffer, Buffer_LEN, lReturn);
		if (lReturn[0] == 0) 
			break;
		bytes = bytes + lReturn[0];
		strWebPage = strWebPage + StringSubstr (sBuffer, 0, lReturn[0]);
	}
	Print ("Closing URL web connection to News-server");   
	iResult = InternetCloseHandle (hInternet);
	if (iResult == 0) 
		return (FALSE);
	return (TRUE);
}
//-----------------------------------------------------------------------------------------

//------------------------------- function called from GrabWeb -----------------------
int hSession(bool Direct)
{
	string InternetAgent;
	if (hSession_IEType == 0) 
	{
		InternetAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461)";
		hSession_IEType = InternetOpenA (InternetAgent, Internet_Open_Type_Preconfig, "0", "0", 0);
		hSession_Direct = InternetOpenA (InternetAgent, Internet_Open_Type_Direct, "0", "0", 0);
	}
	if (Direct) 
	{ 
		return (hSession_Direct); 
	} 
	else 
	{
		return (hSession_IEType); 
	}
}
//-----------------------------------------------------------------------------------------

// That should be all!    // Capella