# ---
# 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]
# # Floating-rate note and discount margin examples

# %%
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.analytics.spreads import DiscountMarginCalculator  # noqa: E402
from fuggers_py.bonds.indices import BondIndex, IndexConventions, IndexFixingStore, OvernightCompounding  # noqa: E402
from fuggers_py.bonds.instruments import FloatingRateNoteBuilder  # noqa: E402
from fuggers_py.bonds.types import RateIndex, YieldCalculationRules  # noqa: E402
from fuggers_py.core import Date, Frequency  # noqa: E402
from fuggers_py.curves import DiscountCurveBuilder, ForwardCurve  # noqa: E402

# %% [markdown]
# ## Build the FRN and supporting curves

# %%
ref = Date.from_ymd(2024, 1, 1)
rules = replace(YieldCalculationRules.us_corporate(), frequency=Frequency.QUARTERLY)
frn = (
    FloatingRateNoteBuilder.new()
    .with_issue_date(ref)
    .with_maturity_date(ref.add_years(2))
    .with_index(RateIndex.SOFR)
    .with_quoted_spread(Decimal("0.0025"))
    .with_current_reference_rate(Decimal("0.03"))
    .with_frequency(Frequency.QUARTERLY)
    .with_rules(rules)
    .with_cap(Decimal("0.05"))
    .build()
)
discount_curve = (
    DiscountCurveBuilder(reference_date=ref)
    .add_zero_rate(0.25, Decimal("0.03"))
    .add_zero_rate(5.0, Decimal("0.03"))
    .build()
)
forward_curve = ForwardCurve.from_months(discount_curve, 3)

# %% [markdown]
# ## Compute discount margin and round-trip the price

# %%
calculator = DiscountMarginCalculator(forward_curve=forward_curve, discount_curve=discount_curve)
dirty_price = calculator.price_with_dm(frn, Decimal("0.005"), ref)
discount_margin = calculator.calculate(frn, dirty_price, ref)

print("Projected cash flows:")
for flow in frn.projected_cash_flows(forward_curve, ref):
    print(flow.date, flow.amount, flow.reference_rate)

print("Dirty price from 50bp DM:", dirty_price)
print("Recovered DM:", discount_margin)
print("Spread DV01:", calculator.spread_dv01(frn, discount_margin, ref))
print("Spread duration:", calculator.spread_duration(frn, discount_margin, ref))

# %% [markdown]
# ## Historical fixings and FRN coupon projection

# %%
fixing_store = IndexFixingStore()
for offset, fixing in enumerate(["0.0500", "0.0505", "0.0510", "0.0515", "0.0520"], start=0):
    fixing_store.add_fixing("SOFR", ref.add_days(offset), Decimal(fixing))

sofr_index = BondIndex(
    name="SOFR",
    rate_index=RateIndex.SOFR,
    conventions=IndexConventions(overnight_compounding=OvernightCompounding.COMPOUNDED),
    fixing_store=fixing_store,
)

frn_with_fixings = (
    FloatingRateNoteBuilder.new()
    .with_issue_date(ref)
    .with_maturity_date(ref.add_years(1))
    .with_index(RateIndex.SOFR)
    .with_index_definition(sofr_index)
    .with_quoted_spread(Decimal("0.0025"))
    .with_current_reference_rate(Decimal("0.05"))
    .with_frequency(Frequency.QUARTERLY)
    .with_rules(rules)
    .build()
)

print("\nCash flows using historical fixings:")
for flow in frn_with_fixings.cash_flows_with_fixings(fixing_store, settlement_date=ref):
    print(flow.date, flow.amount, flow.reference_rate)
