First post in this nice trading forum.
As many of you already know, there is a nice news indicator called FFCal, developed initially by DerkWehler at the FF forum (http://www.forexfactory.com/showthread.php?t=19293).
I've observed that in some of the EA's there is talk to implement a news filter, so I have tinkered (a lot) with the original indicator to have something that can easily be incorporated to an EA without problems (probably I'll tinker a little with one of the EAs myself to make some tests).
Here is my modified version of the FFCal indicator, called FFCalMOD. Please be aware that the code has been heavily modified to suit my needs (especially backtesting), so you can consider it almost a "fork" of the original.
Changes introduced are:
- Related Calencar functions externalized to library. This library is easily usable from an EA.
- The indicator / funtions have been abstracted from the source used (ForexFactory or DailyFX).
- Additional graphic capabilities added (future events lines, coloring of vertical lines, ...).
- Many parts of the code have been rewriten from scratch.
- Backtesting capabilities added. The indicator can instruct the library to use an External Time reference. This reference can be easily provided by the EA under test adding the following line of code at the beginning of the start() function:
TimeLocal() Returns local computer time as number of seconds elapsed from 00:00 January 1, 1970. But at the testing, local time is modelled and is the same as the modelled last known server time. This means TimeLocal() = TimeCurrent() when testing, but many times TimeLocal() != TimeCurrent in real.Code: Select all
if(IsTesting()) GlobalVariableSet("_TimeReference", TimeCurrent());
Additionally, the time is only modeled into the EA context. If you backtest visually, the indicators set at the chart are not called by the EA, but the chart directly. The External Time Reference is my solution to this problem. - ForexFactory XML files are kept on a permanent basis with different name on a daily basis. This is done so to have backtesting capabilities for FF XML files.
- Added daylight saving zone awareness. It's needed to differenciate between the timezone of the broker and our time zone. The original indicator did not have into account that there can be GMT difference between the criminal and us. The library uses a file called daylightsavings.xml to keep track of the lightsaving periods.
- And many other changes ...
- Depurate visual filters to show only selected news.
All the needed files are at the attached ZIP file. Just copy the files at the corresponding directory under experts.
UPDATE (13/1/2014)
Changes in v20d2:
- Corrected libraries directory.
- Added functions for easiest access from EA (see example below).
Please be aware that this is only a sample template that does not implement a filter for the current pair. In other words, it sets a time window for any event of the selected criticity.
Something like this ...
At the beginning for configuration:
Code: Select all
#include "LibNEWS_B6a.mqh"
extern string __MODULE_NEWS_FILTER__ = "____________________________________________________";
extern string __MODULE_NEWS_FILTER_title__ = "=== NEWS FILTER SECTION === ";
extern bool NEWS_UseNewsFilter = false;
extern string __events_selection__ = "--- NEWS EVENTS SELECTION ---";
extern int NEWS_SelectEventsWithCriticity = 3; // 0: Everything; 1: Low; 2: Medium; 3: High
extern string __timezones_configuration__ = "--- SOURCE AND TIMEZONES CONFIGURATION ---";
bool NEWS_AutoGMTZones = false; // Set this to FALSE. It does not work ... yet!
extern int NEWS_LocalGMTZone = 1; // GMT+X
extern int NEWS_BrokerGMTZone = 2; // GMT+Y
extern bool NEWS_UseDailyFXAsSource = true; // Set this to TRUE when backtesting
extern bool NEWS_UseGlobalTimeReference = true; // Set this to TRUE when back
extern string __events_window__ = "--- TRADE WINDOW FOR EVENTS ---";
extern int NEWS_MinutesBeforeNews = 7; // Set to -1 for no Alert
extern int NEWS_MenutesAfterNews = 21; // Set to -1 for no Alert
Code: Select all
// Initialization of the NEWS FILTER LIBRARY
NEWSSetTimeReference (NEWS_UseGlobalTimeReference);
NEWSSetTimeOffset (NEWS_AutoGMTZones, NEWS_LocalGMTZone, NEWS_BrokerGMTZone);
NEWSInitLibrary ();
Code: Select all
// News filtering logic DEINIT
NEWSDeinitLibrary();
// External time reference DEINIT
GlobalVariableDel("_TimeReference");
Code: Select all
// Code for the external Time Reference ...
if(IsTesting()) GlobalVariableSet("_TimeReference", TimeCurrent());
// Perform news checks once per minute
// (Only needed if the NEWSMOD filters has been included.
static int previousMinute;
if (NEWS_UseNewsFilter) {
if (TimeMinute(AltTimeLocal()) != previousMinute && !IsTesting()) {
previousMinute = TimeMinute(AltTimeLocal());
NEWSRefreshEvents (NEWS_UseDailyFXAsSource);
}
}
Code: Select all
bool DoNewsAllowsTrade() {
if (NEWS_SelectEventsWithCriticity < 0)
return (true);
bool skipThisEvent = false;
datetime now = TimeLocalToGMT(AltTimeLocal());
// Get the currency pair, and split it into the two countries
string pair = Symbol();
string country1 = StringSubstr(pair, 0, 3);
string country2 = StringSubstr(pair, 3, 3);
// string previousEvent[8];
// int previousEventIndex = NEWSPreviousEvent (3, previousEvent);
// int previousTime = StrToTime (previousEvent[NEWS_GMT]);
static datetime previousTime = 0;
static datetime actualTime = 0;
string nextEvent[8];
int nextEventIndex = NEWSNextEvent (NEWS_SelectEventsWithCriticity, nextEvent);
datetime nextTime = StrToTime (nextEvent[NEWS_GMT]);
// Test against filters that define whether we want to skip the selected announcement
if (country1 != nextEvent[NEWS_COUNTRY] && country2 != nextEvent[NEWS_COUNTRY])
skipThisEvent = true;
// if (ReportAllForAll)
// skipThisEvent = false;
// if (!SelectSpeaksEvents && (StringFind(eventData[NEWS_TITLE], "speaks") != -1 ||
// StringFind(eventData[NEWS_TITLE], "Speaks") != -1) )
// skipThisEvent = true;
if (nextEvent[NEWS_TIME] == "All Day" ||
nextEvent[NEWS_TIME] == "Tentative" ||
nextEvent[NEWS_TIME] == "")
skipThisEvent = true;
if (now > actualTime && !skipThisEvent) {
previousTime = actualTime;
actualTime = nextTime;
}
if (previousTime > 0 && nextTime > 0)
if ((now - previousTime) < (NEWS_MenutesAfterNews * 60 ) || (nextTime - now) < (NEWS_MinutesBeforeNews * 60))
return (false);
return (true);
}
Constructive feedback will be always welcomed!!!
Best & kind regards,
Sergien