Scenario run
Whole-GB fleet, cannibalisation fixed point solved to convergence. Prices, fleet build-out and BESS dispatch are solved jointly — not in sequence.
Convergence
The model iterates prices and dispatch until they stop moving — this chart shows the solve settling to the cannibalisation equilibrium.
Technical detail
KM iteration λk=2/(k+2) · stop ‖π(k+1)−π(k)‖∞ < £1/MWh (or stable single-digit band) · μ-regularised fallback
GB fleet map
Schematic coastline · dot area ∝ MW · operational construction consented
Registry
Seed registry compiled from public sources — see FLEET_SOURCES.md. Replace with NESO TEC / Elexon feed when licensed.
| Site | Operator | MW | MWh | Class | Zone | Year | Status |
|---|
Price path over the horizon — daily average wholesale price, naive vs cannibalisation equilibrium
Each line is the day-by-day average price. The gap between them is revenue a price-taker forecast assumes but the fleet competes away — the cannibalisation effect, over time.
Price duration curve
Sample week — wholesale price
Sample week — dispatch
Revenue stack by duration class — £/MW/yr
Revenue tracks
| Class | Fleet MW | Wholesale (eq) | Naive wholesale | Wholesale bias | FR | CM | BM | Total £/MW/yr | Cycles/day | Spread capture |
|---|
Sensitivities (quarterly set: gas ±30% · build ±20% · carbon ±40%)
Compare runs (any completed scenario-years, side by side)
Revenue uncertainty (Monte Carlo weather draws — P10/P50/P90)
Cannibalisation curves (sweep: per-MW revenue vs fleet size)
Manage runs — every stored run (all kinds): label, report, data pack, delete
| Created | Kind | Scenario · years | Wk | Anchor | Label | Status | Actions |
|---|
Labels are display names only — the audit manifest is never modified. Deleting a run removes its stored results permanently.
Analyse a new candidate site
The candidate joins the whole-GB fixed point as an extra asset class — its revenue is evaluated at the with-candidate equilibrium, never against exogenous prices.
Batch variants — sweep this site across durations / zones / costs in one submit (up to 8 variants)
The form above is the base. Each variant row re-runs the base with one field overridden — every variant is a full appraisal, saved to the portfolio like any other. Solver and price anchor are batch-level: set them above, they cannot vary per variant.
Batch comparison (ranked by NPV — best first)
| # | Site | Overrides | Total £/kW·yr | NPV £m | IRR | DSCR P50 | P90 | Min |
|---|
Revenue stack
Project finance
Grid connection (CEAtlas) indicative
Revenue track over asset life
Equilibrium price shift
NPV tornado (what does the IC ask? — single-knob NPV drivers, one shared basis)
Measured past (context — not a forecast)
Portfolio (all analysed sites — per-asset attribution)
| ⇄ | Site | MW | Dur | Zone | Scenario · year | Eq £/kW·yr | Total £/kW·yr | Bias | DSCR | P90 DSCR | Min DSCR | NPV £m |
|---|
No sites analysed yet — every analysis is saved to the portfolio automatically.
Revenue track overlay (stacked total £/MW/yr over asset life)
Methodology — a model you can interrogate
Diligence pack — the evidence a diligence analyst needs to verify this product: the held-out 2025 note ↗ · underwriting note ↗ · hindcast 2022–2025 ↗ · validation dossier (sign-in) ↗ · limitations register (sign-in) ↗ · pre-registration record ↗ · measured quarterly index ↗ · per-asset lookup ↗. GB fleet & pipeline map ↗. living index (provisional rolling series) ↗. We publish the failures too — that is the point.
Cannibalisation fixed point
Wholesale prices and whole-fleet BESS dispatch are solved to a self-consistent equilibrium π* = Ψ(Φ(π*)) — a true fixed point, not a one-pass adjustment. The iteration scheme carries a convergence guarantee, every run ships its audited convergence trace, and naive schemes demonstrably fail at GB fleet scale — which is why price-taker tools cannot produce this number at all. The naive (price-taker) forecast is always reported alongside the equilibrium — the bias between them is the number that decides DSCRs.
| Price-formation mode | What it is | When it runs |
|---|---|---|
| supply_curve (default) | parametric inverse supply curve π = S(residual + b), calibrated so the no-BESS price duration curve hits the stylised 2026 GB anchors; fast — no LP in the price step | interactive runs, candidate appraisals, the committed backtests |
| system_lp | merit-order welfare LP with interconnectors and VOLL; π = the power-balance dual (SRMC basis) | scenario-grade cross-checks; FR co-optimisation applies to supply_curve only (disclosed per run) |
Why this is hard to fake: a price-taker spreadsheet cannot produce the naive-vs-equilibrium bias number at all — it has no fleet feedback to measure. The bias only exists if prices and the whole fleet's dispatch are solved jointly, and its magnitude is checkable against the measured index below.
Dispatch
Per-cohort half-hourly LP: SoC dynamics with one-way efficiencies √η, self-discharge, degradation as a marginal cost (£2.50/MWh discharged, LFP default), one-sided cyclic boundary eT ≥ ½E, least-cycling lexicographic tie-break. Whole-GB fleet aggregated into BESS_<year>_<duration> cohorts from the site registry.
What is reduced-form in v1 (disclosed by design)
- Balancing Mechanism: statistical proxy per TNUoS zone × duration class — NOT dispatch-based. The zone factors are measured from the CE index trailing-year EBOCF offer-leg zonal split (replacing an earlier hand-set Scottish-premium guess with measured per-zone factors — the values render in the assumptions register below, sign-in required; thin zones are shrunk toward neutral in proportion to their measured capacity, per-zone counts disclosed in the index JSON, and the zonal variation rides the measured offer leg only). The per-class bases were recalibrated 2026-06 under the pre-registered rule to the index trailing-year measured EBOCF values — every old→new parameter ships in the calibration evidence below. The one-way line floors the 4h class at £0 against a measured NEGATIVE net (BM-instructed cheap charging pays out in the wholesale leg) — an honest structural hard-fail, published as such; 8h is unmeasured and stays a placeholder, disclosed. Caveat for Scottish-boundary sites (Z2–Z4): the measured NET zonal BM is zero or negative in curtailment-absorbing zones (the value lands in cheap charging, i.e. the wholesale leg) — read the zonal split in the quarterly index alongside any Z2–Z4 appraisal. Under the adopted two-leg structure (pre-registered; shipped with its published no-flattery checks) a Z2/Z4 appraisal's BM line floors at £0 where the measured net is negative, and the measured net values still travel with the appraisal payload.
- Frequency response (DC/DM/DR): saturation price model anchored (2026-06 recalibration, pre-registered) to the NESO EAC trailing-year volume-weighted clearing prices with participations refit to the measured per-class FR revenue — the θDC 2021→2024 collapse rate is preserved; DR-H cleared negative over the trailing year and is unremunerated (disclosed; the measured product mix is rotating DC → DR-L quarter on quarter, visible in the quarterly index). The FR verdict cells below therefore wear a fit (in-sample) badge, never "pass" — they were fit to those targets. From 2026Q2 each new index quarter grades this frozen parameterisation OUT-OF-SAMPLE under the standing pre-registered rule (protocol §13).
- Capacity Market: NESO duration de-rating on a cleared-where-cleared price basis (pre-registered rule, executed 2026-07) — delivery years whose T-4 auctions have cleared use the final clearing prices from the pinned auction register (auction results are facts, not forecasts); beyond the cleared horizon the central line is the deterministic conditional expectation of the bounded random walk — no seeded realisation. Future-auction uncertainty is NOT yet in the Monte Carlo bands (the draws inherit the central CM line — disclosed).
- Calibration constants kD = 1.0 (BM/CM/FR are modelled explicitly, so kD ≠ 1 would double-count). The calibration harness is implemented: the 2h cycles/day check runs against the public Modo 1.2–1.5 band (PASS/FAIL in the backtest panel below) with the CE GB BESS index pilot as cross-check, and the spread-capture reference now comes from the CE index (primary-data proxy basis, disclosed below) — no third-party benchmark licence.
- Forward-run demand/wind/solar profiles are synthetic-but-calibrated: the no-BESS price duration curve is fitted to the stylised 2026 GB targets (mean £88, P50 £70, P95 £216, max £676/MWh) under the default stylised anchor; the selectable realised-2024 anchor replaces the curve base with the Elexon-calibrated 2024 fit (in-sample), and the selectable trailing-12m anchor recalibrates the same machinery to the trailing 12 months of realised Elexon prices through the latest settled day (window disclosed per run; staleness flagged after 35 days — see the Forward anchor freshness card below). Realised Elexon MID prices drive the backtest and both realised anchors. Realised NESO/Elexon demand-wind-solar profiles (public no-auth APIs, cached in-repo) are integrated and selectable for the 2022–25 backtests, with a fitted 2-parameter affine basis alignment (in-sample, disclosed per run) that closes the realised TSD-basis level gap to ~4–6% on the window mean; synthetic remains the default because the remaining gap is curve SHAPE on the realised basis (P50 cold, P95 hot — measured numbers in the run caveats). An experimental shape-fit calibration (k, σ freed; payload calibrated_shape) closes 2022 to sub-1% but pins a parameter at a bound every year and was not adopted under the pre-registered rule. On 2023/24 the below-band calibrated cycles coincide with price spreads matching realised within 10% (payload spread_diagnostics) — spread amplitude is ruled out as the shortfall there, and double-counting of history's storage response, dispatch-cost assumptions and band composition are indistinguishable to that diagnostic; 2022's spreads run 37% wide with cycles still below band (unresolved, dispatch-side). The cycles check is excluded from the realised-default-flip rule unless evaluated on a no-BESS counterfactual basis. FORWARD runs remain on synthetic-but-calibrated profiles; live forward profile feeds are the remaining data step.
Assumptions register — the values the model actually runs with
Rendered live from the running configuration (GET /api/assumptions, single-sourced from cecadence.config) — prose can never silently rot against code. Basis column: spec = specification default · measured = from the CE index · calibrated = fit in-sample, disclosed.
loading assumptions…
Uncertainty & finance conventions
- Exceedance convention for revenue bands: PXX is the value exceeded in XX% of Monte Carlo draws, so P90 is the conservative (low) band. Price statistics (e.g. the P95 price) remain percentile-convention scarcity tails.
- Monte Carlo design: N bootstrap weather realisations, each solved to its own cannibalisation equilibrium; bands carry standard errors of the mean.
- Finance targets: P50 DSCR target 1.40× and P90 (exceedance) lender covenant 1.10×.
- Multi-year revenue track: candidate finance runs on the cannibalisation-aware year-by-year revenue trajectory against the growing fleet, with the minimum DSCR and its binding year reported.
Validation invariants (every solve; violations halt the pipeline)
SoC bounds · round-trip consistency · price sanity −£200 ≤ π ≤ £5,000/MWh · zero-storage limit · KKT residuals · cross-solver oracle (CEMeridian vs HiGHS, 1e-6 rel)
CE GB BESS index — the product's own benchmark from open primary data
The product's benchmarks are computed from Elexon BMRS and NESO open data under their open licences — no third-party benchmark licence. The battery-BMU registry (pinned, committed, disclosed per row) is built by cross-referencing the Elexon BMU register with NESO auction and Capacity Market records. The pilot index window measures, from primary data only: fleet cycles/day (B1610 metered volumes ÷ energy capacity), a wholesale revenue proxy per MW (metered volumes × MID half-hourly prices — an ex-post proxy, not traded positions), BM revenue per MW (EBOCF bid-offer cashflows) and FR revenue per MW (EAC clearing price × executed quantity per product), plus revenue shares by stream. The index covers the trailing four fully-settled quarters (one registry, per-quarter active-unit scoping handles mid-period commissioning, active-MW-day weighted aggregation) plus the Capacity Market stream from the CM register's awarded de-rated obligations × auction clearing prices (delivery years overlap-weighted; initial-auction basis). BM/FR numerators cover exactly the ACTIVE unit set of the per-MW denominator; excluded revenue is quantified, never silent. The single-quarter pilot that preceded the trailing window remains in docs/evidence/bess_index_pilot.json for provenance — the trailing-year card below supersedes it (different basis: trailing active-MW-day weighted vs one pilot quarter). Every number below renders live from the committed index evidence (bess_index_trailing.json).
📄 The latest measured quarter is published as the CECadence Quarterly GB BESS Index report ↗ — on-brand, print-to-PDF, built from this same open data. Per-unit, the same record is browsable in the per-asset lookup ↗ — measured revenue, strategy class and within-class percentile for every gated unit.
loading CE GB BESS index…
Calibration harness — model (2026 CE-CENTRAL) vs CE index trailing year
The calibration harness grades the model's per-duration-class BM and FR revenue lines and cycles/day against the index-measured trailing year, like-for-like by stream, with the CALIBRATION_TOLERANCES verdicts (per-duration revenue 15%/20% soft/hard; cycles 10%/15%, 25% reject). kD stays 1.0 — the harness validates the explicit reduced forms and publishes pass/fail honestly; the index wholesale floor and spread capture are context, never graded (basis mismatch, disclosed). Model side: a claim-grade 26-week 2026 CE-CENTRAL run on the stylised anchor.
loading calibration verdicts…
Cross-walk on the index's own conventions — model vs measured, stream by stream (informational)
The same realised-anchor 2025 dispatch that reproduces the committed realised backtest cells, valued under the index's own ex-post proxy convention (model volumes marked at the realised MID series — the metered-at-MID FLOOR applied to model volumes) and set against the measured trailing-year wholesale floor, cycles and spread capture per duration class — the first like-for-like per-class wholesale comparison, published straight. Nothing here is graded (no tolerance rule exists for these streams; one would be pre-registered first). The graded BM/FR cells are in the calibration table directly above.
loading cross-walk…
The standing out-of-sample record (§13)
Each quarter after 2026Q1, the revenue lines FROZEN at the iteration-148 pre-registration are graded against that quarter's measured index — data the frozen parameterisation has never seen. The record is append-only and survives every recalibration verbatim; grading verdicts begin once four out-of-sample quarters have accumulated. Until then every row is informational, published as measured.
loading out-of-sample record…
The cycles gap, step by step (informational)
Every step below is already published in the calibration evidence under its own disclosures — assembled here into one table so the graded REJECT is legible as attributed causes. The graded verdict stays the synthetic-anchor cycles REJECT ×3.
Where the model fails — published deliberately
Backtest evidence — measured record (2022–25 + held-out 2026H1, 26-week convention)
Pre-computed through the same run_backtest pipeline as the live form below, on the pinned public-data caches; every cell is reproducible live. Generated stamp and honest caveats travel with the data. 2025 is the pre-registered HELD-OUT validation year: every rule (alignment bounds/quantiles, check targets, cycles rules, week sampling, coverage gates, fuel-multiplier derivation) was frozen in committed code before any 2025 backtest input was fetched, and the results publish regardless of outcome — protocol served at /heldout-protocol.html. The pre-registered H1-2026 held-out price window (§14) has since been EXECUTED — its rows render below (window mean PASS, P50/P95 FAIL, published unmodified); quarterly out-of-sample revenue grading from 2026Q2 (§13) remains pre-registered and pending.
loading evidence summary…
Where the error lives — sequential decomposition (informational)
Week-sampling sensitivity — 13/26/52-week horizons (disclosure)
Forward anchor freshness — trailing-12m calibration
The selectable realised_trailing price anchor is the supply curve recalibrated to the trailing 12 months of realised Elexon MID prices through the latest settled day (the same equilibrium-refit machinery as the realised-2024 anchor; in-sample for the window). Every anchored result discloses its calibration window; a window end older than 35 days flags runs STALE (they still work) until the calibration is refreshed here.
loading trailing-anchor calibration…
Backtest vs realised (Elexon MID) — run it live
The model is re-run for a historical year with the fleet that actually existed (site registry, no scenario top-up) and compared against realised GB half-hourly market-index prices from the public Elexon Insights API — annual mean within 5% is the credibility target (measured PASS/FAIL per year on the Evidence card above; the held-out 2025 year FAILS in both modes (P95 tail in both; synthetic also misses the 5% mean at +12.0%), published unmodified per the pre-registered protocol). Model-side profiles default to the calibrated stylised synthetic basis the supply curve is anchored to; realised historic demand/wind/solar (NESO data portal + Elexon FUELHH, cached in-repo) is selectable — a fitted affine basis alignment (in-sample for prices, disclosed in the payload) closes the measured cold level gap to ~4–6% on the window mean, but P50 stays cold and the P95 tail runs hot, so synthetic remains the default (the run's caveats carry the measured numbers). On 2023/24, below-band calibrated cycles coincide with price spreads matching realised — spread amplitude is ruled out as the cause, while double-counting of history's storage response, dispatch-cost assumptions and band composition are indistinguishable to that diagnostic (the dispatch-check table carries the applicability note verbatim); 2022 is unresolved (spreads 37% wide).
No backtest run this session — run one above to check the model against realised Elexon prices.
Latest run manifest
No runs yet.