Cookies

We use analytics to improve the website, which helps us reach more people. Essential cookies are always on. Cookie Policy

Backtest Methodology

Last updated: September 19, 2026

Risk notice. Everything described on this page is a simulation over historical data. A backtest is a model, and a model is wrong in ways this page tries to make explicit rather than hide. Results are not a track record and not a prediction. Trading smallcaps involves substantial risk of loss.

1. Why this page exists

A backtest number is only worth as much as the assumptions behind it, and those assumptions are usually invisible. Two platforms can run the same rules over the same days and report returns that differ by a factor of several, purely through cost modelling and fill assumptions.

So this page states the assumptions. Where GapperLab makes a choice that flatters results, it is named. Where the model is known to be optimistic, it is named too, in section 7.

2. Market data and resolution

The timeframe is part of the strategy, not a platform constant. Each strategy declares the bar size its rules are evaluated on, and the simulation runs on intraday bars at that resolution. A strategy written on 15-minute bars is backtested on 15-minute bars, and comparing its results against a 1-minute strategy is comparing two different models, not two different edges.

Universe construction and previous-day reference levels are derived from daily aggregates over the same price history the intraday bars come from, so a rule that refers to "yesterday's high" and a rule that refers to an intraday level are reading a consistent record rather than two histories that can disagree.

One consequence worth stating plainly: the simulation inherits whatever is wrong in the underlying price history, including bad prints and corporate-action adjustments applied after the fact. Coverage is also thinner for very illiquid names than for liquid ones, which matters in this niche specifically, because illiquid names are where the most extreme moves happen.

3. What the gapper universe actually means

The word "gapper" is used loosely across the industry, so here is the definition this platform uses, which is broader than the common one.

A ticker-day enters the gapper segment when it moved at least 10% in any one of three separate windows:

  • the overnight gap, from the previous close to the open,
  • the premarket session,
  • the after-hours session of that same day.

Three clauses, not two. A stock that opened flat and then ran 30% in after-hours is in the segment. This matters when you reason about how many opportunities a strategy should have seen: applying the narrow "it opened with a gap" definition to this universe gives the wrong answer.

Related, because the name misleads: the gap-streak filter counts consecutive days a stock ran, not consecutive days it gapped, and it is capped at 11. A minimum of zero on that filter is a no-op, not a way to say "no streak".

4. R, and why every metric is expressed in it

R is the unit of risk. One R is what a single trade was designed to lose if the stop had been hit exactly as planned. A result of +2R means the trade made twice what it risked.

result_r = pnl_usd / risk_usd

The denominator is what the stop was meant to cost. Expressing results in R rather than in percent is what makes trades of different sizes comparable, and it is why the platform reports expectancy, Sharpe and drawdown in R terms.

R is net, not gross. The numerator is realised profit and loss after commission and after short-locate fees, so every downstream metric that hangs off R already reflects those costs. A pre-cost R exists as an internal intermediate, because feeding a cost-adjusted number back into position sizing would charge commission twice, but it is never displayed and never returned anywhere.

5. Cost model

Three costs are modelled, and they are applied at different stages, which is worth understanding because it changes what a reported figure includes.

  • Slippage is applied directly to the fill price, and always in the direction that works against the position: added to the entry price on a long, subtracted on a short. It can be configured as a flat amount per share or as a percentage, and in percentage mode the per-share cost is derived per ticker-day from that day's price level rather than from a single global constant.
  • Commission is applied to the profit and loss of the trade, and can be configured as a flat amount or as a percentage.
  • Short-locate fees are modelled per share and apply to short positions only, which is the honest treatment: locate is a real and often dominant cost of shorting hard-to-borrow smallcaps, and a model that ignores it makes short strategies look far better than they are.

All three flow into pnl_usd, and therefore into R, and therefore into every aggregate metric.

6. Entries, exits and position sizing

Entry price. By default a trade enters at the close of the bar that produced the signal, adjusted by the configured limit offset, with slippage applied against the position. If instead you configure a specific entry price, the simulation requires the following bar to actually trade through that price before filling: if it does not, no trade is taken. That is the conservative treatment, and it is why a price-triggered configuration produces fewer trades than a market-entry one over the same signals.

Position sizing is based on a fixed dollar risk per trade in every mode except the percent-of-account mode. The number of shares follows from that risk budget and the distance to the stop, so a wider stop buys fewer shares for the same risk.

Stops and targets are evaluated bar by bar at the strategy's own timeframe, including partial exits at multiple targets, in which case the reported R for the trade is the size-weighted blend of the legs and the remainder.

7. What this model does not capture

This is the section that matters most, and the one most backtest tools omit. Every item below makes reported results better than reality, not worse.

  • Liquidity is not enforced. The simulation does not check that the market could have absorbed your size at that price. On a thin smallcap, a position that looks fine in the model can be a meaningful share of the minute's volume.
  • Borrow availability is not modelled. Locate cost is modelled; locate availability is not. A short the simulation takes may have been impossible to open because no shares were locatable at any price.
  • Halts are not simulated as halts. Smallcaps halt on volatility, and a halt removes your ability to exit precisely when you most want to. The simulation continues across the gap in the data.
  • Slippage is a parameter, not a market impact model. It does not widen with your size, with volatility, or in the first minute of the session, which is exactly where real slippage is worst.
  • Intrabar ordering is unknown. A bar records its high and its low but not which came first, so any rule whose outcome depends on that ordering is resolved by convention rather than by fact. This is not a rounding detail: it is the difference between a stop and a target both being reachable in the same bar, and the coarser the strategy's timeframe, the more of the session falls inside that blind spot.
  • Survivorship and data revisions. The historical universe is the one the price history records today, including corporate actions and corrections applied after the fact, not the universe as it appeared at the time.

The practical reading: treat a backtested edge as an upper bound on the live edge, and treat a strategy whose edge only survives at low cost assumptions as not having an edge.

8. How to read the metrics

Some standard metrics are actively misleading in this asset class, and the platform takes documented positions on them.

  • Win rate is never decisive. Win rate improves when you widen the stop. So do profit factor and recovery factor. All three reward exactly the change that makes a strategy more dangerous, so none of them is used as a weighted axis in the platform's own scoring.
  • A high Sharpe is not automatically suspicious here. Sharpe is annualised by frequency, and an intraday strategy with hundreds of trades per year produces high values in the normal case, not the pathological one.
  • The left tail is not visible in R. Per-trade R skew is positive by construction, because the stop caps losses near minus one R. Reading that as "this strategy has no tail risk" is the classic error. The correct lens is the conditional average of the worst losses against the nominal one R: a stop that holds gives about one R, and the excess over that is the stop failing, through gap-throughs, slippage or halts.
  • Diversification across strategies is weaker than it looks. Average pairwise correlation understates joint risk, because what matters is co-loss on the worst days, and on those days most strategies lose together.

9. Backtest and live agreement

The rules you backtest and the rules that watch the live session are held to each other automatically: both which trades trigger and what each metric evaluates to are compared, and a disagreement is treated as a defect. This matters more than it sounds. A platform where the tested behaviour and the live behaviour drift apart produces confidence that was never earned, which is worse than producing nothing.

The limitation is worth stating: what that guarantees is that the rules are evaluated the same way in both places. Whether the live market data reaching those rules is complete and timely on any given morning is a separate question, and no rule comparison can answer it.

10. Corrections

If something on this page is wrong, incomplete, or does not match what the platform actually does, that is a defect and it is worth reporting to info@gapperlab.com. This page is versioned with the product and carries the date it was last revised.

More about the product and who operates it is on the about page.