Articles ·

What a Metrand backtest accepts as market data

A backtest is only as true as the bars it is given. A single malformed candle can open a position at a price the market never traded, a timestamp off by a factor of a thousand can turn a year into a few hours, and bars sent newest-first can make a strategy decide on the future. So the engine checks every bar before it replays anything, and refuses the request with the first bar that fails and the reason.

The same checks apply to the bars of the market the strategy trades, to every other market it reads, and to the finer candles that can be sent under the bars.

A bar whose high is at or above its open and close and whose low is at or below them; a series moving forward in open time with a hole of missing bars
Every bar is checked, the series runs forward, and bars the exchange lacks are counted.

Every bar

Field Rule
o, h, l, c finite numbers above zero
h, l the high at or above both the open and the close; the low at or below both
v finite and not negative (it may be left out, and is then 0)
t the bar's open time, in milliseconds since 1970-01-01 UTC, not negative

The series

Where a window ends

A window ends at the last bar that had closed by its end time. An end time in the middle of an hour ends an hourly window at the bar before, never at one running past the moment asked for, and never at the bar still forming now.

Only the traded market's own bars

A backtest replays the bars of the market a strategy trades: Binance USDⓈ-M futures or Bybit perpetuals. The 5- and 15-second bars the platform's charts fold from Binance spot seconds are a different market, and the futures market publishes no second bars, so a backtest refuses those timeframes instead of quietly replaying spot prices.

Other markets

A strategy that reads other markets gets their bars on the same timeframe as the market it trades. Bars are merged in the order they open, which is the order they close in only when they last as long: a 4-hour bar of another market sent under a 1-hour strategy would reach it hours before it closed, so the request is refused. When the bars of two markets open at the same moment, the traded market's comes first, as a live run receives them.

Bars the exchange does not have

Exchange histories have holes: maintenance, outages, gaps in the published archives. A hole is the market's history, not an error, so the engine replays across it the way the market resumed: a position held over a gap is marked at the next bar's open, and a stop the price gapped past fills there.

What changes is that the hole is no longer invisible. The report says how many bars were missing between the first and the last bar, and the longest stretch without one (report.config.missing_bars, report.config.largest_gap_ms), and the app shows it under the result.

Running these checks over five years of 15-minute Binance futures history for ten major coins found every bar sound, and one hole: three days in LTCUSDT, XLMUSDT and XRPUSDT, 480 missing bars each, which earlier reports had skipped over without a word.

Funding

Funding settlements must be in time order, each with a finite rate given as a fraction per settlement (0.0001 is 0.01%). A rate above 10% in absolute value is refused as a percentage sent by mistake.

A funding series must also be whole over the traded span: no stretch of more than 8½ hours — the longest interval any venue settles on, and half an hour for the newest settlement to be published — without one. A series with a hole would charge part of the window and leave the rest free without saying so. Sending no funding at all is allowed: the backtest then runs without it, and the report says funding_applied: false. The platform's own funding history passed this check over five years of ten major coins, including the three days their candles were missing.

In the API

A refused request answers with an error that starts with backtest_candles_invalid: or backtest_funding_invalid: and names the series (the traded market, detail, or the other market's instrument), the bar's index and what is wrong with it, so a client or an AI agent can fix the data and send it again.