Automationยท

How to Add a News Filter to Your MT4 Expert Advisor

MetaTrader 4 has no economic calendar for Expert Advisors. This guide adds one in ten minutes: a free calendar API, one include file, one function to call before every entry. Full MQL4 code, no API key.

An Expert Advisor that trades through Non-Farm Payrolls or a rate decision is not trading its strategy: it is flipping a coin with a wide spread. A news filter fixes that. It pauses new entries for a few minutes before and after the releases that move the market, and lets the strategy do its job the rest of the time.

MetaTrader 5 has a calendar built in. MetaTrader 4 does not, so the EA has to fetch the news from somewhere. This guide uses the free ShowMyTrades economic calendar API: no account, no API key, one URL to allow in the terminal, and an include file you can paste into any EA.

๐Ÿงญ What You Are Building

every 15 minutes          every tick
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ download the next โ”‚ โ”€โ”€โ–บ โ”‚ is a release within            โ”‚
โ”‚ 2 days of news    โ”‚     โ”‚ [-30 min, +30 min] of now?     โ”‚
โ”‚ (CSV, one request)โ”‚     โ”‚   yes โ†’ no new entries         โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜     โ”‚   no  โ†’ run the strategy       โ”‚
                          โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
DecisionDefault in the codeWhy
Which currenciesEUR,USDThe two sides of the pair you trade. Empty means all nine majors
Which impacthighhigh,medium for a more cautious filter
Pause before30 minutesSpreads widen and liquidity thins before the number
Pause after30 minutesThe first reaction and the reversal both happen here
Download interval15 minutesThe calendar changes a few times a day; the API caches for 15 minutes anyway

๐Ÿ”‘ Step 1: Allow the Address in MetaTrader

WebRequest(), the MQL4 function that downloads from the internet, only talks to addresses you have approved. In the terminal open Tools โ†’ Options โ†’ Expert Advisors, tick Allow WebRequest for listed URL and add:

https://showmytrades.com

Skip this and the download returns -1 with error 4060. The include file prints a reminder in the Experts tab when that happens, so you will not wonder why the filter is silent.

๐Ÿ“„ Step 2: Save the Include File

Save the following as SMT_NewsFilter.mqh in the MQL4\Include folder of your terminal (File โ†’ Open Data Folder). It is the same file documented in the API reference, and it also compiles in MQL5 unchanged.

SMT_NewsFilter.mqh
//+------------------------------------------------------------------+
//| SMT_NewsFilter.mqh - news filter for MT4 and MT5                 |
//| Data: https://showmytrades.com/api/public/calendar/v1 (free)     |
//| Docs: https://showmytrades.com/docs/api/economic-calendar        |
//| Setup: Tools > Options > Expert Advisors > Allow WebRequest for  |
//|        https://showmytrades.com                                  |
//+------------------------------------------------------------------+
#property strict

input string SMT_Currencies     = "EUR,USD"; // News: currencies (comma-separated, empty = all)
input string SMT_Impact         = "high";    // News: impact (high | high,medium | all)
input int    SMT_MinutesBefore  = 30;        // News: pause before a release (minutes)
input int    SMT_MinutesAfter   = 30;        // News: pause after a release (minutes)
input int    SMT_RefreshMinutes = 15;        // News: download interval (minutes, min 15)

datetime smt_eventTime[];
string   smt_eventTitle[];
datetime smt_nextDownload = 0;

//--- everything after the n-th comma (the CSV title, which may itself contain commas)
string SMT_AfterComma(const string line, const int n)
{
   int pos = -1;
   for(int i = 0; i < n; i++)
   {
      pos = StringFind(line, ",", pos + 1);
      if(pos < 0) return "";
   }
   string rest = StringSubstr(line, pos + 1);
   StringReplace(rest, "\"\"", "\"");
   if(StringLen(rest) >= 2 && StringGetCharacter(rest, 0) == '"')
      rest = StringSubstr(rest, 1, StringLen(rest) - 2);
   return rest;
}

//--- downloads the next 2 days (the window also covers the last 6 hours)
bool SMT_Download()
{
   string url = "https://showmytrades.com/api/public/calendar/v1?format=csv&days=2&impact=" + SMT_Impact;
   if(StringLen(SMT_Currencies) > 0) url += "&currency=" + SMT_Currencies;

   char   post[], result[];
   string headers;
   ResetLastError();
   int status = WebRequest("GET", url, "", NULL, 10000, post, 0, result, headers);
   if(status != 200)
   {
      Print("[SMT] calendar download failed: HTTP ", status, ", error ", GetLastError(),
            ". Is https://showmytrades.com in Tools > Options > Expert Advisors > Allow WebRequest?");
      smt_nextDownload = TimeCurrent() + 60; // retry in a minute
      return false;
   }

   string body = CharArrayToString(result, 0, WHOLE_ARRAY, CP_UTF8);
   string lines[];
   int n = StringSplit(body, '\n', lines);

   ArrayResize(smt_eventTime, 0);
   ArrayResize(smt_eventTitle, 0);
   for(int i = 1; i < n; i++) // line 0 is the header
   {
      string f[];
      if(StringSplit(lines[i], ',', f) < 8) continue;
      int k = ArraySize(smt_eventTime);
      ArrayResize(smt_eventTime, k + 1);
      ArrayResize(smt_eventTitle, k + 1);
      smt_eventTime[k]  = (datetime)StringToInteger(f[0]);      // Unix seconds, UTC
      smt_eventTitle[k] = f[2] + " " + f[3] + ": " + SMT_AfterComma(lines[i], 7);
   }
   smt_nextDownload = TimeCurrent() + MathMax(SMT_RefreshMinutes, 15) * 60;
   Print("[SMT] calendar: ", ArraySize(smt_eventTime), " events loaded");
   return true;
}

//--- true while a release is within the pause window; reason tells which one
bool SMT_IsNewsTime(string &reason)
{
   reason = "";
   if(MQLInfoInteger(MQL_TESTER)) return false;   // no network in the tester
   if(TimeCurrent() >= smt_nextDownload) SMT_Download();

   datetime now = TimeGMT();
   for(int i = 0; i < ArraySize(smt_eventTime); i++)
   {
      if(now >= smt_eventTime[i] - SMT_MinutesBefore * 60 && now <= smt_eventTime[i] + SMT_MinutesAfter * 60)
      {
         reason = smt_eventTitle[i];
         return true;
      }
   }
   return false;
}

What it does, in order: builds the request from the inputs, downloads the CSV, keeps one timestamp and one label per event, and answers the only question the EA cares about: is a release within the window right now?

๐Ÿ”Œ Step 3: Call It Before Every Entry

In your EA, include the file and ask before opening a position:

YourEA.mq4
#include <SMT_NewsFilter.mqh>

void OnTick()
{
   string news;
   if(SMT_IsNewsTime(news))
   {
      Comment("News filter active: ", news);
      return;                       // no new entries during the news window
   }
   Comment("");
   // ... your entry logic ...
}

The five inputs (SMT_Currencies, SMT_Impact, and the three minute values) appear in the EA's input dialog like any other setting, so each chart can have its own.

Recompile, attach the EA, and look at the Experts tab: the first line should be [SMT] calendar: N events loaded. On a quiet day N can be zero, which is correct, not an error.

โฑ๏ธ Times, Clocks and the Tester

Three details decide whether the filter fires at the right minute.

The API speaks UTCts is Unix time in seconds, UTC. The code compares it with TimeGMT(), the computer's clock in UTC. Nothing depends on the broker's time zone or on daylight saving
Keep the clock rightOn a VPS, make sure Windows time synchronisation is on. A clock five minutes off shifts every window by five minutes
The strategy tester has no internetWebRequest() is disabled there, so the function returns "no news" in backtests. Testing a news filter on history needs a local file of past events, which is a different project

๐ŸŽ›๏ธ Tuning It

  • Open positions. The code only blocks new entries. Whether to close, tighten stops or widen them before a release is a strategy decision; the same SMT_IsNewsTime() tells you when to do it.
  • One side of the pair only. Set SMT_Currencies to USD if only dollar news matters to you.
  • Medium impact too. SMT_Impact = "high,medium" roughly triples the events. Good for scalpers, often too much for swing systems.
  • Holidays. impact=all includes market holidays as all-day events. Most filters do not want them; the default leaves them out.

๐Ÿ” Checking the Data

The same calendar is a page you can read: economic calendar. When the EA says it paused for "USD high: Nonfarm Payrolls", you can see the event there with its forecast and, after the release, its actual.

โ“ FAQ

Does this need a ShowMyTrades account? No. The calendar API is free and open, with no key. Track your account on ShowMyTrades if you want the verified public page, but the news filter does not depend on it.

How much traffic does it generate? One request every 15 minutes per chart, a few kilobytes each. Ten EAs on one terminal are 40 requests an hour. The limit is 600 per minute per IP address.

Why not read Forex Factory directly? You can, and many EAs do. Its weekly file allows two downloads every five minutes per IP address, which breaks on a VPS running many terminals, and it has no actual values. The ShowMyTrades endpoint filters by currency and impact on the server, returns a few kilobytes and is built for polling.

What if the download fails? The filter keeps the last calendar it loaded and retries after a minute. If it never loaded one (fresh start, no internet) it reports "no news", so the EA trades: if that is not what you want, check ArraySize(smt_eventTime) == 0 and decide.

Does the same file work in MT5? Yes, unchanged. MT5 also has a calendar of its own; use whichever suits you.


The filter is a page of code and a URL. If your EA is already tracked on ShowMyTrades, the trades it skips around the news will show up as the drawdown it did not take.