# ---
# jupyter:
#   jupytext:
#     formats: ipynb,py:percent
#     text_representation:
#       extension: .py
#       format_name: percent
#       format_version: '1.3'
#       jupytext_version: 1.19.1
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# %% [markdown]
# # Stress Testing, Key Rates, And Scenarios
#
# Risk meetings need more than a single DV01. This notebook combines a key-rate profile with parallel, spread, and custom curve shocks to show best and worst cases for the same portfolio.

# %%
from __future__ import annotations

from decimal import Decimal

import matplotlib

matplotlib.use("Agg")

import matplotlib.pyplot as plt
import pandas as pd

from fuggers_py.portfolio import (
    aggregate_key_rate_profile,
    key_rate_shift_result,
    rate_shock_impact,
    run_stress_scenarios,
    spread_shock_result,
    standard_scenarios,
)

from examples._shared.datasets import build_research_portfolio, build_usd_discount_curve, research_reference_date
from examples._shared.plotting import apply_research_style
from examples._shared.tables import display_table

apply_research_style()

# %%
reference_date = research_reference_date()
curve = build_usd_discount_curve(reference_date)
portfolio = build_research_portfolio(reference_date)
profile = aggregate_key_rate_profile(portfolio, curve=curve, settlement_date=reference_date)
parallel_up = rate_shock_impact(portfolio, curve=curve, settlement_date=reference_date, bump_bps=Decimal('10'))
spread_widening = spread_shock_result(portfolio, curve=curve, settlement_date=reference_date, bump_bps=Decimal('25'))
custom_curve = key_rate_shift_result(
    portfolio,
    curve=curve,
    settlement_date=reference_date,
    tenor_shocks_bps={'2Y': Decimal('10'), '5Y': Decimal('-5'), '10Y': Decimal('15')},
)
standard = run_stress_scenarios(portfolio, curve=curve, settlement_date=reference_date, scenarios=standard_scenarios())

scenario_definitions = pd.DataFrame(
    [
        {'scenario': '+10bps parallel', 'description': 'Flat rates sell-off'},
        {'scenario': '+25bps spread widening', 'description': 'Broad credit spread shock'},
        {'scenario': 'Custom key-rate twist', 'description': '2Y and 10Y up, 5Y richer'},
    ]
)
scenario_results = pd.DataFrame(
    [
        {'scenario': '+10bps parallel', 'pnl': parallel_up.actual_change},
        {'scenario': '+25bps spread widening', 'pnl': spread_widening.actual_change},
        {'scenario': 'Custom key-rate twist', 'pnl': custom_curve.actual_change},
    ]
)
for name, result in standard.results.items():
    scenario_results.loc[len(scenario_results)] = {'scenario': name, 'pnl': result.actual_change}

key_rate_table = pd.DataFrame({'tenor': list(profile.entries.keys()), 'dv01': list(profile.entries.values())})

# %%
display_table(scenario_definitions)
display_table(scenario_results, float_columns=['pnl'])
display_table(key_rate_table, float_columns=['dv01'])

# %% [markdown]
# The worst-case stress is the credit-spread widening, not the simple parallel rates shock. That distinction matters in a mixed rates-and-credit book because hedging only the rates component leaves a material spread tail behind.

# %%
figure, axes = plt.subplots(1, 2, figsize=(12, 4.8))
axes[0].bar(scenario_results['scenario'], scenario_results['pnl'])
axes[0].set_title('Scenario P&L Comparison')
axes[0].set_xlabel('Scenario')
axes[0].set_ylabel('Change in value')
axes[0].tick_params(axis='x', rotation=20)

axes[1].bar(key_rate_table['tenor'], key_rate_table['dv01'])
axes[1].set_title('Aggregate Key-Rate Profile')
axes[1].set_xlabel('Tenor')
axes[1].set_ylabel('Key-rate DV01')
plt.tight_layout()
figure

# %%
figure, axis = plt.subplots(figsize=(10, 4.2))
ordered = scenario_results.sort_values('pnl')
axis.barh(ordered['scenario'], ordered['pnl'], color='#2c7da0')
axis.set_title('Best And Worst Cases')
axis.set_xlabel('Change in value')
axis.set_ylabel('Scenario')
plt.tight_layout()
figure

# %% [markdown]
# ## Risk-meeting use
#
# - Start with the key-rate chart to identify where the portfolio is truly long or short duration.
# - Use the scenario table to separate rates risk from spread risk.
# - Focus management attention on the scenarios with the largest negative P&L rather than on a single summary DV01.
