Guides

How to Connect MetaTrader 4 to a Free Web Signal With WebRequest

By Poverty Sux International, LLC · Published · 9 minute read

Analysis, not financial advice. Automated trading can lose money quickly. Test everything on a demo account first.

MetaTrader 4 can read data from the internet without any extra software. The built-in WebRequest() function lets an Expert Advisor or a script download a web page or a small text file, then act on what it finds. This guide shows how to connect MetaTrader 4 to a free signal feed, such as the hourly gold reading published on our signal feed page, and how to fix the error that stops most people on their first try: error 4060.

What WebRequest does, and where it works

WebRequest() sends an HTTP request (GET or POST) to an address and waits for the reply. It returns the HTTP status code, such as 200 for success, or -1 if the request failed before a reply arrived. When it returns -1, GetLastError() tells you why.

Three rules from the MQL4 documentation matter more than anything else:

  1. The address must be allowed in the terminal. MetaTrader 4 refuses to contact any website that is not on its allowed list.
  2. It only runs in Expert Advisors and scripts. It cannot be called from a custom indicator. Indicators run in a common thread shared by all indicators and charts on one symbol, so one indicator waiting on the network could freeze every chart of that symbol.
  3. It does not run in the Strategy Tester. A back test cannot download live data, so you need a separate plan for testing (see the frequently asked questions below).

The call is also synchronous: the Expert Advisor pauses until the reply arrives or the timeout expires. Keep requests small and infrequent, and never call WebRequest() on every tick.

Step 1: Allow the address in MetaTrader 4

  1. In MetaTrader 4, open Tools, then Options.
  2. Select the Expert Advisors tab.
  3. Tick Allow WebRequest for listed URL.
  4. Add the site's base address on a new line, for example https://povertysux.co. You do not need to add the path to the file, and you do not need to add a port, because MetaTrader picks port 443 for addresses that start with https and port 80 for http.
  5. Click OK, then remove and re-attach the Expert Advisor so the setting takes effect.

While you are on that tab, make sure Allow automated trading is also enabled if you intend the Expert Advisor to place orders. Reading a signal does not require it.

Step 2: Understand the feed format

A good free feed is boring on purpose: one short line of text that a program can split without a parser library. Our signal.txt file contains one line of ten fields separated by the pipe character (|), with no spaces. The field names, in order, are:

signal|signal_code|spot|updated_utc|valid_until_utc|support|resistance|invalidation|event_risk|version

A real line from 6:18 PM Eastern Time on October 26, 2026 looked like this:

BUY|1|4015.65|2026-10-26T22:18:02Z|2026-10-26T23:28:02Z|4007.90|4018.70|4022.00|0|1

The two fields that matter most are the numeric signal_code (easier to compare than text) and valid_until_utc, the time after which the reading should be treated as stale. A reading that is past its expiry time is not a signal at all; it is old information. Any Expert Advisor that reads a web feed should check the expiry before using the value.

Expiry is normal, not an error. Readings are published every hour from Sunday 6 PM to Friday 5 PM New York time, with no update during the daily 5 PM to 6 PM break. Because each reading expires 70 minutes after its own price sample, the file is legitimately expired for part of every evening around the break, and from about 5:25 PM on Friday until the first update after 6 PM on Sunday. Treat those times as "no signal".

The full field list, including the JSON and CSV versions, is on the signal feed documentation page.

Step 3: A minimal Expert Advisor that reads the feed

The example below polls the feed every five minutes using a timer, splits the line, checks the expiry time and shows the result in the chart's corner. It does not trade. Add your own order logic only after you have watched it run correctly on a demo account.

#property strict

input string SignalURL   = "https://povertysux.co/signal.txt";
input int    PollSeconds = 300;    // five minutes; the feed updates hourly
input int    TimeoutMs   = 5000;   // give up after five seconds

datetime g_lastPoll   = 0;
string   g_signal     = "";
int      g_code       = 99;        // 99 is this Expert Advisor's own "no reading" value; the feed never sends it
datetime g_validUntil = 0;

// Forget the stored reading so a failed download can never leave an old value in use.
void ClearReading()
{
   g_signal     = "";
   g_code       = 99;
   g_validUntil = 0;
}

// Converts "2026-10-26T21:23:00Z" into an MQL4 datetime (UTC).
datetime IsoToTime(string iso)
{
   string s = iso;
   StringReplace(s, "-", ".");
   StringReplace(s, "T", " ");
   StringReplace(s, "Z", "");
   return StringToTime(s);
}

bool FetchSignal()
{
   ClearReading();                 // a failure on any path below leaves "no reading"
   char   post[], result[];
   string replyHeaders;
   ResetLastError();
   int status = WebRequest("GET", SignalURL, NULL, NULL, TimeoutMs,
                           post, 0, result, replyHeaders);
   if(status == -1)
   {
      int err = GetLastError();
      if(err == 4060)
         Print("Error 4060: add the site address under Tools > Options > ",
               "Expert Advisors, and run this as an Expert Advisor, not an indicator.");
      else
         Print("WebRequest failed, error ", err);
      return false;
   }
   if(status != 200) { Print("Server answered with HTTP ", status); return false; }

   string body = CharArrayToString(result, 0, WHOLE_ARRAY, CP_UTF8);
   body = StringTrimRight(StringTrimLeft(body));

   string f[];
   if(StringSplit(body, '|', f) < 10) { Print("Unexpected reply: ", body); return false; }
   for(int i = 0; i < ArraySize(f); i++) f[i] = StringTrimRight(StringTrimLeft(f[i]));

   g_signal     = f[0];
   g_code       = (int)StringToInteger(f[1]);
   g_validUntil = IsoToTime(f[4]);
   if(g_validUntil <= 0) { Print("Unreadable expiry time: ", f[4]); ClearReading(); return false; }
   return true;
}

bool SignalIsFresh() { return g_validUntil > 0 && TimeGMT() < g_validUntil; }

int OnInit()
{
   EventSetTimer(30);
   g_lastPoll = TimeLocal();
   FetchSignal();
   return INIT_SUCCEEDED;
}

void OnDeinit(const int reason) { EventKillTimer(); Comment(""); }

void OnTimer()
{
   if(TimeLocal() - g_lastPoll >= PollSeconds)
   {
      g_lastPoll = TimeLocal();
      FetchSignal();
   }
   if(!SignalIsFresh()) { Comment("Gold signal: missing or expired"); return; }
   Comment("Gold signal: ", g_signal, " (code ", g_code, "), valid until ",
           TimeToString(g_validUntil), " UTC");   // UTC = Coordinated Universal Time
}

A few design choices are worth copying even if you write your own version:

If you prefer not to write the parsing yourself, the free include file and example Expert Advisor linked from the signal feed page wrap the same steps in two functions.

How to fix error 4060

Error 4060 is named ERR_FUNCTION_NOT_CONFIRMED in MQL4, with the description "Function is not allowed for call". In practice it shows up in three situations. Check them in this order:

  1. The address is not on the allowed list, or the box is unticked. Go back to Step 1. Check the spelling, check https against http, and remove any trailing spaces. The address you list must match the start of the address in your code.
  2. The code is running inside an indicator. Indicators cannot call WebRequest(). Move the network call into an Expert Advisor or a script. If you need the value inside an indicator, have the Expert Advisor store it in a global variable of the terminal (GlobalVariableSet()) and read it from the indicator.
  3. The terminal has not picked up the new setting. Remove the Expert Advisor from the chart and attach it again. If that fails, restart MetaTrader 4.

Two related errors are easy to confuse with it. The MQL4 reference says WebRequest() cannot be executed in the Strategy Tester; the code you see there is typically error 4059 (ERR_FUNC_NOT_ALLOWED_IN_TESTING, "Function is not allowed in testing mode"). In MetaTrader 5 the indicator case usually reports error 4014 instead; in MetaTrader 4, 4014 means something else ("unknown command"). If you get an HTTP status such as 403 or 404 rather than -1, the terminal did connect: the problem is the address or the server, not the permission.

Other common problems

Testing without the Strategy Tester

Because WebRequest() does not run in the tester, separate the network part from the decision part. Our signal history page publishes signal-history.json, but it holds only the last 24 hourly readings, for the hourly timeframe only. If you want weeks of test data, have your Expert Advisor log each reading it downloads to a file, then write a test version that reads those saved values from the local file instead of the web. Then forward-test the live version on a demo account for at least several weeks before considering anything else.

A word on using any signal

A signal is a summary of indicators, not knowledge of the future. Read the technical summary to see how ours is built, size every position so that being wrong is affordable, and read the disclaimer before connecting any feed to real money.

Frequently asked questions

Can I call WebRequest from a custom indicator?

No. MetaTrader 4 only allows WebRequest() in Expert Advisors and scripts. Fetch the data in an Expert Advisor and pass it to the indicator through a terminal global variable or a file.

Do I have to list the full file address in the options?

No. Listing the site's base address, such as https://povertysux.co, covers the files under it. The protocol must match the one in your code.

Why does my Expert Advisor work live but fail in the Strategy Tester?

WebRequest() cannot run in the Strategy Tester, which typically shows up as error 4059. Test the logic with readings you have saved to a file instead.

How often should I poll a free feed?

Match the feed's update schedule. For an hourly signal, every five minutes is more than enough and keeps load on the server and your terminal low.

Is it safe to trade automatically on a free signal?

No signal is safe in the sense of guaranteeing a result. Use a demo account first, check the expiry on every reading, and decide in advance what your Expert Advisor does when the feed is missing.

Analysis, not financial advice. Poverty Sux does not manage money or recommend trades.

Not financial advice. This guide is general education about how technical tools and markets work. It does not consider your situation, and trading gold, especially with leverage, can lose more than you deposit. Read the disclaimer.