# ---
# 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]
# # Tutorial: fuggers_py.analytics.spreads examples
#
# This notebook demonstrates:
#
# - Government curve construction
# - G-spread (interpolated + explicit)
# - I-spread (swap curve)
# - Z-spread roundtrip

# %%
# Setup cell
from __future__ import annotations

import sys
from decimal import Decimal
from math import exp
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"))

# %% [markdown]
# ## Imports

# %%
from fuggers_py.analytics.spreads import (  # noqa: E402
    BenchmarkSpec,
    GovernmentCurve,
    GSpreadCalculator,
    ISpreadCalculator,
    ZSpreadCalculator,
    g_spread,
    g_spread_with_benchmark,
    i_spread,
    z_spread_from_curve,
)
from fuggers_py.bonds.instruments import FixedBondBuilder  # noqa: E402
from fuggers_py.bonds.traits import BondCashFlow, CashFlowType  # noqa: E402
from fuggers_py.bonds.types import Tenor, YieldCalculationRules  # noqa: E402
from fuggers_py.curves import DiscountCurveBuilder  # noqa: E402
from fuggers_py.core import Currency, Date, Frequency, Price  # noqa: E402

# %% [markdown]
# ## Government curve

# %%
reference_date = Date.from_ymd(2020, 1, 1)

gov_curve = GovernmentCurve.us_treasury(reference_date)

gov_curve.add_benchmark(Tenor.parse("2Y"), Decimal("0.02"))

gov_curve.add_benchmark(Tenor.parse("5Y"), Decimal("0.03"))

gov_curve.add_benchmark(Tenor.parse("10Y"), Decimal("0.04"))

interpolated_7y = gov_curve.interpolated_yield(7.0)
interpolated_7y

# %% [markdown]
# ## Build a fixed-rate bond

# %%
issue = Date.from_ymd(2015, 6, 15)
maturity = Date.from_ymd(2025, 6, 15)

bond = (
    FixedBondBuilder.new()
    .with_issue_date(issue)
    .with_maturity_date(maturity)
    .with_coupon_rate(Decimal("0.075"))
    .with_frequency(Frequency.SEMI_ANNUAL)
    .with_currency(Currency.USD)
    .with_rules(YieldCalculationRules.us_corporate())
    .build()
)

# %% [markdown]
# ## G-spread (interpolated + explicit benchmark)

# %%
bond_yield = Decimal("0.05")

spread_interpolated = g_spread_with_benchmark(bond_yield, gov_curve, bond.maturity_date())
spread_explicit = g_spread(bond_yield, Decimal("0.0425"))
spread_interpolated, spread_explicit

# %% [markdown]
# ## Date-based benchmark semantics (interpolated / nearest / 10Y / explicit)

# %%
maturity_date = Date.from_ymd(2027, 1, 1)

g_interpolated = g_spread_with_benchmark(
    bond_yield,
    gov_curve,
    maturity_date,
    benchmark=BenchmarkSpec.interpolated(),
)
g_nearest = g_spread_with_benchmark(
    bond_yield,
    gov_curve,
    maturity_date,
    benchmark=BenchmarkSpec.nearest(),
)
g_ten_year = g_spread_with_benchmark(
    bond_yield,
    gov_curve,
    maturity_date,
    benchmark=BenchmarkSpec.ten_year(),
)
g_explicit = g_spread_with_benchmark(
    bond_yield,
    gov_curve,
    maturity_date,
    benchmark=BenchmarkSpec.explicit(Decimal("0.0425")),
)

g_interpolated, g_nearest, g_ten_year, g_explicit

# %% [markdown]
# ## I-spread (swap curve)

# %%
swap_curve_builder = DiscountCurveBuilder(reference_date=reference_date)

swap_curve_builder.add_zero_rate(1.0, Decimal("0.04")).add_zero_rate(10.0, Decimal("0.04"))

swap_curve = swap_curve_builder.build()

ispread_calc = ISpreadCalculator(curve=swap_curve)
ispread_value = ispread_calc.spread_bps(bond, Decimal("0.055"))
ispread_value

# %% [markdown]
# ## Z-spread roundtrip (synthetic cashflows)

# %%
cf_settlement = reference_date
cashflows = [
    BondCashFlow(date=reference_date.add_years(1), amount=Decimal("5"), flow_type=CashFlowType.COUPON),
    BondCashFlow(
        date=reference_date.add_years(2),
        amount=Decimal("105"),
        flow_type=CashFlowType.COUPON_AND_PRINCIPAL,
    ),
]

known_z = 0.015

df_settle = float(swap_curve.discount_factor(cf_settlement))

dirty_price = 0.0
for cf in cashflows:
    t = float(cf_settlement.days_between(cf.date)) / 365.0
    df = float(swap_curve.discount_factor(cf.date)) / df_settle
    dirty_price += float(cf.factored_amount()) * df * exp(-known_z * t)

recovered = z_spread_from_curve(
    cashflows,
    dirty_price=dirty_price,
    curve=swap_curve,
    settlement_date=cf_settlement,
)
recovered_bps = recovered * Decimal("10000")
recovered_bps

# %% [markdown]
# ## Benchmark spec helpers

# %%
BenchmarkSpec.ten_year(), BenchmarkSpec.explicit(Decimal("0.0425")), BenchmarkSpec.nearest()
