MQL5 Market Validator testing an XAUUSD EA on other symbols — APIs, external data and validation errors

Hello everyone,

I would like to ask for advice from developers who have experience publishing Expert Advisors on the MQL5 Market, especially EAs designed for a specific symbol and using external data/APIs.

I have developed an Expert Advisor specifically for XAUUSD (Gold). The EA is not a multi-symbol Forex EA and it is not designed to trade EURUSD, GBPUSD, or other currency pairs.

The EA uses a combination of:

  • XAUUSD market data;

  • technical calculations based on the XAUUSD chart;

  • external market data obtained through APIs;

  • additional external data used as filters/confirmation;

  • internal calculations and trading rules specifically designed for Gold.

The EA works correctly in my own MT5 Strategy Tester when tested on XAUUSD.

However, during MQL5 Market automatic validation, the EA is being tested on other symbols and timeframes. The validation report contains:

test on EURUSD,H1 (netting) there are no trading operations test on XAUUSD,D1 (netting) there are no trading operations test on GBPUSD,M30 (netting) 2025.02.01 00:00:01 failed market sell 0.1 GBPUSD sl: 1.24512 tp: 1.22766 [Market closed] strategy tester report 243 total trades

This raises several questions for me.

The most important point is that GBPUSD is not the intended trading instrument of this EA.

The EA is designed around XAUUSD-specific behavior and data. Therefore, testing its trading logic on GBPUSD does not represent the actual conditions for which the product was developed.

There is also another issue involving external APIs.

The EA uses external data sources through HTTP/WebRequest. Those APIs provide information related to the market conditions used by the XAUUSD strategy.

Therefore, when the Market Validator tests the EA on EURUSD or GBPUSD, the external data and calculations are still related to the XAUUSD strategy, while the chart symbol being tested is a completely different instrument.

I am concerned that this creates an artificial validation scenario:

EA strategy = XAUUSD
External data = XAUUSD / Gold related
Chart being tested = GBPUSD

The result is not representative of how the EA is actually intended to operate.

I would like to understand the correct MQL5 Market approach for this type of product.

My questions are:

  1. Is it acceptable to publish an EA that is intentionally restricted to XAUUSD?

  2. If so, what is the recommended way to restrict the EA to XAUUSD so that it does not attempt to trade other symbols during Market validation?

  3. Does the MQL5 Market Validator intentionally test every EA on symbols such as EURUSD and GBPUSD regardless of the symbol for which the EA was designed?

  4. How should an EA that uses external APIs/WebRequest behave during validation when the API data is specifically related to XAUUSD?

  5. Is the developer expected to make the EA generate valid trading behavior on every symbol used by the Validator, even when those symbols are completely outside the intended scope of the product?

  6. Could an API-dependent, symbol-specific EA be rejected simply because the Validator tests it under conditions that do not represent its intended use?

  7. What is the recommended implementation for an XAUUSD-only EA to gracefully ignore unsupported symbols without causing validation errors?

There is another interesting detail in my report.

The validator attempted:

failed market sell 0.1 GBPUSD [Market closed]

at:

2025.02.01 00:00:01

which was a Saturday.

At the same time, the complete test report shows:

strategy tester report 243 total trades

So the EA is not simply failing to trade. It is generating trading operations during the validation.

I am trying to understand whether I am approaching the MQL5 Market requirements incorrectly.

I do not want to simply add code that hides errors or artificially changes the strategy just to satisfy the Validator.

I would like to implement the correct solution for a symbol-specific XAUUSD Expert Advisor that uses external APIs/data.

If anyone has published a similar EA on the MQL5 Market, I would really appreciate hearing how you handled:

  • symbol restrictions;

  • Market validation on unrelated symbols;

  • WebRequest/API dependencies;


  • and validation errors caused by symbols that the EA was never designed to trade.

Thank you in advance for any advice.

Reinaldo Benevides Lima Da Silva:
The most important point is that GBPUSD is not the intended trading instrument of this EA.

Market products cannot be restricted like so.

You should read all of the Market Rules.

The proper way to guide users to use your EA only on XAUUSD is to emphasize that in your product description.
[Deleted]
Good questions — the policy side was already covered above, so I'll add the technical part. The validator intentionally runs every EA on several symbols and timeframes, and "there are no trading operations" is itself a failure condition, so the EA must complete clean runs with actual trades on symbols other than XAUUSD too. The practical approach most single-symbol EA authors use is to decouple the strategy from the chart symbol: build your gold signals from explicit XAUUSD indicator handles created in OnInit, and place the resulting trades on whatever the chart symbol is — that way validation passes while real users still run it on XAUUSD as your product description instructs. Make the WebRequest/API layer fault-tolerant with short timeouts and a fallback to indicator-only logic, since the validator environment may not reach your endpoints, and any unhandled network error becomes a validation failure. Also guard order sending with a market-open check, because the validator's test window can include weekends — which explains your Saturday "Market closed" error on GBPUSD. That isn't hiding errors; it's making the EA genuinely robust outside its home symbol, which is exactly what the Market review is checking for.
Reinaldo Benevides Lima Da Silva:
Two things in your description explain most of the failures, and neither is about the symbol itself.

1. WebRequest() is not executed in the Strategy Tester at all, and the validator is a tester run. So every API call fails there, your strategy never gets its data, and on any symbol you end up with "there are no trading operations". Check MQLInfoInteger(MQL_TESTER) and, in the tester, run a fallback path that trades on chart data only (even a simple, conservative rule). Live, use the API as normal and treat a failed request as "no signal", never as an error that stops the EA.

2. "[Market closed]" on Saturday dates usually means orders are being sent from OnTimer(). The timer keeps firing in the tester when there are no ticks, including weekends. Send orders from OnTick() only, or check the session first with SymbolInfoSessionTrade() for the current day and time.

After that, the "XAUUSD only" part is a description issue, as Ryan said: state it clearly and let the EA run harmlessly elsewhere. A useful pattern is to read XAUUSD data through its own handles (iATR("XAUUSD",...), CopyRates("XAUUSD",...)) if that symbol exists, and fall back to the chart symbol if it does not, so the validator always sees valid trades.

Hi Reinaldo, what does your EA use for signals in the local test when the API isn't available? WebRequest() doesn't work in the local Strategy Tester either, as the docs explain: https://www.mql5.com/en/docs/network/webrequest

I'd check that first. Using saved historical API data with the same trading rules can make sense, as long as the test only uses data available at that point in time. Adding a different rule just to produce trades under MQL_TESTER would mean testing a different strategy. Sending gold signals to GBPUSD changes what you're trading too.

Also, the Saturday error doesn't tell us whether the order came from OnTimer(). You'd need to trace where it was sent.

I haven't gone through your attached code, so I can't say what's causing it yet. Which functions handle a failed API request and choose the order symbol? Those would be a good place to start.
Documentation on MQL5: WebRequest / Network Functions
Documentation on MQL5: WebRequest / Network Functions
  • www.mql5.com
The function sends an HTTP request to a specified server. The function has two versions: 1. Sending simple requests of type "key=value...

One more validator failure that is easy to miss once the EA does trade on other symbols: the broker's volume limit.

My EA sizes each trade by risk (percent of equity to the stop-loss). It was built for USDJPY, and the validator also ran it on GBPUSD M30, where the calculated lot came out at 5.16. The order was rejected three times with "Volume limit reached" and that version failed. SYMBOL_VOLUME_LIMIT is the maximum total volume of open positions and pending orders in one direction on a symbol (0 means no limit), and the broker counts everything on that symbol, not only the EA's own trades. Clamping the lot to what is left fixed it:

double LimitRoom(const string sym, const bool is_buy)
{
   double lim = SymbolInfoDouble(sym, SYMBOL_VOLUME_LIMIT);
   if(lim <= 0) return DBL_MAX;                       // 0 = no limit
   double used = 0.0;
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
      if(PositionGetTicket(i) == 0 || PositionGetString(POSITION_SYMBOL) != sym) continue;
      if((PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) == is_buy)
         used += PositionGetDouble(POSITION_VOLUME);
   }
   for(int i = OrdersTotal() - 1; i >= 0; i--)
   {
      if(OrderGetTicket(i) == 0 || OrderGetString(ORDER_SYMBOL) != sym) continue;
      long t = OrderGetInteger(ORDER_TYPE);
      bool b = (t == ORDER_TYPE_BUY || t == ORDER_TYPE_BUY_LIMIT || t == ORDER_TYPE_BUY_STOP || t == ORDER_TYPE_BUY_STOP_LIMIT);
      if(b == is_buy) used += OrderGetDouble(ORDER_VOLUME_CURRENT);
   }
   return MathMax(0.0, lim - used);
}

After clamping, round the lot down to SYMBOL_VOLUME_STEP and skip the trade if the result is below SYMBOL_VOLUME_MIN.

A second one from the same week: on XAUUSD D1 the EA tried to trade while the symbol's trading session was closed, and every such order failed with "Market closed" (one report had 50 of them). Checking the session before sending, and simply waiting while it is closed, removed them:

bool SessionOpen(const string sym)
{
   MqlDateTime d;
   TimeToStruct(TimeCurrent(), d);
   int secs = d.hour * 3600 + d.min * 60 + d.sec;
   datetime from, to;
   bool any = false;
   for(uint i = 0; i < 10; i++)
   {
      if(!SymbolInfoSessionTrade(sym, (ENUM_DAY_OF_WEEK)d.day_of_week, i, from, to)) break;
      any = true;
      int f = (int)(from % 86400), e = (int)(to % 86400);
      if(to - from >= 86400 || (e == 0 && to > from)) e = 86400;
      if(secs >= f + 60 && secs < e - 60) return true;   // avoid the first and last minute
   }
   return !any;                                           // no sessions listed = treat as open
}