merton.scenarios.climate¶
Climate-transition scenarios.
This module provides the building blocks for climate stress testing in the TCFD / NGFS tradition. A climate scenario specifies:
A carbon-price path
c(t)(USD per tonne of CO₂-equivalent).Sectoral asset writedowns as a function of the carbon price and sector-specific emission intensities.
Sectoral PD multipliers that capture residual default-risk premia not absorbed into the asset value (e.g. demand destruction, regulatory change, technology obsolescence).
Stress-testing a firm under scenario s then becomes:
stressed_firm = s.apply(firm, sector=Sector.ENERGY).firm
result = MertonModel().fit(stressed_firm)
Sector emission intensities default to the (rounded) IEA 2024 NetZero pathway figures for the listed sectors, expressed as tonnes CO₂-equivalent per million USD of enterprise value (tCO₂e/M$). Users can override these with their own bottom-up estimates per portfolio.
References
NGFS (2024). NGFS Phase V Climate Scenarios for Central Banks and Supervisors. https://www.ngfs.net/ngfs-scenarios-portal/ IEA (2024). World Energy Outlook 2024. International Energy Agency. TCFD (2017). Recommendations of the Task Force on Climate-Related Financial Disclosures. Financial Stability Board.
Classes¶
GICS-aligned sector enumeration used throughout the climate module. |
|
A climate-transition stress scenario. |
Functions¶
|
Return the default emission intensity (tCO₂e per $M EV) for a sector. |
|
Asset writedown factor implied by a carbon price. |
|
Build a piecewise-linear carbon-price curve from |
Module Contents¶
- class merton.scenarios.climate.Sector[source]¶
-
GICS-aligned sector enumeration used throughout the climate module.
- merton.scenarios.climate.sectoral_carbon_intensity(sector: Sector | str) float[source]¶
Return the default emission intensity (tCO₂e per $M EV) for a sector.
Practitioners typically replace these with bottom-up Scope-1+2 figures from their internal data; the defaults are reasonable order-of-magnitude placeholders for top-down portfolio stress.
- merton.scenarios.climate.carbon_price_to_writedown(carbon_price: float, sector: Sector | str, *, pass_through: float = 0.5, intensity: float | None = None) float[source]¶
Asset writedown factor implied by a carbon price.
The fraction of enterprise value destroyed by a carbon price
cis\[\text{writedown}(c, \text{sector}) = \min\!\Bigl(1,\ (1 - \text{pass\_through}) \cdot \frac{c \cdot I_{\text{sector}}}{10^6}\Bigr),\]where
I_sectoris the emission intensity (tCO₂e per $M EV) andpass_throughis the share of the cost the firm passes through to customers (0 → fully absorbed by equity; 1 → fully passed through). The factor returned is the fractional writedown (e.g., 0.12 = 12 % asset value destroyed); apply it asA_stressed = A · (1 − writedown).- Parameters:
carbon_price – Carbon price
cin USD per tonne of CO₂-equivalent.sector – Sector tag (
Sectorenum or a string the enum can parse).pass_through – Fraction of the carbon cost passed through to customers, in
[0, 1]. Higher pass-through → smaller writedown.intensity – Override the default sector intensity (tCO₂e per $M EV).
- class merton.scenarios.climate.ClimateScenario[source]¶
Bases:
merton.scenarios.base.ScenarioA climate-transition stress scenario.
- Parameters:
name – Short identifier (e.g.
"NGFS Net Zero 2050").carbon_price_path – Callable
t → c(t)returning carbon price (USD/tCO₂e) at horizont(years). Usecarbon_price_curve()for a piecewise-linear helper.pd_multipliers –
{sector: multiplier}mapping.multiplier > 1increases PD relative to the no-stress baseline;< 1decreases it. Sectors absent from the mapping default to1.0.pass_through – Fraction of the carbon cost passed through to customers. Default 0.5 (half passed through, half borne by equity holders).
physical_writedown – Additional asset writedown to capture chronic physical risk (stranded assets, flooding, etc.) as a fraction of EV per year of horizon. Default 0.
description – Human-readable summary used in audit trails / reports.
- carbon_price_path: collections.abc.Callable[[float], float][source]¶
- asset_writedown(horizon: float, sector: Sector | str, *, intensity: float | None = None) float[source]¶
Total fractional asset writedown (transition + physical).
- pd_multiplier(sector: Sector | str) float[source]¶
Return the PD multiplier for
sector(1.0 if unset).
- apply(firm: merton.core.firm.Firm, *, sector: Sector | str | None = None, intensity: float | None = None, **kwargs: Any) merton.scenarios.base.ScenarioResult[source]¶
Apply the climate stress to
firmand return a stressed copy.The transformation only writes down equity (the observable input to Merton).
ClimateOverlayis the recommended wrapper if you also want PD-multiplier scaling applied to the structural output.
- merton.scenarios.climate.carbon_price_curve(knots: list[tuple[float, float]]) collections.abc.Callable[[float], float][source]¶
Build a piecewise-linear carbon-price curve from
(t, price)knots.Knots are sorted by time; beyond the last knot the function holds the final value constant (the NGFS convention).
Examples
>>> from merton.scenarios.climate import carbon_price_curve >>> path = carbon_price_curve([(0.0, 50.0), (10.0, 300.0)]) >>> path(5.0) 175.0