# Never fill a gap with a zero

> Four rules our market history follows: never average two venues, never fill a gap, never keep two copies, and never include a series that lies about itself.

- Source: https://defiloops.com/blog/never-fill-a-gap-with-a-zero
- Published: 2026-09-16
- Category: Architecture
- Tags: data, backtesting, engineering
- Author: DeFiLoops

---
The agent answers questions from stored history rather than by calling exchanges when you ask.
That is deliberate: a backtest is only worth reading if its inputs held still while you read
it, and asking the same question twice should give the same answer.

Which makes the storage the product. Four rules it follows, each of which we learned by
getting it wrong.

## Never fill a gap with a zero

An absent or partial series is reported as absent. It is never smoothed, interpolated or
defaulted.

The reason is that a zero is a *claim*. An open interest of zero says nobody anywhere holds a
position in that market — which is never true of a live one. A model handed that zero cannot
tell it apart from a real collapse, and will happily build a conclusion on top of it.

<Callout type="note" title="So coverage is a question you can ask">
  Open interest fills per symbol, one day-file at a time, so one symbol can be complete while
  another is half-filled. The tool reports how many days it actually holds, and that number
  moves. Ask it rather than trusting a figure written down anywhere — including here.
</Callout>

## Never average two venues

Funding rates from four venues are kept apart. Binance and Bybit correlate around 0.85 on BTC,
which means they disagree often enough to matter.

**Where two venues disagree, the disagreement is the reading.** A mean would hide precisely
the days worth knowing about — the ones where something was happening at one venue and not the
other — and would replace two true numbers with one number that was never true anywhere.

## Never keep two copies

There were two copies of the pool history. The agent kept its own synced copy beside the main
one, on a different schedule, against an indexer that backfills.

They drifted to **39 pools against 32**, with 30 in common.

<Callout type="warn" title="Two copies of one history is not redundancy">
  It is two answers to the same question, where which one you get depends on which service you
  happened to ask. There is one copy now and every tool reads it over the network, which is
  slower and correct.
</Callout>

There is a sharper version of the same lesson. The schedules write to a database rather than
to files, because when there was a file in between, a deploy overwrote a freshly synced pool
history with a stale copy from somebody's laptop. **Nothing failed.** Every page rendered,
every tool answered, and hedges were priced from a day ten days out of date for as long as it
took somebody to notice.

## Never include a series that lies about itself

Wrapped assets are absent from the price history on purpose. WBTC's archive begins in January
2024; XAUt is missing 63 months.

A price series built from those would not describe bitcoin or gold. It would describe the
wrapper's own thin trading — and it would look like data, plot like data, and be wrong in a way
no error message could catch. BTC is the reference for WBTC instead, and the wrapper's price
against the asset is an on-chain question the pool history already answers.

The same judgement runs the other way. Fees for a Uniswap pool are hard, because an indexer
values a swap only if it can price both tokens, so a pool can record thousands of trades and
report **zero fees**. Where the other side of the trade is a dollar, the fee is rebuilt exactly
— and **every rebuilt row is flagged**, with the tools passing that flag through to the answer.

## What all of this is for

It is read, not traded on. This history exists so the agent can analyse — what a range would
have collected day by day, what a hedge has cost at every roll since 2021, what a perpetual
pays across four venues — and none of it is a feed, a signal service, or an input to execution.

The separation is worth stating because it is unusual: the half of this system that spends
money works from a closed catalogue of operations, and the half that reads works from these
streams. Nothing crosses. A backtest cannot place a trade, and a plan cannot be sized from a
number a survey returned.

<Callout type="note" title="Every stream has an end, and says so">
  Pool history from May 2021, DVOL from March 2021, Binance funding from September 2019,
  Hyperliquid's from May 2023 because that is when the venue began. A tool that cannot cover
  the window you asked for tells you, rather than answering anyway from a shorter one.
</Callout>