Data contract

Holdout Data Contract v1

The file format for sending us data: returns only (Tier 1), or positions and trades for a deeper audit (Tier 2). You get the spec, sample files, a JSON Schema per file and a free validator, so you can check your folder before anything is sent.

Version 1.0, 2026-09-26. Questions: [email protected].

The short version

  • Tier 1, returns only: one file, returns.csv. The minimum for every service, and anonymised is fine.
  • Tier 2, positions and trades: add instruments.csv and positions.csv (plus trades.csv and baskets.csv where relevant) for holdings-based checks. It takes us more time, so it costs more: see pricing.
  • Our format, checked by you first: download the samples and run the validator on your folder. PASS means it is ready to send.
  • Can’t produce this format? We can convert your files as a paid add-on, quoted separately, from $500.
  • Same confidentiality either way. Position and trade data is handled exactly like returns, under the same terms.

Two tiers

What you send, and what it unlocks

Tier 1: returns onlyTier 2: positions, trades, exposures
Filesreturns.csv, plus the number of variants you tried (and the variant grid, if you have one)Tier 1, plus instruments.csv, positions.csv; trades.csv and baskets.csv where relevant
Anonymised?Yes: “Strategy A”, no names, optionally rescaledPossible, with trade-offs (see below)
What we can testEverything built on the return series: deflated Sharpe, PBO, haircuts, Reality Check and SPA, holdout decay, stability, return-based factor alpha, smoothing flags, drawdown rangesTier 1, plus holdings-based factor exposure, cost and capacity against volume, look-ahead and survivorship checks, positions-to-returns reconciliation, concentration, leverage, liquidity and drift
PriceThe listed priceAbout 1.8× the Tier 1 price (pricing)

Downloads

Samples, schemas and the validator

The sample instruments are invented (SAMPLE-*); the SPY and TLT prices in them are simulated, not market data.

Check your folder

python holdout_validate.py my-folder/

  PASS  returns.csv       63 rows   ok
  PASS  instruments.csv   12 rows   ok
  PASS  positions.csv     90 rows   ok
  PASS  trades.csv         2 rows   ok
  PASS  baskets.csv        6 rows   ok

RESULT: PASS (0 error(s), 0 warning(s))

Exit code 0 means PASS, 1 means FAIL. Every problem is listed with its file and line number. Add --json for a machine-readable report. The same check is holdout-audit validate in our toolkit. A PASS means the folder is in the right format, not that the numbers are right; we still review them.

General rules

How every file is laid out

  • One folder, fixed file names: returns.csv, instruments.csv, positions.csv, trades.csv, baskets.csv.
  • CSV (UTF-8, comma-separated, one header row, the column names below in lower case) or Parquet with the same names (returns.parquet).
  • One row per record. No merged cells, subtotals, spacer rows, notes under the table or multi-row headers.
  • Dates in ISO-8601: 2026-03-18 (or a full timestamp for intraday data). Not 03/18/2026, not Excel serial numbers.
  • Plain numbers: a . decimal point, no %, thousands separators, currency symbols or brackets. Returns are decimals: 0.012 = +1.2%.
  • One base currency, declared in returns.csv. NAV, flows, market values and fees are in it.
  • Consistent IDs: every instrument_id in positions, trades or baskets appears exactly once in instruments.csv.
  • Signed quantities: negative means short (or a sale). Leave optional cells empty rather than writing 0 or N/A.

Files and fields

What goes in each file

returns.csv · Tier 1, always required

ColumnRequiredMeaning
dateyesPeriod end (daily, weekly or monthly); unique, in date order
navnav or returnNet asset value at the period end, base currency, above zero
returnnav or returnSimple decimal return for the period, time-weighted, net of costs and fees unless agreed. With nav, the first row may be blank
flownoExternal cash flow at the period end: + subscription, − redemption. Used with nav for time-weighted returns
currencyyesBase currency (ISO 4217, e.g. USD); the same on every row

A flow on day t is included in that day’s NAV, so return = (NAVt − flowt) / NAVt−1 − 1. If you send both NAV and returns they must agree within 1 basis point. An audit needs at least 60 periods; two years or more is better.

instruments.csv · required with any Tier 2 file

ColumnRequiredMeaning
instrument_idyesYour identifier, unique in the file
id_typeyesISIN, CUSIP, FIGI, TICKER_MIC (e.g. SPY.ARCX), OCC (option symbol), FUTURES (contract code), CUSTOM (internal or masked)
descriptionnoFree text; keep it generic if anonymising
asset_classyesequity, etf, index, future, option, fx, bond, commodity, swap, basket, cash, other
currencyyesCurrency the instrument is priced in
multiplierno (blank = 1)Contract multiplier: 100 for US equity options, the point value for futures
underlying_idderivatives, swapsThe underlying’s instrument_id (listed in this file too)
expiryfutures, optionsExpiry or maturity date
strikeoptionsStrike, in the instrument currency
put_calloptionsP or C
exchangenoListing venue, ideally an ISO 10383 MIC (XNYS, XCME)

positions.csv · Tier 2

ColumnRequiredMeaning
dateyesEnd-of-day holdings date, ideally on the returns.csv calendar
instrument_idyesFrom instruments.csv
quantityyesSigned units or contracts; negative = short. For cash rows, the amount
priceprice or market_valuePrice per unit, in the instrument currency
market_valueprice or market_valueValue in the base currency, negative for shorts. Futures and swaps: the notional (their P&L sits in cash)
currencyyesCurrency of price; the instrument’s currency
sleevenoSub-strategy or book label
deltaoptionsPer-unit option delta, between −1 and 1 (puts are negative)

One row per instrument, date and sleeve. When price and market value are both given, market value must equal quantity × price × multiplier within 0.5%. Include cash rows if you want positions reconciled to NAV.

trades.csv · optional

ColumnRequiredMeaning
trade_dateyesTrade date
instrument_idyesFrom instruments.csv
quantityyesSigned: + buy, − sell; never zero
priceyesExecution price, instrument currency
feesnoCommissions and fees, base currency, as a positive number
sleevenoSub-strategy or book label
trade_idnoYour unique reference; add it when two fills are otherwise identical

baskets.csv · only for custom baskets or swap look-through

ColumnRequiredMeaning
basket_idyesThe basket’s instrument_id (asset class basket, swap or index)
dateyesComposition date; applies until the next date for that basket
constituent_idyesThe constituent’s instrument_id
weightweight or unitsDecimal weight; a basket’s weights on a date sum to 1
unitsweight or unitsUnits per one unit of the basket; use for long/short or leveraged baskets

Special cases

Indices, baskets, derivatives, anonymisation, market data

Index products

An index future, option, ETF or swap is one instrument by default: send its price and we treat it as a single exposure. We look through to constituents only if you supply them in baskets.csv. We do not source licensed index constituent data, so look-through of a proprietary index depends on your own right to share it.

Custom baskets and swaps

Either send the basket as a single price series (simplest), or also send baskets.csv with its composition on each rebalance date, which lets us analyse factors, concentration and liquidity on the constituents. A total return swap is asset_class = swap with underlying_id pointing at its reference basket.

Derivatives

Futures: market value is the notional, and P&L runs through cash. Options: send multiplier, strike, expiry, put/call, underlying and a per-position delta, and we report both notional and delta exposure. Without delta, delta exposure needs a pricing model, and the report says so.

The anonymisation trade-off

Masked CUSTOM identifiers are fine, but then we can’t look anything up. You supply the prices (and volumes, for capacity), and some checks are lost or weaker: survivorship and look-ahead checks against public records, holdings-based factor exposures, and capacity against real traded volume. Masking only the sensitive names keeps most of the value. Anonymised Tier 1 returns remain the option with the least disclosure.

Market data

We prefer your prices: they are what your book was actually marked at. Any public or licensed market data we use to fill gaps or run checks stays inside the analysis. We do not redistribute market data; reports show derived statistics, not vendor price series.

Tier 2

What positions and trades unlock

  • Holdings-based factor exposure: loadings from what was actually held, compared with the return-based regression, to reveal style drift that returns alone hide.
  • Cost and capacity: turnover and trade sizes against average daily volume, estimated market impact, and the size at which costs erase the edge.
  • Look-ahead and survivorship checks: positions taken before information was public, and instruments in a backtest universe that did not yet exist or later disappeared.
  • Positions-to-returns reconciliation: daily returns rebuilt from holdings and prices, and the size of the unexplained gap.
  • Concentration, leverage, liquidity and drift: top holdings, gross and net exposure, days to liquidate, and how they moved over time.

Validator

What the validator checks

  • The right files are present, UTF-8, comma-separated, with every row as wide as the header.
  • Required columns, ISO dates, plain numbers, allowed codes and identifier formats.
  • Returns: unique ordered dates, one base currency, positive NAV, percent-scaled returns caught, returns matching NAV and flows within 1 bp.
  • Every instrument used in positions, trades and baskets exists in instruments.csv; options have strike, expiry and put/call.
  • No duplicate positions, trades or basket rows.
  • Market value matches quantity × price × multiplier within 0.5%; its sign follows the quantity.
  • Basket weights sum to 1 (±0.01).
  • Warnings for position dates missing from the returns calendar, and for positions that don’t add up to NAV when cash rows are supplied.

A folder with problems

  FAIL  returns.csv        4 rows   3 error(s)
  FAIL  positions.csv      3 rows   3 error(s)

  ERROR returns.csv    returns look like percentages
                       (median |return| = 0.35);
                       send decimals: 1.2% -> 0.012
  ERROR returns.csv:5  'date' = '01/07/2026' is not
                       an ISO-8601 date (YYYY-MM-DD)
  ERROR positions.csv:2  market_value 5,000.00 !=
                       -100 x 50 x 1 = -5,000.00
  ERROR positions.csv:3  instrument_id 'SAMPLE-EQ-999'
                       is not in instruments.csv

RESULT: FAIL

Output shortened for this page.

Data in another shape? We can prepare it

If you can’t produce these files (a broker or administrator export, several spreadsheets, PDFs), we convert them for you as a paid add-on, quoted separately, from $500, depending on the number of sources and the cleaning needed. The converted folder goes through the same validator and back to you for sign-off before the audit starts, so you confirm that the data we audit is your data. Send data only after scoping, by the agreed secure method; never through the intake form.