VanillaSC – the Iberian exception on the day-ahead electricity price

VanillaSC – the Iberian exception on the day-ahead electricity price#

Estimator:

Vanilla Synthetic Control (VanillaSC)mlsynth.VanillaSC

Source:

Haro Ruiz, M., Schult, C. and Wunder, C. (2024), “The effects of the Iberian exception mechanism on wholesale electricity prices and consumer inflation: a synthetic-controls approach,” Applied Economics Letters 33(9):1310-1316, DOI 10.1080/13504851.2024.2425834.

Replication type:

cross-validation against the authors’ own public replication code (github.com/mharoruiz/ibex) on the day-ahead-price outcome.

Status:

verified – the donor weights and the per-period gap reproduce the ibex synthetic control value-for-value (weight L1 distance \(\approx 0\), gap agreement to ~1e-8).

What the paper does#

In June 2022 Spain and Portugal introduced the Iberian exception mechanism (IbEx), a cap on the gas price that electricity generators may bid into the day-ahead market. Haro Ruiz, Schult and Wunder (2024) estimate its effect with a standard synthetic control: each treated country is compared with a synthetic counterpart built from a weighted average of untreated European countries that tracks it before the intervention.

The authors follow Ferman, Pinto and Possebom (2020) and match on all pre-treatment outcome lags rather than a hand-picked set of covariates. Their replication code (01_functions/sc.R) solves the canonical Abadie-Diamond-Hainmueller program: choose donor weights \(\mathbf{w}\) on the simplex (non-negative, summing to one) that minimise the pre-treatment fit to the treated series, using limSolve::lsei. That is exactly what mlsynth’s VanillaSC computes with backend="outcome-only" – the well-posed convex problem, no predictor weights.

Validation strategy#

Spain (ES) and Portugal (PT) are both treated in June 2022, and the paper excludes each treated country from the other’s donor pool (“we exclude Portugal … and vice versa”). mlsynth’s multi-treated design drops every treated unit from the shared donor pool, so for these two mutually-excluded units a single VanillaSC fit reproduces the paper’s two per-country loops against the identical 20-country pool. We fit once, on the paper’s own day-ahead data (basedata/ibex_day_ahead_price.csv, monthly, 2015–2023, treatment in June 2022), and compare to the ibex outputs (03_results/sc_optimized_weights.csv and 03_results/sc_series_001.csv, captured at commit c5371314).

Cross-validation – weights and gap#

Because both implementations solve the same simplex program on the same data, the donor weights coincide to solver tolerance, and with identical weights and donor data the per-period gap coincides pointwise:

Quantity

VanillaSC (mlsynth)

ibex (lsei / scinference)

Spain – Slovenia (SI) weight

0.526

0.526

Portugal – Slovenia (SI) weight

0.516

0.516

Spain – donor-weight L1 distance

\(\approx 0\)

0

Portugal – donor-weight L1 distance

\(\approx 0\)

0

Spain – mean post ATT (Euros/MWh)

\(-46.4\)

\(-46.4\)

Portugal – mean post ATT (Euros/MWh)

\(-45.5\)

\(-45.5\)

Both countries show a large cut in the day-ahead price – about 40% below the synthetic counterfactual over the first year – which is the paper’s headline finding. The two treated series load on the same donors (Slovenia, Belgium, Greece, the Netherlands, Italy, Latvia, Sweden), with Slovenia dominant.

Scope#

The paper reports four outcomes: the day-ahead price and three consumer-price indices (energy, non-energy and all-items HICP at constant taxes). The three CPI series are pulled live from Eurostat (prc_hicp_cind) at run time and are not redistributed with the ibex repository, so this replication pins the offline, fully reproducible day-ahead-price result. The CPI outcomes use the same estimator and the same specification; only the input data differs.

A note on the snapshot: the ibex sc_series output extends the day-ahead series to March 2024, while the committed input snapshot ends December 2023. The donor weights depend only on the shared January-2015 to May-2022 pre-treatment window, so they match exactly; the average post-treatment gap reported above is taken over the common window.

Verification#

The check is committed as the ibex_dap benchmark case (benchmarks/cases/ibex_dap.py), which runs VanillaSC on the shipped day-ahead panel and asserts the weights, the dominant-donor weight and the post-treatment ATT against the captured ibex reference under benchmarks/reference/ibex_dap/. It appears on the Validation dashboard dashboard under VanillaSC.