# ---
# 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]
# # Risk, Hedging, And VaR
#
# We build a small single-name risk worksheet: two bonds, a base curve, a tenor profile, a simple DV01 hedge ratio, and a compact VaR view from deterministic return scenarios.

# %%
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.analytics.pricing import BondPricer
from fuggers_py.analytics.risk import historical_var, parametric_var, parametric_var_from_dv01
from fuggers_py.analytics.risk.duration import KeyRateDurationCalculator, STANDARD_KEY_RATE_TENORS, spread_duration
from fuggers_py.bonds import FixedBondBuilder, YieldCalculationRules
from fuggers_py.core import Currency, Date, Frequency
from fuggers_py.curves import DiscountCurveBuilder, ParallelBump

from examples._shared.plotting import apply_research_style, percent_axis
from examples._shared.tables import display_table

apply_research_style()

# %% [markdown]
# ## Base instruments and curve
#
# The long bond is the risk we want to hedge; the intermediate bond acts as a liquid hedge candidate.

# %%
reference_date = Date.from_ymd(2024, 1, 2)
curve = (
    DiscountCurveBuilder(reference_date=reference_date)
    .add_zero_rate(0.5, Decimal('0.0300'))
    .add_zero_rate(2.0, Decimal('0.0330'))
    .add_zero_rate(5.0, Decimal('0.0380'))
    .add_zero_rate(10.0, Decimal('0.0410'))
    .build()
)
long_bond = (
    FixedBondBuilder.new()
    .with_issue_date(reference_date)
    .with_maturity_date(reference_date.add_years(10))
    .with_coupon_rate(Decimal('0.0475'))
    .with_frequency(Frequency.SEMI_ANNUAL)
    .with_currency(Currency.USD)
    .with_rules(YieldCalculationRules.us_corporate())
    .build()
)
hedge_bond = (
    FixedBondBuilder.new()
    .with_issue_date(reference_date)
    .with_maturity_date(reference_date.add_years(5))
    .with_coupon_rate(Decimal('0.0400'))
    .with_frequency(Frequency.SEMI_ANNUAL)
    .with_currency(Currency.USD)
    .with_rules(YieldCalculationRules.us_corporate())
    .build()
)
pricer = BondPricer()

# %%
base_long = pricer.price_from_curve(long_bond, curve, reference_date)
base_hedge = pricer.price_from_curve(hedge_bond, curve, reference_date)
bump_size = 1e-4
long_up = pricer.price_from_curve(long_bond, ParallelBump(bump_size).apply(curve), reference_date)
long_down = pricer.price_from_curve(long_bond, ParallelBump(-bump_size).apply(curve), reference_date)
hedge_up = pricer.price_from_curve(hedge_bond, ParallelBump(bump_size).apply(curve), reference_date)
hedge_down = pricer.price_from_curve(hedge_bond, ParallelBump(-bump_size).apply(curve), reference_date)
long_dv01 = (long_down.dirty.as_percentage() - long_up.dirty.as_percentage()) / Decimal('2')
hedge_dv01 = (hedge_down.dirty.as_percentage() - hedge_up.dirty.as_percentage()) / Decimal('2')
effective_duration = (long_down.dirty.as_percentage() - long_up.dirty.as_percentage()) / (Decimal('2') * base_long.dirty.as_percentage() * Decimal(str(bump_size)))
key_rate_profile = KeyRateDurationCalculator(bump=bump_size).calculate(long_bond, curve, reference_date, tenors=list(STANDARD_KEY_RATE_TENORS))
spread_dur = spread_duration(long_bond, None, reference_date, curve=curve, spread=Decimal('0.0'), bump=bump_size)
hedge_ratio = long_dv01 / hedge_dv01

risk_table = pd.DataFrame(
    [
        {'metric': 'Long-bond price', 'value': base_long.dirty.as_percentage()},
        {'metric': 'Long-bond DV01', 'value': long_dv01},
        {'metric': 'Effective duration', 'value': effective_duration},
        {'metric': 'Spread duration', 'value': spread_dur},
        {'metric': '5Y hedge DV01', 'value': hedge_dv01},
        {'metric': 'DV01 hedge ratio', 'value': hedge_ratio},
    ]
)

display_table(risk_table, float_columns=['value'])

# %% [markdown]
# Effective duration captures curve-driven price sensitivity, while spread duration isolates the credit spread move. The hedge ratio translates that risk into a simple amount of the 5Y hedge bond needed to neutralize first-order rate exposure.

# %%
key_rate_table = pd.DataFrame(
    {'tenor': [str(item.tenor) for item in key_rate_profile.items], 'duration': [item.duration for item in key_rate_profile.items]}
)
hedge_table = pd.DataFrame(
    [
        {'position': 'Long 10Y bond', 'dv01': long_dv01, 'notional_units': Decimal('1.0')},
        {'position': 'Short 5Y hedge bond', 'dv01': -hedge_dv01, 'notional_units': -hedge_ratio},
    ]
)

display_table(key_rate_table, float_columns=['duration'])
display_table(hedge_table, float_columns=['dv01', 'notional_units'])

# %% [markdown]
# ## Deterministic VaR scenarios
#
# We use a short synthetic return history to compare historical and parametric VaR with a DV01-based approximation from a 15bp rates shock.

# %%
returns = [-0.0110, -0.0075, -0.0050, -0.0035, -0.0020, -0.0012, 0.0005, 0.0010, 0.0025, 0.0035, 0.0055, 0.0070]
historical = historical_var(returns, confidence=0.95)
parametric = parametric_var(returns, confidence=0.95)
dv01_var = parametric_var_from_dv01(long_dv01, shock_bps=15.0, confidence=0.95)
var_table = pd.DataFrame(
    [
        {'method': 'Historical', 'value': historical.value},
        {'method': 'Parametric', 'value': parametric.value},
        {'method': 'DV01 approximation', 'value': dv01_var.value},
    ]
)

display_table(var_table, percent_columns=['value'])

# %%
figure, axes = plt.subplots(1, 2, figsize=(12, 4.8))
axes[0].bar(key_rate_table['tenor'], key_rate_table['duration'])
axes[0].set_title('Key-Rate Duration Profile')
axes[0].set_xlabel('Tenor')
axes[0].set_ylabel('Duration contribution')

axes[1].plot(range(1, len(returns) + 1), [100 * value for value in returns], marker='o', linewidth=2, label='Scenario return')
axes[1].axhline(-100 * float(historical.value), color='#8c2f39', linestyle='--', label='Historical VaR')
axes[1].axhline(-100 * float(parametric.value), color='#e09f3e', linestyle='--', label='Parametric VaR')
axes[1].set_title('Return Path And VaR Markers')
axes[1].set_xlabel('Observation')
axes[1].set_ylabel('Return')
percent_axis(axes[1])
axes[1].legend(title='')
plt.tight_layout()
figure

# %% [markdown]
# ## Interpretation
#
# - DV01 and effective duration are the right first-pass tools for parallel rate hedging.
# - Key-rate duration shows where that exposure actually sits along the curve.
# - Spread duration matters because a credit bond rarely moves on rates alone.
# - Historical VaR reflects the realized tail in the chosen window; parametric VaR is smoother but can understate skewed or regime-driven losses.
