FFCal_v01b





//=============================================================================
//                                                            FFCal_v01.mq4
//                                            Copyright © 2006, Derk Wehler
// Written in cooperation with:                 http://www.forexfactory.com
//
//
// This "indicator" calls DLLs to fetch a special XML file from the 
// ForexFactory web site.  It then parses it and writes it out as a .CSV 
// file, which it places in the folder: experts/files so that IsNewsTime() 
// can use that file to tell if it is near announcement time.
//
// It does this once when it starts up and once per hour in case there have 
// been any updates to the annoucement calendar.
//
// In order for this to work correctly and synchronize with your broker's 
// server time, you must enter the proper value for "TimeZone".  This is 
// entered relative to GMT.  For example, my broker's server time is GMT+1, 
// so I have the default set to 1.  If your broker uses GMT+3, enter 3.
// If your broker uses GMT-2, then enter -2.
//
//
//
//=============================================================================
//                             OTHER CREDIT DUE
//      (For GrebWeb and LogUtils functionality (see end of this flie)
//
// 12/14/2007  Robert Hill added code for using text objects for easier reading
//=============================================================================
//+---------------------------------------------------------------------------+
//|                                                               WinInet.mqh |
//|                                                        Paul Hampton-Smith |
//|                                                        paul1000@pobox.com |
//|                                                                           |
//| This include has been adapted from the groundbreaking GrabWeb script      |
//| developed by Adbi that showed me how to import functions from wininet.dll |
//|---------------------------------------------------------------------------|
//|                                                               grabweb.mq4 |
//|                                                    Copyright © 2006, Abhi |
//|                                         http://www.megadelfi.com/experts/ |
//|                                     E-mail: grabwebexpert{Q)megadelfi.com |
//|                                fix my e-mail address before mailing me ;) |
//+---------------------------------------------------------------------------+
/*
		IDEAS FOR ADDITIONS:
		
1) Additional currencies to watch??

2) A text lable of what the news was and when it was, e.g
    "USD CPI m/m @ [broker time here]" at the top or bottom within the shaded area.
    
3) Label the number of pips it went in its initial direction and how much it 
	retraced...of course you'd have to come up with a convention for measuring 
	movement.  Or you could label what price was just prior to news then labels 
	the next two price exteremes.  I think it would be nice to have the numbers 
	right under/over the candle that produced the extremes for whatever timeframe 
	you are in.

4) Label the volume count for the candle that included the news in it...whatever 
	timeframe your in.  So I could switch from 1 min. to 5 min. to 15 min. 
	timeframes and get different vol. counts for the bar that included the news.
	
5) Optional alert x minutes before news and maybe again y minutes before news?
*/

#property copyright "Copyright © 2006, Derk Wehler"
#property link      "http://www.forexfactory.com"

#property indicator_chart_window
#property indicator_buffers 2

//====================================================================================
//====================================================================================
//====================================================================================
//====================================================================================
//====================================================================================
//====================================================================================
//====================================================================================

extern int		TimeZone 			= 1;		// Set this to the GMT addition, so "1" for GMT+1, "-3" for GMT-3
extern bool 	IncludeHigh 		= true;
extern bool 	IncludeMedium 		= true;
extern bool 	IncludeLow 			= false;
extern bool 	IncludeSpeaks 		= true; 	// news items with "Speaks" in them have different characteristics
extern int		Alert1MinsBefore	= -1;		// Set to -1 for no Alert
extern int		Alert2MinsBefore	= -1;		// Set to -1 for no Alert
extern bool 	EnableLogging 		= false; 	// Perhaps remove this from externs once its working well
// Added by Robert for text size and color instead of comment
extern int txtSize = 10;
extern color txtColor1 = White;
extern color txtColor2 = DeepSkyBlue;
extern color txtColor3 = Red;
extern color txtColor4 = Orange;
extern color txtColor5 = Lime;


int		DebugLevel = 2;

double 	ExtMapBuffer0[];
double 	ExtMapBuffer1[];

string	sUrl = "http://www.forexfactory.com/weekly_calendar.xml";
int 	xmlHandle;
int 	logHandle = -1;
int 	BoEvent, finalend, end, i;
int		begin;
int 	minsTillNews;
int		dispMinutes;
string 	sData, csvoutput;
string 	dispTitle, dispCountry, dispImpact, dispForecast, dispPrevious;
string 	mainData[7];
string	commentStr;

static bool FirstRun = true;
static int	PrevMinute = -1;


int init()
{
	Print("In Init()...\n");
	
	SetIndexStyle(0, DRAW_NONE);
	SetIndexBuffer(0, ExtMapBuffer0);

	SetIndexStyle(1, DRAW_NONE);
	SetIndexBuffer(1, ExtMapBuffer1);

	IndicatorShortName("FFCal");
	SetIndexLabel(0, "MinsBeforeNews");
	SetIndexLabel(1, "MinsAfterNews"); 

	return(0);
}


int deinit()
{
   ObjectDelete("Label1"); ObjectDelete("Minutes"); ObjectDelete("Impact");
   ObjectDelete("Previous"); ObjectDelete("Forecast");
	return(0);
}


int start()
{
	int 		newsIdx = 0;
	int 		nextNewsIdx = -1;
	int 		next;
	string 		myEvent;
	bool 		skip;
	datetime 	newsTime;
	
	// If we are not logging, then do not output debug statements either
	if (!EnableLogging)
		DebugLevel = 0;
				
	commentStr = "Forex Factory Calendar\n";
	string xmlFileName = Month() + "-" + Day() + "-" + Year() + "-" + "FFCal.xml";
	Print("STARTED");
	
	// Refresh FF calendar on startup, and once at the top of each hour
	if (FirstRun || Minute() == 0)
	{
		FirstRun = false;

		if (DebugLevel > 1)
			Print("sUrl == ", sUrl);
		
		if (DebugLevel > 0)
			Print("Grabbing Web, url = ", sUrl);
	
		// THIS CALL WAS DONATED BY PAUL TO HELP FIX THE RESOURCE ERROR
		GrabWeb(sUrl, sData);

		if (DebugLevel > 0)
		{
			Print("Opening XML file...\n");
			Print(sData);
		}

		// Write the contents of the ForexFactory page to an .htm file
		xmlHandle = FileOpen(xmlFileName, FILE_BIN|FILE_READ|FILE_WRITE);
		if (xmlHandle < 1)
		{
			if (DebugLevel > 0)
				Print("Can\'t open new xml file, the last error is ", GetLastError());
			return(false);
		}
		FileWriteString(xmlHandle, sData, StringLen(sData));
		FileClose(xmlHandle);

		if (DebugLevel > 0)
			Print("Wrote XML file...\n");

		// THIS BLOCK OF CODE DONATED BY WALLY TO FIX THE RESOURCE ERROR
		//--- Look for the end XML tag to ensure that a complete page was downloaded ---//
		end = StringFind(sData, "</weeklyevents>", 0);

		if (end <= 0)
		{
			Alert("GetNewsFF Error - Web page download was not complete!");
			return(false);
		}
		//-------------------------------------------------------------------------------//
	}

	// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
	// Perform remaining checks once per minute
	if (Minute() == PrevMinute)
		return (true);
	PrevMinute = Minute();
	Print("NEW MINUTE...");

	// Open the log file (will not open if logging is turned off)
	OpenLog("FFCal");

	// Init the buffer array to zero just in case
	ArrayInitialize(ExtMapBuffer0, 0);
	ArrayInitialize(ExtMapBuffer1, 0);
	
	// Open the XML file
	xmlHandle = FileOpen(xmlFileName, FILE_BIN|FILE_READ);
	if (xmlHandle < 0)
	{
		Print("Can\'t open xml file: ", xmlFileName, ".  The last error is ", GetLastError());
		return(false);
	}
	if (DebugLevel > 0)
		Print("XML file open must be okay");
	
	// Read in the whole XML file
	// Ave file length == ~7K, so 65536 should always read whole file
	sData = FileReadString(xmlHandle, 65536);	
	FileClose(xmlHandle);

	// Get the currency pair, and split it into the two countries
	string pair = Symbol();
	string cntry1 = StringSubstr(pair, 0, 3);
	string cntry2 = StringSubstr(pair, 3, 3);
	if (DebugLevel > 0)
		Print("cntry1 = ", cntry1, "    cntry2 = ", cntry2);
	
	if (DebugLevel > 0)
		Log("Weekly calendar for " + pair + "\n\n");

	// -------------------------------------------------
	// Parse the XML file looking for an event to report
	// -------------------------------------------------
	
	dispMinutes = 10080;	// (a week)
	BoEvent = 0;

	string sTags[7] = { "<title>", "<country>", "<date>", "<time>", "<impact>", "<forecast>", "<previous>" };
	string eTags[7] = { "</title>", "</country>", "</date>", "</time>", "</impact>", "</forecast>", "</previous>" };
	int loopcount = 0;
	while (true)
	{
//		loopcount++;
//		if (loopcount > 500)
//			break;
		BoEvent = StringFind(sData, "<event>", BoEvent);
		if (BoEvent == -1)
			break;
			
		BoEvent += 7;	
		next = StringFind(sData, "</event>", BoEvent);
		myEvent = StringSubstr(sData, BoEvent, next - BoEvent);
		BoEvent = next;
		
		begin = 0;
		skip = false;
		for (i=0; i < 7; i++)
		{
			mainData[i] = "";
			next = StringFind(myEvent, sTags[i], begin);
			
			// Within this event, if tag not found, then it must be missing; skip it
			if (next == -1)
				continue;
			else
			{
				// We must have found the sTag okay...
				begin = next + StringLen(sTags[i]);			// Advance past the start tag
				end = StringFind(myEvent, eTags[i], begin);	// Find start of end tag
				if (end > begin && end != -1)
				{
					// Get data between start and end tag
					mainData[i] = StringSubstr(myEvent, begin, end - begin);
				}
			}
		}
		
//		for (i=6; i >= 0; i--)
//			Print(sTags[i], "  =  ", mainData[i]);

		if (cntry1 != mainData[1] && cntry2 != mainData[1])
			skip = true;
		if (!IncludeHigh && mainData[4] == "High") 
			skip = true;
		if (!IncludeMedium && mainData[4] == "Medium") 
			skip = true;
		if (!IncludeLow && mainData[4] == "Low") 
			skip = true;
		if (!IncludeSpeaks && (StringFind(mainData[0], "speaks") != -1 || StringFind(mainData[0], "Speaks") != -1) ) 
			skip = true;
		if (mainData[3] == "tentative" || mainData[3] == "Tentative") 
			skip = true;
		
		// If not skipping this event, then log it into the draw buffers
		if (!skip)
		{
			// If we got this far then we need to calc the minutes until this event
			//
			// First, convert the announcement time to seconds, GMT
			newsTime = StrToTime(MakeDateTime(mainData[2], mainData[3]));
			
			// Now convert to brokerage time
			newsTime += (TimeZone * 60 * 60);
			
			// Now calculate the minutes until this announcement (may be negative)
			minsTillNews = (newsTime - TimeCurrent()) / 60;

			// Keep track of the most recent news announcement.
			// Do that by saving each one until we get to the 
			// first annoucement that isn't int he past; i.e.
			// minsTillNews > 0.  Then, keep this one instead for
			// display, but only once the minutes until the next 
			// news is SMALLER than the minutes since the last.
//			Print("Mins till event: ", minsTillNews);
			if (minsTillNews < 0 || MathAbs(dispMinutes) > minsTillNews)
			{
				dispTitle = mainData[0];
				dispCountry = mainData[1];
				dispImpact = mainData[4];
				dispForecast = mainData[5];
				dispPrevious = mainData[6];
				dispMinutes = minsTillNews;
			}
			
			Log("Weekly calendar for " + pair + "\n\n");
			if (DebugLevel > 0)
			{
				Log("FOREX FACTORY\nTitle: " + mainData[0] + 
									"\nCountry: " + mainData[1] + 
									"\nDate: " + mainData[2] + 
									"\nTime: " + mainData[3] + 
									"\nImpact: " + mainData[4] + 
									"\nForecast: " + mainData[5] + 
									"\nPrevious: " + mainData[6] + "\n\n");
			}
			
			// Do alert if user has enabled
			if (Alert1MinsBefore != -1 && minsTillNews == Alert1MinsBefore)
				Alert(Alert1MinsBefore, " minutes until news for ", pair, ": ", mainData[0]);
			if (Alert2MinsBefore != -1 && minsTillNews == Alert2MinsBefore)
				Alert(Alert2MinsBefore, " minutes until news for ", pair, ": ", mainData[0]);
				
			// Buffers are set up as so: 
			// ExtMapBuffer0 contains the time UNTIL each announcement (can be negative)
			// e.g. [0] = -372; [1] = 25; [2] = 450; [3] = 1768 (etc.)
			// ExtMapBuffer1[0] has the mintutes since the last annoucement.
			// ExtMapBuffer1[1] has the mintutes until the next annoucement.
			ExtMapBuffer0[newsIdx] = minsTillNews;
			newsIdx++;
		}
	}

	// Cycle through the events array and pick out the most recent 
	// and the next coming event to put into ExtMapBuffer1
	int nextMins;
	int lastMins = 0;
	bool first = true;
	ExtMapBuffer1[0] = 0;
	ExtMapBuffer1[1] = 0;
	string outNews = "Minutes until news events for " + pair + " : ";
	for (i=0; i < newsIdx; i++)	
	{
		nextMins = ExtMapBuffer0[i];
		outNews = outNews + nextMins + ", ";
		
		if (nextMins > 0 && first)
		{
			first = false;
			ExtMapBuffer1[0] = lastMins;
			ExtMapBuffer1[1] = nextMins;
		}
		lastMins = nextMins;
	}
	
	// If we are past all news events, then neither one will have been 
	// set, so set the past event to the last (negative) minutes
	if (ExtMapBuffer1[0] == 0 && ExtMapBuffer1[1] == 0)
		ExtMapBuffer1[0] = lastMins;
	
	// For debugging...Print the tines until news events, as a "Comment"
	if (DebugLevel > 0)
	{
		Print(outNews);
		Print("LastMins (ExtMapBuffer1[0]) = ", ExtMapBuffer1[0]);
		Print("NextMins (ExtMapBuffer1[1]) = ", ExtMapBuffer1[1]);
	}

// Added by Robert for using txtSize and txtColor for easier reading

    int curY = 10;
    ObjectCreate("Label1", OBJ_LABEL, 0, 0, 0);
        ObjectSetText("Label1",commentStr,txtSize, "Arial Bold", txtColor1);
        ObjectSet("Label1", OBJPROP_CORNER, 0);
        ObjectSet("Label1", OBJPROP_XDISTANCE, 10);
        ObjectSet("Label1", OBJPROP_YDISTANCE, curY);       
     
    curY = curY + txtSize + 4;
    ObjectCreate("Minutes", OBJ_LABEL, 0, 0, 0);
        ObjectSetText("Minutes",dispMinutes + " Mins until " + dispCountry + ": " + dispTitle,txtSize, "Arial Bold", txtColor2);
        ObjectSet("Minutes", OBJPROP_CORNER, 0);
        ObjectSet("Minutes", OBJPROP_XDISTANCE, 10);
        ObjectSet("Minutes", OBJPROP_YDISTANCE, curY);
         
    curY = curY + txtSize + 4;
    ObjectCreate("Impact", OBJ_LABEL, 0, 0, 0);
        ObjectSetText("Impact","Impact: " + dispImpact,txtSize, "Arial Bold", txtColor3);
        ObjectSet("Impact", OBJPROP_CORNER, 0);
        ObjectSet("Impact", OBJPROP_XDISTANCE, 10);
        ObjectSet("Impact", OBJPROP_YDISTANCE, curY);

    curY = curY + txtSize + 4;
    ObjectCreate("Previous", OBJ_LABEL, 0, 0, 0);
        ObjectSetText("Previous","Previous: " + dispPrevious,txtSize, "Arial Bold", txtColor4);
        ObjectSet("Previous", OBJPROP_CORNER, 0);
        ObjectSet("Previous", OBJPROP_XDISTANCE, 10);
        ObjectSet("Previous", OBJPROP_YDISTANCE, curY);
            
    curY = curY + txtSize + 4;
    ObjectCreate("Forecast", OBJ_LABEL, 0, 0, 0);
        ObjectSetText("Forecast","Forecast: " + dispForecast, txtSize, "Arial Bold", txtColor5);
        ObjectSet("Forecast", OBJPROP_CORNER, 0);
        ObjectSet("Forecast", OBJPROP_XDISTANCE, 10);
        ObjectSet("Forecast", OBJPROP_YDISTANCE, curY); 
    
	// Now handle all other indicator functions
//	commentStr = commentStr + dispMinutes + " Mins until " + dispCountry + ": " + dispTitle;
//	commentStr = commentStr + "\nImpact: " + dispImpact;
//	commentStr = commentStr + "\nPrevious: " + dispPrevious;
//	commentStr = commentStr + "\nForecast: " + dispForecast;
//	Comment(commentStr);

	if (logHandle != -1)
		FileClose(logHandle);
	return (0);
}

   
string MakeDateTime(string strDate, string strTime)
{
	// converts forexfactory time & date into yyyy.mm.dd hh:mm
	int n1stDash = StringFind(strDate, "-");
	int n2ndDash = StringFind(strDate, "-", n1stDash+1);

	string strMonth = StringSubstr(strDate, 0, 2);
	string strDay = StringSubstr(strDate, 3, 2);
	string strYear = StringSubstr(strDate, 6, 2); 
	strYear = "20" + strYear;
	
	int nTimeColonPos	= StringFind(strTime, ":");
	string strHour = StringSubstr(strTime, 0, nTimeColonPos);
	string strMinute = StringSubstr(strTime, nTimeColonPos+1, 2);
	string strAM_PM = StringSubstr(strTime, StringLen(strTime)-2);

	int nHour24 = StrToInteger(strHour);
	if (strAM_PM == "pm" || strAM_PM == "PM" && nHour24 != 12)
	{
		nHour24 += 12;
	}
	string strHourPad = "";
	if (nHour24 < 10) 
		strHourPad = "0";

	return(StringConcatenate(strYear, ".", strMonth, ".", strDay, " ", strHourPad, nHour24, ":", strMinute));
}


//=================================================================================================
//=================================================================================================
//====================================   GrabWeb Functions   ======================================
//=================================================================================================
//=================================================================================================
// Main Webscraping function
// ~~~~~~~~~~~~~~~~~~~~~~~~~
// bool GrabWeb(string strUrl, string& strWebPage)
// returns the text of any webpage. Returns false on timeout or other error
// 
// Parsing functions
// ~~~~~~~~~~~~~~~~~
// string GetData(string strWebPage, int nStart, string strLeftTag, string strRightTag, int& nPos)
// obtains the text between two tags found after nStart, and sets nPos to the end of the second tag
//
// void Goto(string strWebPage, int nStart, string strTag, int& nPos)
// Sets nPos to the end of the first tag found after nStart 

bool bWinInetDebug = false;

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 = 13;

#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


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); 
	}
}


bool GrabWeb(string strUrl, string& strWebPage)
{
	int 	hInternet;
	int		iResult;
	int 	lReturn[]={1};
	string 	sBuffer="x";
	int 	bytes;
	
	hInternet = InternetOpenUrlA(hSession(FALSE), strUrl, "0", 0, 
								INTERNET_FLAG_NO_CACHE_WRITE | 
								INTERNET_FLAG_PRAGMA_NOCACHE | 
								INTERNET_FLAG_RELOAD, 0);
								
	if (bWinInetDebug) 
		Log("hInternet: " + hInternet);   
	if (hInternet == 0) 
		return(false);
		
	iResult = InternetReadFile(hInternet, sBuffer, Buffer_LEN, lReturn);
	
	if (bWinInetDebug) 
		Log("iResult: " + iResult);
	if (bWinInetDebug) 
		Log("lReturn: " + lReturn[0]);
	if (bWinInetDebug) 
		Log("iResult: " + iResult);
	if (bWinInetDebug) 
		Log("sBuffer: " +  sBuffer);
	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]);
	}

	iResult = InternetCloseHandle(hInternet);
	if (iResult == 0) 
		return(false);
	if (bWinInetDebug) 
	{ 	
		Log("iResult: " + iResult);
		int handle = FileOpen("Grabweb.htm",FILE_BIN|FILE_READ|FILE_WRITE);
		FileWriteString(handle,strWebPage,StringLen(strWebPage));
		FileClose(handle);
	}
	return(true);
}


/*
string GetData(string strWebPage, int nStart, string strLeftTag, string strRightTag, int& nPos)
{
	nPos = StringFind(strWebPage,strLeftTag,nStart);
	if (nPos == -1)
	{
		if (bWinInetDebug) Log("GetData(WebPage,"+nStart+","+strLeftTag+","+strRightTag+"): not found, returning empty string and -1");
		return("");
	}
	nPos += StringLen(strLeftTag);
	int nEnd = StringFind(strWebPage,strRightTag,nPos+1);
	string strData = StringTrimLeft(StringTrimRight(StringSubstr(strWebPage,nPos,nEnd-nPos)));
	if (bWinInetDebug) Log("GetData(WebPage,"+nStart+","+strLeftTag+","+strRightTag+") returning "+strData+" and "+nPos);
	return(strData);
}

void Goto(string strWebPage, int nStart, string strTag, int& nPos)
{
	nPos = StringFind(strWebPage,strTag,nStart);
	if (nPos == -1) 
	{
		if (bWinInetDebug) Log("Goto("+nStart+","+strTag+") not found. Returning -1");
		return;
	}
	nPos += StringLen(strTag);
	if (bWinInetDebug) Log("Goto("+nStart+","+strTag+") returning "+nPos);
}

void SaveWebPage(string strWebPage, string strID)
{
	string strFilename = strID+"_"+Year()+Pad(Month())+Pad(Day())+"-"+Pad(Hour())+Pad(Minute())+Pad(Seconds())+".htm";
	int handle = FileOpen(strFilename,FILE_BIN|FILE_WRITE);
	FileWriteString(handle,strWebPage,StringLen(strWebPage));
   FileClose(handle);
}


string Pad(int n)
{
	string strPad = "";
	if (n <= 9) strPad = "0";
	return(strPad+n);
}
*/

//=================================================================================================
//=================================================================================================
//===================================   LogUtils Functions   ======================================
//=================================================================================================
//=================================================================================================

void OpenLog(string strName)
{
	if (!EnableLogging) 
		return;

	if (logHandle <= 0)
	{
		string strMonthPad = "";
 	 	string strDayPad = "";
  		if (Month() < 10) 
  			strMonthPad = "0";
  		if (Day() < 10) 
  			strDayPad = "0";
  			
  		string strFilename = StringConcatenate(strName, "_", Year(), strMonthPad, Month(), strDayPad, Day(), "_log.txt");
  		
		logHandle = FileOpen(strFilename,FILE_CSV|FILE_READ|FILE_WRITE);
		Print("logHandle =================================== ", logHandle);
	}
	if (logHandle > 0)
	{
		FileFlush(logHandle);
		FileSeek(logHandle, 0, SEEK_END);
	}
}


void Log(string msg)
{
	if (!EnableLogging) 
		return;
		
	if (logHandle <= 0) 
		return;
		
	msg = TimeToStr(TimeCurrent(),TIME_DATE|TIME_MINUTES|TIME_SECONDS) + " " + msg;
	FileWrite(logHandle,msg);
}

//=================================================================================================
//=================================================================================================
//=================================   END IMPORTED FUNCTIONS  =====================================
//=================================================================================================
//=================================================================================================





Sample





Analysis



Market Information Used:



Indicator Curves created:

Implements a curve of type DRAW_NONE


Indicators Used:



Custom Indicators Used:
wininet

Order Management characteristics:

Other Features:

Uses files from the file system
It writes information to file
It issuies visual alerts to the screen
It reads information from a file