Ultimately by design the MT4 Tester doesn’t accommodate what you seek to do (backtest multiple pairs testing in aggregate) but depending on the nature of your strategy you could take advantage of the fact that MQL allows you to access multiple currencies via it’s APIs despite the currency you have selected.
This post is a programming approach to trying to get MQL to use one strategy on multiple pairs. For the possibily of exporting report data to Excel on a per-pair-test basis, I’m not in Windows and I don’t use MT4 to check this out but CSV exporting sounds like a route to investigate.
Ok so anyways, basically everything in MQL revolves around the start() method.
This method is called when ever a tick is generated for the currency pair you’re observing.
If you’ve run the tester with EUR/USD, everytime a tick is generated by the pair, the MT4 engine calls start() which then allows your strategy to make enquires to find out the bid, ask, high, low, close, etc for the pair.
However, taking a look at the APIs, you can see that methods such as iClose, iBid, iAsk, iMarketData?, etc allow you to supply a Symbol(pair). So even though the start() was called for EUR/USD, you can still use the APIs to enquire about other pairs like USD/JPY, GBP/EUR and so on.
What makes an automated strategy execute efficiently is the event driven nature of the core engine call start() whenever something happens. This prevents one from having to write a strategy that spends every single microsecond checking bids, asks, closes and so on and testing for them for changes before running trading logic.
Bar based logic
If you have a strategy that reacts when a new bar starts (old bar just closed) on any timeframe, you can use the MT4 apis to monitor the bar counts on any pair (and timeframe) and when bar count changes occur for any one pair run trading logic on or with respect to the last closed bar (or indeed the current forming bar). As the checks being done are happening from within start(), this means that you can only interrogate other pairs when the pair you are observing generates a new tick.
Using a Script, as opposed to an EA for your logic prevents you using the Tester but if the logic is already tested, using a Script allows you to remove the start() restriction and control all the logic with bar count checks across multiple pairs and timeframes.
Tick based logic
If you have a strategy that reacts to new ticks then you have a fundamental problem in so far as the code will execute only when the pair being observed received a new tick and kicks off start(). Once this has happaned, nothing stops you from interrogating other pairs as per above. We know from looking at a watchlist that ticks come in across all pairs but not necessarily at the same time.
For live trading purposes this means we cannot use tick based strategies on multiple currencies from within the same start() method but must open up separate charts for each pair and attach the strategy accordingly.
For Tester (or even just MT4) purposes, we can generally presume that no one will be testing an ultra high frequency strategy that simply must capture and onserve every single tick-level price change so we can afford not to capture every sub-second tick but make do with working within say a maximum 5 second window [slow markets can generate no tick for even longer sometimes - so use the most liquid pair as the pair that generates calls to start()].
So what we do is let the start() method execute for the EURUSD tick that just came in and then use
double lastTickTime = MarketInfo(“SOME PAIR”, MODE_TIME)
to obtain the last tick time on any pair, compare that against the last check we made to see if there’s been a change, then kick off the logic while relying on MODE_ASK, MODE_BID, etc or some of the iFunctions below to get the info needed:
int iBars( string symbol, int timeframe)
int iBars(“SOME PAIR”, PERIOD_M5 | PERIOD_M15 | etc) gives you bar counts
double iClose( string symbol, int timeframe, int shift)
double iClose(“SOME PAIR”, PERIOD_M5 | PERIOD_M15 | etc, 0 | 1 | etc) give you the close price of any bar
iHigh, iLow, iOpen, iLowest, iHighest, iTime can all help to get information on any pair and timeframe.
Needless to say we can access indicator data for any pair and timeframe in much the same way.
As we’re looking at other pairs from within EURUSD generated start() calls there will be moments other pairs will tick and these will be missed by the logic until EURUSD itself ticks. But also as the EURUSD is the most liquid we increase the opportunity to get as many calls to start() such that the shortest time exists between any other pair’s tick and our ability to catch it.
Also, the time it will take to go through all the pairs will impact the core MQL engine as start() should complete work as quickly as possible (under 2 seconds) then return ready for the next tick. MQL doesn’t allow you to use threads or at least to get threads requires some Win32 DLL coding to force the operating system to give you them.
So if one seeks to coordinate multiple pairs trading in one strategy (keeping track of money management centrally across multiple pairs and trades for example) the underlying infrastructure risk inherent in MQL make this a risk to the capital being traded.
Global variables however (both in the trading logic and the system ones accessible to each logic instance attached to a chart) are a way we can share information across each instance to effect coordinated management otherwise the best thing to do is give each pair a copy of the strategy and allow each one to trade Equity/p of the money by opening Lots/p contracts where p is the number of observed pairs (and therefore the number of strategies running).
Bottom line
Doing your pair tests independently presents the least headache then pour over the results to derive your aggregate picture. If you normally risk X percent on one pair and know you will risk X/4 when looking at four pairs, do 4 tests and risk X/4 each time. Obviously this wont support dynamic situations where you might say X risk on pair 1, X/2 on pair 2 and X/4 on pair 3 as these trades arise but hey, this is Metatrader and MQL and everything is happening within a sandbox.
Alternative
JForex? :20:
Multi-threaded, Backtest multiple pairs 100% tick and spread modelling quality, OnTickEvent(), OnBarEvent(), OnAccountMessageEvent(), OnEconomicNewAnnouncementEvent(), access to every type of Java library and codebase in existence (database, email, SMS, GUI, PDF, encryption, networking), institutional liquidity, PAMM, Gold/Silver, CFDs in the works, blah, blah, blah.
Depends on what you’re up to and how complex it is or needs to be. Or rather how demanding your strategy and approach ultimately is of your platform.