<!-- https://zunderlabs.com/docs/methods/honest-backtest · Markdown version of the page -->

# How the honest backtest works

Why the browser Backtest replays real fills instead of simulating a strategy, the exact replay rules, and the honesty rules Zunder applies to every backtest.

There are two kinds of backtest on this site's horizon, and they answer different questions.

| | Browser Backtest | Zunder's research backtests |
|---|---|---|
| Question | what would my rules have changed about **these real trades**? | would **this strategy** have made money? |
| Input | an address's recorded fills, funding and orders | candles, a strategy, a fill model |
| Prices | the ones that happened | simulated fills |
| Runs | in your browser (`crates/zunder-risk-wasm`, being built) | on Zunder's build box (`zunder-sim`, `zunder-research`) |

## The browser Backtest: replay, not simulation

It never invents a price. Every trade in both curves was a real fill; the guarded curve only takes **less** of it, or none.

The rules of the replay (`crates/zunder-risk-wasm/src/replay.rs`):

1. **Actual equity** = starting equity + closed PnL − fees + funding, as recorded.
2. **Guarded entries** are judged by the same function as Watch and the live market, against the guarded account. Refused: skipped. Resized: scaled.
3. **Guarded exits** follow the account's exits in proportion. If the account closed half, the guarded position closes half.
4. **Fees and funding** of the guarded position are the recorded ones, scaled to its size.
5. **A real `RiskEngine`** observes guarded equity at every event. A daily loss stop blocks entries until the next UTC day; a drawdown halt blocks them for good. Guarded positions are closed at the account's next fill price in that coin.
6. **The audit** judges every fill against the account as it really was, with a second engine on the actual equity.

### Example

The account buys 2 ETH at 2,500 with a stop at 2,400 on 2,000 equity, later sells 1 ETH at 2,600 and 1 ETH at 2,450.

- Guard allows 0.38 ETH: `40 / (100 + 3)` = 0.388…, with 12 bps of 2,500 = 3 as costs, rounded down to a lot size of 0.01 ETH (an assumption for the example).
- The guarded exits are half and half: 0.19 ETH at 2,600 and 0.19 ETH at 2,450.
- Guarded PnL: 0.19 × 100 − 0.19 × 50 = 9.50, before fees. Actual: 1 × 100 − 1 × 50 = 50.

The guarded curve made less on this trade. It also risked a fifth as much. The page shows both, and never hides the cases where Guard would have cost profit.

## Honesty rules

These come from how Zunder treats its own research (`CLAUDE.md`, hard rule 8: "A backtest that looks great is a bug until proven otherwise"), applied to the browser tool:

- **Costs included.** Fees and funding as Hyperliquid recorded them.
- **Assumptions on the page.** Every result lists what the replay could not know ([the list](https://zunderlabs.com/docs/tools/backtest#what-it-cannot-know)).
- **No promise.** "Would have lost less on this history" is a statement about the past, under stated assumptions. It is not a forecast.
- **Any address.** The page is prefilled with a public vault as an example, and invites you to replay any address, including ones where Guard would have cost profit.

## Zunder's research backtests

For its own strategies, Zunder applies stricter rules (`docs/strategy-research.md`): a strategy sees a candle only after it closed; a random-walk test and an independent second implementation of the backtest loop guard against look-ahead; parameters are tuned on one period, checked on a second, and tested once on a held-out third; every variant tried is counted, and the result is corrected for that count (deflated Sharpe ratio). Most ideas end as "rejected". Those results are research notes, not product claims.
