Quantitative Research

Portfolio lab

The published pages answer questions someone else asked. This one is the simulator behind them, opened up: choose the exit window, the holding period, how capital gets allocated when signals overlap, which slice of the universe to trade, what friction to assume, and how much money you actually have. Everything recomputes in your browser, on the raw events, every time you change something. Every published page on this site shows one configuration that someone else chose. This one recomputes the entire portfolio in your browser under whatever assumptions you set. Nothing here is precomputed except the raw events. The defaults are the pre-registered configuration — the one fixed before any result was seen. Everything you change from there is exploration, and the panel at the bottom tells you how much weight your exploration deserves.

Start from a preset

Four starting points, not four results. The published backtest reproduces the assumptions used on the rest of this site — flat 0.1% friction, unlimited positions. Measured friction swaps that flat number for the per-tier slippage measured from the data, everything else unchanged. Measured friction, 10-day hold also switches the exit window to 10 days, caps concurrent positions at 20, and turns on smart rotation. A $10,000 account, realistically starts from that same 10-day setup and adds what a small account actually faces: whole shares only, a $50 minimum position, and the position size capped at 1% of 20-day ADV.

Simulation setup

Execution & frictions

The published backtest assumes 0.1% per side. This strategy breaks even at 0.263% per side, and the spread estimated from our own daily highs and lows (Corwin-Schultz) sits above that in every price tier — read that as a ceiling, not as what you would pay. What we can measure directly is weaker than it first looked, in both directions. The 0.054% half-spread we measured in the small-cap third comes from a heavily selected subsample — names quoting continuously enough to build a full curve — and does not represent small caps. But the wider figures that appear when the filter is relaxed are not a measurement either: our intraday quotes come from IEX, and on names whose true spread is known to be 0.01-0.05% (over $200M average daily volume) the measured spread moves 13-fold with nothing but the number of quotes in the window — 0.596% where IEX showed fewer than 20, 0.045% where it showed over 500. Below roughly 500 quotes the number reflects feed coverage, not the spread. So the honest position is that we cannot yet measure execution cost where this strategy earns most of its return, and whether 0.1% per side is conservative or optimistic stays open until it is measured against a consolidated tape. That is why this is a control you can move, not a constant.
BrokerThe broker buttons only touch the friction fields, so you can combine any broker with any strategy above. They map to what each one actually charges on US equities: IBKR Lite is commission-free with smart routing, so the effective spread lands below the quoted one. IBKR Pro charges $0.005 a share with a $1 minimum per order — modelled here as a flat $1 per side, which is the term that bites on small positions and is the single most damaging cost at a small balance. eToro charges no commission but earns on the spread and gives no price improvement, so the effective spread is set to the full quoted estimate. Not modelled: eToro's ~0.5% currency conversion if you fund in anything other than dollars, and the fact that fractional shares often cannot be routed as market-on-close orders — this strategy trades at the close.

Universe filters

Three size axes, because they are not the same question. Price tier drives the bid-ask cost you actually pay and covers 100% of events — "penny" is the SEC definition, under $5 a share, which is a price, not a size. Market-cap bucket is the literature ladder and covers 74% (the rest have no share count filed before the event). Within-month tercile is size relative to the universe that month. Each filter shows what it costs you in events.
PriceBucketed by share price on the event day: under $1, $1–$5 (the SEC's own definition of a penny stock), $5–$10, $10–$50, over $50. Price, not size — a $2 stock and a $200 stock can sit in the same market-cap bucket.
Market capMarket capitalization at the time of the event, on the standard nano/micro/small/mid/large ladder. Needs shares outstanding filed before the event date — missing for about a quarter of events, which this filter then drops.
TercileSmall/mid/large thirds of the universe traded that same month — a moving ladder, not a fixed dollar one like market-cap bucket. Same shares-outstanding gap as the bucket filter.
SectorTwelve industry sectors, the same classification used on the Size & sector controls page.
RoleKeeps only events where at least one Officer, Director or 10% owner is among the signers that day. An event can match more than one role if several insiders filed the same day.
SessionWhich of the four IBKR-style windows the day's first Form 4 acceptance fell into, ET: pre-market (4:00-9:30), market hours (9:30-16:00), post-market (16:00-20:00), overnight (20:00-4:00). By this measure 36% of buy filings' first acceptance lands during market hours — a looser count than the Entry control's 33%, which additionally requires every filing that day, not just the first, to be in-hours. Either way most of the sample is outside market hours, which is where the filing-day-close anchor most often predates disclosure (see the Entry control's tip). This filter is about when the news came out, not the entry price, so it combines cleanly with any Entry option, including real price.

Conviction filters

Result

Two benchmark lines, on purpose. Buy-and-hold SPY answers "would I have been better off just owning the index". Exposure-matched SPY answers "does the edge exist" — it only counts the days the book is actually invested, which for a one-day holding period is a fraction of the calendar. They can differ by an order of magnitude for the same index over the same years. Reading the wrong one is the easiest mistake to make on this page.

Drag on the chart to select a period.

Drag on the chart above, or either handle below, to change the date range without typing — both charts and every number on this page follow it.

Return by period, against both benchmarks

Same curve as above, cut into bars instead of a line — pick the bucket size. Every bucket compares your configuration, SPY buy-and-hold and IWM buy-and-hold over the exact same days, so a bar-to-bar read is fair.

Backtest composition

How the capital the simulation deployed splits across the fills in the selected date range — not a live position, there isn't one yet (see the note below). Total invested is the sum of entry notional across every fill shown; P&L in the tooltip is realized, not a mark-to-market of an open position.

    What was verified before publishing this

    The controls page publishes its sanity checks whether they pass or fail, and this one had been computing its own without showing them. The important one compares two independent paths to the same price: the multi-day series used here is built separately from the event windows the rest of the project uses, and if the two disagree on the day-after close, one of them is wrong and nothing below should be trusted.

    The shape of the horizon

    The selector above samples one holding period at a time. This runs all seventeen of them against whatever configuration you have set, so you see the relationship instead of a point. It matters because the two cases look nothing alike: with a conviction filter the Sharpe ratio falls monotonically from about 2.0 at one day, while without one it starts wiped out and then wanders flat around 0.7. Reading the whole curve is also the defence against picking a lucky number — an isolated peak on a noisy line is overfitting, a peak on a smooth one is just the shape.

    Is it consistent, or is it one lucky stretch?

    A filter combination picked after seeing the full-sample result and then judged on that same sample proves nothing. Persistent out-performance across independent stretches of time is a different claim, and it is a claim that can be checked. These numbers recompute with every change you make above.

    How to read the trade count. A configuration that beats the index on 40 trades is noise with good luck. One that beats it across both halves of the sample, in most calendar years, on thousands of trades, and still clears the out-of-sample split, is making a much stronger claim. The specification counter tracks how many distinct configurations you have run this session, because the more you try, the more likely one of them looks good by chance alone.

    Trade journal

    Every fill the simulation makes, in MetaTrader Strategy Tester order — one row per round trip, entry and exit together, not one row per side. Entry and Exit are the split-adjusted series used to compute every return on this page, already including slippage; Gross (%) and Friction ($) pull that cost back out so you can see what the fill would have returned with no execution cost at all, and where the difference went.

    What this still does not model

    The entry price of the D window is not always reachable. Window D assumes you buy at the close of the filing day. But only 33% of purchase filings are accepted by EDGAR during market hours (9:30–16:00 ET): for the remaining 67% that close had already printed before the filing was public, so nobody could have bought there. Measured against real intraday execution prices (1-minute bars at the second of acceptance, exiting on a matching series from the same provider), the reachable entry costs about 0.08 percentage points per trade — around 6% of the portfolio result with no quality filter, and up to a quarter of it with one. The effect survives real execution prices in every configuration tested. An earlier version of this note put that cost near half the edge and said the effect did not survive without a filter; that came from measuring entry and exit on two different price sources with different dividend-adjustment conventions, and it does not hold once both legs come from the same one.
    Read this before trusting any number above. Market impact is capped, not modelled: the ADV control shrinks a position rather than moving the price against you. Borrow availability is ignored, which matters if you ever enable the short leg. The universe is 788 SEC registrants that are still active today, so companies that went bankrupt or delisted are missing entirely — precisely where insider selling would be most informative. Corwin-Schultz estimates the quoted spread; the effective spread paid is typically 50-70% of that, and trading at the close is usually cheaper still, so the measured defaults are more likely too harsh than too kind. And every backtest on this page is a backtest: it is what the rules would have produced, not what you would have earned.