# ---
# 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]
# # Portfolio benchmark comparison

# %%
from __future__ import annotations

import sys
from dataclasses import replace
from decimal import Decimal
from pathlib import Path

root = Path.cwd()
if (root / "src").exists():
    sys.path.insert(0, str(root / "src"))
elif (root.parent / "src").exists():
    sys.path.insert(0, str(root.parent / "src"))

from fuggers_py.bonds.instruments import FixedBond  # noqa: E402
from fuggers_py.bonds.types import CreditRating, Sector, YieldCalculationRules  # noqa: E402
from fuggers_py.core import Currency, Date, Frequency  # noqa: E402
from fuggers_py.curves import DiscountCurveBuilder  # noqa: E402
from fuggers_py.portfolio import Classification, Holding, PortfolioBenchmark, PortfolioBuilder, estimate_tracking_error  # noqa: E402


# %%
reference_date = Date.from_ymd(2024, 1, 2)
curve = (
    DiscountCurveBuilder(reference_date=reference_date)
    .add_zero_rate(0.5, Decimal("0.030"))
    .add_zero_rate(2.0, Decimal("0.033"))
    .add_zero_rate(5.0, Decimal("0.038"))
    .add_zero_rate(10.0, Decimal("0.041"))
    .build()
)

def make_holding(label: str, years: int, coupon: str, price: str, sector: Sector, rating: CreditRating) -> Holding:
    bond = FixedBond.new(
        issue_date=reference_date,
        maturity_date=reference_date.add_years(years),
        coupon_rate=Decimal(coupon),
        frequency=Frequency.ANNUAL,
        currency=Currency.USD,
        rules=replace(YieldCalculationRules.us_corporate(), frequency=Frequency.ANNUAL),
    )
    return Holding(
        id=label,
        instrument=bond,
        quantity=Decimal("100"),
        clean_price=Decimal(price),
        label=label,
        classification=Classification(sector=sector, rating=rating, currency=Currency.USD),
    )


portfolio = (
    PortfolioBuilder()
    .with_currency(Currency.USD)
    .add_holding(make_holding("gov_short", 2, "0.0325", "99.5", Sector.GOVERNMENT, CreditRating.AA))
    .add_holding(make_holding("corp_bbb", 5, "0.0500", "101.0", Sector.CORPORATE, CreditRating.BBB))
    .add_holding(make_holding("corp_bb", 8, "0.0625", "98.0", Sector.INDUSTRIALS, CreditRating.BB))
    .build()
)
benchmark_portfolio = (
    PortfolioBuilder()
    .with_currency(Currency.USD)
    .add_holding(make_holding("bench_gov", 3, "0.0300", "100.5", Sector.GOVERNMENT, CreditRating.A))
    .add_holding(make_holding("bench_corp", 6, "0.0450", "100.0", Sector.CORPORATE, CreditRating.BBB))
    .build()
)


# %% [markdown]
# ## Compare active risk and weights

# %%
benchmark = PortfolioBenchmark(portfolio, benchmark_portfolio)
comparison = benchmark.compare(curve, reference_date)
{
    "active_duration": comparison.active_duration,
    "active_dv01": comparison.active_dv01,
    "active_ytm": comparison.active_ytm,
    "tracking_error_estimate": estimate_tracking_error(benchmark, curve, reference_date),
}

# %%
{
    "active_weights": benchmark.active_weights(curve, reference_date),
    "active_weights_by_sector": benchmark.active_weights_by_sector(curve, reference_date),
}
