News_Plotter
Download scriptNews Event Plotter Overview
This tool is designed to help traders visualize upcoming economic news events directly on their trading charts. It automates the process of reading a news calendar, calculating the correct times for those events based on your local time zone, and drawing visual markers so you can prepare for market volatility.
Core Functionality
Data Integration and Processing The script works by reading an external CSV file containing global economic news. Because these files often contain raw data in various formats, the logic includes several automatic conversion steps:
- Time Zone Adjustment: It takes a GMT offset into account to ensure that news events align with your specific local time.
- Time Formatting: It automatically converts standard AM/PM time formats into a 24-hour format required for accurate chart plotting.
- Date Standardization: It parses dates from the file and organizes them into a structured list for the software to read.
Visual Chart Markers Once the news data is processed, the script draws vertical dotted lines on your chart at the exact moment an event is scheduled to occur.
- Dynamic Coloring: Events are color-coded by their importance level (e.g., High, Medium, and Low) to help you quickly identify high-impact volatility.
- Information Labels: Each line on the chart includes a text description indicating both the severity rating and the name of the news event (e.g., "High: Non-Farm Payrolls").
- Smart Layering: If multiple news events occur at the exact same time, the logic prioritizes the highest-rated event to ensure that critical information is not hidden behind less important data.
Alert System Beyond just visual markers, the script includes a proactive notification system:
- Advance Warnings: You can set a specific warning period (in minutes). The script will trigger an audio alert before a news event occurs.
- Selective Alerts: You can choose to receive alerts only for high-impact news or across all categories, allowing you to filter out the "noise" of minor updates.
- One-Time Notifications: To prevent constant buzzing, the script is designed to alert you only once per specific news event.
Chart Maintenance To keep your trading workspace clean, the script includes an optional cleanup feature. If enabled, it will automatically detect and remove vertical lines for news events that occurred on previous days, ensuring your chart only shows relevant, upcoming information.
//+------------------------------------------------------------------+
//| Des_News_Plotter.mq4 |
//| DesORegan |
//| mailto: oregan_des@hotmail.com |
//+------------------------------------------------------------------+
// ========================================================================================================
// This indicator displays lines on the chart corresponding to upcoming news events. It has the following features:
// 1. Customizable audio alerts prior to the news event itself.
// 2. Allows the user to display lines according to event rating. e.g. display High rated events only.
// 3. Deletes old news lines from the chart(older than today's)".
// 4. Adjusts GMT from file to local (using GMT_Offset).
// 5. Converts AM/PM time in file to 24hr for correct plotting.
// 6. Prioritises higher rated events at same time as lower events. Prevents High "hiding" behind Low etc..
// (assuming appropriate timeframe is selected)
// 7. Event descriptions used to populate object descriptions.
//
// To be able to use this indicator you must first save the file from the DailyFx website to the
// C:\Program Files\Broker Metatrader\experts\files folder. The file is located at:
// http://www.dailyfx.com/calendar/Dailyfx_Global_Economic_Calendar.csv
// IMPORTANT: It must be saved as "News.csv". Make sure it's for the current week.
//
// Save your own preferences by changing the external inputs in the code and recompiling.
// There may be bugs in this indicator but I think I've got most if not all ironed out.
// Only one way to find out. ;-)
//
// ========================================================================================================
#property copyright "DesORegan"
#property link "mailto: oregan_des@hotmail.com"
#property indicator_chart_window
#include <stdlib.mqh>
// =========================
// External Global Variables
// =========================
extern int GMT_Offset=2; // change this to suit, default (+2) is for CET
extern bool Display_Low=true;
extern color Low_Color=Blue;
extern bool Display_Medium=true;
extern color Medium_Color=Orange;
extern bool Display_High=true;
extern color High_Color=Red;
extern bool News_Alerts=true;
extern bool Low_Alerts=false;
extern bool Medium_Alerts=false;
extern bool High_Alerts=true;
extern int Warning_In_Mins=15;
extern bool Delete_Old_News=false; // deletes events older than today's
// =========================
// Internal Global Variables
// =========================
datetime Today_Start;
// =========================
// Internal Global Arrays
// =========================
string News_Array [][5]; // 0=Date,1=Description,2=Rating,3=Rating No.,4=Alert Given?
// =================================================================================================
// =================================================================================================
// Custom indicator initialization function
// =================================================================================================
// =================================================================================================
int init()
{
//======================
// Variable Init
//======================
Today_Start = iTime(Symbol(),PERIOD_D1,0);
GMT_Offset = GMT_Offset*3600; // *secs in hour
Warning_In_Mins = Warning_In_Mins*60; // *secs in minute
News_Plotter(); // reads file and plots news according to preferences
if (Delete_Old_News == true) Delete_Old_News(); // deletes old event lines
return(0);
}
// =================================================================================================
// =================================================================================================
// Custom indicator deinitialization function
// =================================================================================================
// =================================================================================================
int deinit()
{
ObjectsDeleteAll();
return(0);
}
// =================================================================================================
// =================================================================================================
// Custom indicator iteration function
// =================================================================================================
// =================================================================================================
int start()
{
if (News_Alerts == true) Check_News(); // checks for imminent news events
if (Delete_Old_News == true && Today_Start != iTime(Symbol(),PERIOD_D1,0)) // only calls if new day
{
Delete_Old_News();
Today_Start = iTime(Symbol(),PERIOD_D1,0);
}
return(0);
}
// =================================================================================================
//| News_Plotter function
// =================================================================================================
int News_Plotter ()
{
string Event_Date, Event_Month, Event_Day, Event_Time;
string Gap, Event_Description, Event_Rating, Event_Rating_No;
string Hrs, Mins;
int Int_Hrs, Int_Mins, Last_Int_Event_Rating, i=0;
datetime Real_Event_DateTime, Real_Event_Time;
color Market_Event_Color;
int File = FileOpen("News.CSV", FILE_CSV|FILE_READ,','); // opens News.csv file
if (File == -1)
{
Alert("News Events File Error.");
int err=GetLastError();
Print("Error(",err,"): ",ErrorDescription(err));
}
FileSeek(File, 96, SEEK_SET); // move file pointer to beginning of valid data
while(FileIsEnding(File)==false) // While the file pointer is not at the end of the file
{
ArrayResize(News_Array,i+1); //resizes array for every loop (event)
// ===========================
// Reads file and formats data
// ===========================
Event_Date = FileReadString(File); // Read Date from file
if(StringSubstr(Event_Date,4,3) == "Jan") Event_Month = "01"; // extract Month and convert to number
else if(StringSubstr(Event_Date,4,3) == "Feb") Event_Month = "02"; // in string format for adding to
else if(StringSubstr(Event_Date,4,3) == "Mar") Event_Month = "03"; // other components of Date
else if(StringSubstr(Event_Date,4,3) == "Apr") Event_Month = "04";
else if(StringSubstr(Event_Date,4,3) == "May") Event_Month = "05";
else if(StringSubstr(Event_Date,4,3) == "Jun") Event_Month = "06";
else if(StringSubstr(Event_Date,4,3) == "Jul") Event_Month = "07";
else if(StringSubstr(Event_Date,4,3) == "Aug") Event_Month = "08";
else if(StringSubstr(Event_Date,4,3) == "Sep") Event_Month = "09";
else if(StringSubstr(Event_Date,4,3) == "Oct") Event_Month = "10";
else if(StringSubstr(Event_Date,4,3) == "Nov") Event_Month = "11";
else if(StringSubstr(Event_Date,4,3) == "Dec") Event_Month = "12";
else Alert ("Date Reading Error in News Function");
Event_Day = StringSubstr(Event_Date, (StringLen(Event_Date)-2), 0); // extract Day
Event_Date = TimeYear(TimeCurrent())+"."+Event_Month+"."+Event_Day; // reconfigure Date
Event_Time = StringConcatenate("0000",FileReadString(File)) ; // read Time and fill out with 0's
// ===========================
// Converts AM/PM to 24hr
// ===========================
if (StringSubstr(Event_Time, (StringLen(Event_Time)-2), 2) == "PM") // PM time conversion
{
Mins = StringSubstr(Event_Time,(StringLen(Event_Time)-5),2);
Hrs = StringSubstr(Event_Time,(StringLen(Event_Time)-8),2);
Int_Hrs = StrToInteger(Hrs)*3600;
Int_Mins = StrToInteger(Mins)*60;
Real_Event_Time = Int_Hrs + Int_Mins;
if (Real_Event_Time < 43200) Real_Event_Time = Real_Event_Time + 43200; // prevents 12:12PM etc from being altered
}
else // AM time conversion
{
Mins = StringSubstr(Event_Time,(StringLen(Event_Time)-5),2);
Hrs = StringSubstr(Event_Time,(StringLen(Event_Time)-8),2);
Int_Hrs = StrToInteger(Hrs)*3600;
Int_Mins = StrToInteger(Mins)*60;
Real_Event_Time = Int_Hrs + Int_Mins;
}
Gap = FileReadString(File) ;
Gap = FileReadString(File) ;
Event_Description = FileReadString(File);
Event_Rating = FileReadString(File) ;
for (int p = 1; p <= 5; p++) Gap = FileReadString(File) ; // more gaps in file for unused data
if (Real_Event_Time == 0) // if no time is specified in file
{
Real_Event_DateTime = StrToTime(Event_Date) + Real_Event_Time;
//Print("Warning: "+Event_Date+" "+Event_Rating+" - "+Event_Description+" - Event Time Unknown");
//Print("Please check internet for updates.");
Event_Description = "Event Time Unknown "+Event_Description;
}
else Real_Event_DateTime = StrToTime(Event_Date) + Real_Event_Time + GMT_Offset;
// ==================
// Fills News_Array
// ==================
News_Array[i,0] = TimeToStr(Real_Event_DateTime); // fills datetime data in compatible format
News_Array[i,1] = Event_Description; // fills description data
News_Array[i,2] = Event_Rating; // fills rating data
if (Event_Rating == "High") Event_Rating_No = "3";
if (Event_Rating == "Medium") Event_Rating_No = "2";
if (Event_Rating == "Low") Event_Rating_No = "1";
News_Array[i,3] = Event_Rating_No; // number equivalent for ratings
News_Array[i,4] = "0"; // used for prevents repetition of alerts
i++; // required to increment News_Array
}
FileClose( File );
// =================================================================
// Helps set rating color for events at same time to highest rating.
// Used with Market_Event_Color below.
// =================================================================
for (p = 1; (p <= ArraySize(News_Array)/5); p++) // this helps give priority to higher rated events
{
if (News_Array[p,0] == News_Array[p-1,0] && StrToInteger(News_Array[p,3]) < StrToInteger(News_Array[p-1,3]))
{
News_Array[p,3] = News_Array[p-1,3];
}
}
// ============================
// Plots event lines on chart
// ============================
for (p = 0; p < (ArraySize(News_Array)/5); p++)
{
if (News_Array[p,3] == "1") Market_Event_Color = Low_Color;
if (News_Array[p,3] == "2") Market_Event_Color = Medium_Color;
if (News_Array[p,3] == "3") Market_Event_Color = High_Color;
if(Display_Low == true && News_Array[p,2] == "Low")
{
ObjectCreate(p+".News: "+News_Array[p,0],OBJ_VLINE,0,StrToTime(News_Array[p,0]),NULL);
ObjectSet(p+".News: "+News_Array[p,0],OBJPROP_COLOR,Market_Event_Color);
ObjectSet(p+".News: "+News_Array[p,0],OBJPROP_WIDTH,1);
ObjectSet(p+".News: "+News_Array[p,0], OBJPROP_BACK, true);
ObjectSet(p+".News: "+News_Array[p,0],OBJPROP_STYLE,STYLE_DOT);
ObjectSetText(p+".News: "+News_Array[p,0], News_Array[p,2]+": "+News_Array[p,1], 8);
}
if(Display_Medium == true && News_Array[p,2] == "Medium")
{
ObjectCreate(p+".News: "+News_Array[p,0],OBJ_VLINE,0,StrToTime(News_Array[p,0]),NULL);
ObjectSet(p+".News: "+News_Array[p,0],OBJPROP_COLOR,Market_Event_Color);
ObjectSet(p+".News: "+News_Array[p,0],OBJPROP_WIDTH,1);
ObjectSet(p+".News: "+News_Array[p,0], OBJPROP_BACK, true);
ObjectSet(p+".News: "+News_Array[p,0],OBJPROP_STYLE,STYLE_DOT);
ObjectSetText(p+".News: "+News_Array[p,0], News_Array[p,2]+": "+News_Array[p,1], 8);
}
if(Display_High == true && News_Array[p,2] == "High")
{
ObjectCreate(p+".News: "+News_Array[p,0],OBJ_VLINE,0,StrToTime(News_Array[p,0]),NULL);
ObjectSet(p+".News: "+News_Array[p,0],OBJPROP_COLOR,Market_Event_Color);
ObjectSet(p+".News: "+News_Array[p,0],OBJPROP_WIDTH,1);
ObjectSet(p+".News: "+News_Array[p,0], OBJPROP_BACK, true);
ObjectSet(p+".News: "+News_Array[p,0],OBJPROP_STYLE,STYLE_DOT);
ObjectSetText(p+".News: "+News_Array[p,0], News_Array[p,2]+": "+News_Array[p,1], 8);
}
}
// ==================================
// DEBUG TOOL - PRINTS ARRAY CONTENTS
// ==================================
//for (p = 0; p < (ArraySize(News_Array)/5); p++)
// {
// Print(News_Array[p,0]+" "+News_Array[p,1]+" "+News_Array[p,2]+" "+News_Array[p,3]+" "+News_Array[p,4]);
// }
return(0);
}
// =================================================================================================
// Check News function
// =================================================================================================
int Check_News ()
{
for (int p = 0; p < (ArraySize(News_Array)/5); p++)
{
if (TimeCurrent()-TimeSeconds(TimeCurrent()) == (StrToTime(News_Array[p,0])-Warning_In_Mins) && News_Array[p,4] == "0")
{
if (Low_Alerts == true && News_Array[p,2] == "Low")
{
Alert(News_Array[p,1]+" rated "+News_Array[p,2]+" occurs in "+Warning_In_Mins/60+"mins.");
News_Array[p,4] = "1";
}
if (Medium_Alerts == true && News_Array[p,2] == "Medium")
{
Alert(News_Array[p,1]+" rated "+News_Array[p,2]+" occurs in "+Warning_In_Mins/60+"mins.");
News_Array[p,4] = "1";
}
if (High_Alerts == true && News_Array[p,2] == "High")
{
Alert(News_Array[p,1]+" rated "+News_Array[p,2]+" occurs in "+Warning_In_Mins/60+"mins.");
News_Array[p,4] = "1";
}
}
}
return(0);
}
// =================================================================================================
// Delete_Old_News function
// =================================================================================================
int Delete_Old_News()
{
for (int p = 0; p < (ArraySize(News_Array)/5); p++)
{
if (iTime(Symbol(),PERIOD_D1,0) > StrToTime(News_Array[p,0]))
{
ObjectDelete(p+".News: "+News_Array[p,0]);
}
}
return(0);
}
Comments