# ---
# 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]
# # Benchmark, Active Risk, And Attribution
#
# Here we compare an active bond portfolio with a simpler benchmark, then break the active stance into holdings, sector tilts, and duration/spread attribution.

# %%
from __future__ import annotations

import matplotlib

matplotlib.use("Agg")

import matplotlib.pyplot as plt
import pandas as pd

from fuggers_py.portfolio import PortfolioBenchmark, calculate_attribution, duration_difference_by_sector, spread_difference_by_sector

from examples._shared.datasets import build_benchmark_portfolio, 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)
benchmark = build_benchmark_portfolio(reference_date)
benchmark_view = PortfolioBenchmark(portfolio, benchmark)
comparison = benchmark_view.compare(curve, reference_date)
attribution = calculate_attribution(portfolio, curve=curve, settlement_date=reference_date)
sector_duration = duration_difference_by_sector(portfolio, benchmark, curve=curve, settlement_date=reference_date)
sector_spread = spread_difference_by_sector(portfolio, benchmark, curve=curve, settlement_date=reference_date)

comparison_table = pd.DataFrame(
    [
        {'metric': 'Portfolio duration', 'value': comparison.duration.portfolio_duration},
        {'metric': 'Benchmark duration', 'value': comparison.duration.benchmark_duration},
        {'metric': 'Active duration', 'value': comparison.duration.active_duration},
        {'metric': 'Portfolio YTM', 'value': comparison.yields.portfolio_ytm},
        {'metric': 'Benchmark YTM', 'value': comparison.yields.benchmark_ytm},
        {'metric': 'Active z-spread', 'value': comparison.spread.active_z_spread},
        {'metric': 'Active DV01', 'value': comparison.risk.active_dv01},
    ]
)
active_weights = pd.DataFrame(comparison.sector.active_weights.entries)
attribution_table = pd.DataFrame(attribution.entries)
duration_table = pd.DataFrame(sector_duration.entries)
spread_table = pd.DataFrame(sector_spread.entries)

# %%
display_table(comparison_table, percent_columns=['value'])
display_table(active_weights, percent_columns=['portfolio_weight', 'benchmark_weight', 'active_weight'])
display_table(attribution_table, percent_columns=['pv_pct', 'dv01_pct'], float_columns=['duration_contribution'])

# %% [markdown]
# The active book is longer spread and slightly longer duration than the benchmark. The active weights show that the underweight in government and benchmark corporate risk is being recycled into an industrial high-yield sleeve.

# %%
figure, axes = plt.subplots(1, 2, figsize=(12, 4.8))
axes[0].bar(active_weights['name'], 100 * active_weights['active_weight'])
axes[0].set_title('Active Weights By Sector')
axes[0].set_xlabel('Sector')
axes[0].set_ylabel('Active weight (%)')

axes[1].bar(duration_table['name'], duration_table['active_value'])
axes[1].set_title('Active Duration By Sector')
axes[1].set_xlabel('Sector')
axes[1].set_ylabel('Duration contribution')
plt.tight_layout()
figure

# %%
figure, axes = plt.subplots(1, 2, figsize=(12, 4.8))
axes[0].bar(spread_table['name'], 10000 * spread_table['active_value'])
axes[0].set_title('Active Spread By Sector')
axes[0].set_xlabel('Sector')
axes[0].set_ylabel('Active spread (bps)')

axes[1].bar(attribution_table['name'], attribution_table['duration_contribution'])
axes[1].set_title('Holdings Contribution To Portfolio Duration')
axes[1].set_xlabel('Holding')
axes[1].set_ylabel('Duration contribution')
plt.tight_layout()
figure

# %% [markdown]
# ## Active stance
#
# - The portfolio is intentionally underweight the benchmark's government ballast.
# - The active spread comes mostly from the industrial high-yield allocation rather than from the core BBB corporate holding.
# - The benchmark comparison is therefore a clean way to separate intended risk-taking from accidental carry differences.
