# Paired backtest attribution input contract

This contract applies to `freqtrade/scripts/paired_backtest_attribution.py`.
The tool is read-only and must only receive already-generated, sanitized
Freqtrade result archives or JSON files.

## Four required arms

| Arm | Meaning | Primary comparison |
|---|---|---|
| `baseline-a` | Original RiskCap run before the candidate | Formal production reference |
| `noop` | Candidate plumbing with the new gate disabled | Must exactly reproduce A |
| `candidate` | Frozen V2 pass-through plus XSMOM rank gate | Compared only with baseline A |
| `baseline-b-repeat` | The unchanged original RiskCap rerun after the candidate | Sandwich drift control; must exactly reproduce A |

All four inputs must use the same timerange, timeframe, starting balance,
maximum open trades, trading/margin mode, protections, and trade fees. A
protocol mismatch, no-op mismatch, or baseline A/B-repeat mismatch makes the
single candidate contrast unsafe to interpret and produces a nonzero exit
status.

There is no availability-control strategy and no A→B cold-start contrast.
V2's unscored-pair pass-through preserves baseline behavior during cold start.
The only formal result comparison is `baseline_a_vs_candidate`.

## Accepted result shape

An input may be:

1. a Freqtrade result zip containing exactly one non-config result JSON; or
2. the extracted result JSON.

The normal top-level shape is:

```json
{
  "strategy": {
    "StrategyClass": {
      "trades": [],
      "profit_total_abs": 0.0,
      "profit_total": 0.0,
      "profit_factor": 0.0,
      "max_drawdown_account": 0.0,
      "starting_balance": 1000.0,
      "final_balance": 1000.0,
      "backtest_start": "2026-01-01 00:00:00",
      "backtest_end": "2026-05-01 00:00:00",
      "timeframe": "5m"
    }
  }
}
```

Each trade must include `pair`, `is_short`, `open_timestamp`,
`close_timestamp`, `profit_abs`, and `profit_ratio`. A unique trade entry is
identified by `(pair, side, open_timestamp, enter_tag)`. Duplicate keys are
rejected rather than guessed.

When an archive contains multiple strategies, pass the corresponding
`--baseline-a-strategy`, `--noop-strategy`, `--candidate-strategy`, or
`--baseline-b-repeat-strategy`.

The isolation gate also requires a `_wallet.feather` member in baseline A,
no-op, and baseline B-repeat archives. Their member SHA-256 values must match
exactly. Bare JSON remains readable for diagnostics but cannot pass sandwich
isolation because it cannot prove wallet-path identity.

## Outputs and interpretation

The output directory contains:

- `paired_backtest_attribution.json`: provenance, metrics, contrasts, result
  path episodes, and EDGE/POWER sensitivity;
- `metrics.csv`;
- `trade_differences.csv`;
- `divergence_episodes.csv`;
- `edge_power_sensitivity.csv`;
- `realized_equity_path.csv`.

Trade retention matches entry opportunities. Exact retention additionally
requires matching close path, prices, sizing, PnL, funding, and exported order
fills.

Trade-difference, episode, and EDGE/POWER sensitivity tables contain only the
formal baseline-A versus candidate comparison. Baseline/no-op and baseline
A/B-repeat comparisons are implementation-isolation checks, not performance
contrasts.

The portfolio path is **realized equity at trade-close event boundaries**.
Freqtrade's exported maximum drawdown is reported separately and remains the
authoritative backtest DD. Arithmetic EDGE/POWER sensitivity removes recorded
trade PnL without rerunning slot allocation; its drawdown is deliberately not
recomputed.

## Evidence limit

Standard Freqtrade result archives do not preserve authentic rejected raw
signals, gate decisions, every submitted/unfilled order, dynamic stop state,
or mark-to-market active-state history. Therefore emitted episodes are labeled
`RESULT_PATH_DIVERGENCE` and always carry
`formal_path_divergence_eligible=false`.

They cannot satisfy the experiment contract's minimum formal
`PATH_DIVERGENCE` episode count. Formal episodes require a separately frozen
event ledger containing, for every arm, raw signal, gate decision, submitted
order, fill, active order/position state, stop change, exit, and common event
boundary.
