|
| 1 | +import unittest |
| 2 | +from quantlib.settings import Settings |
| 3 | +from quantlib.time.api import ActualActual, Annual, Date, DateGeneration, Period, Schedule, Following, TARGET, Actual365Fixed |
| 4 | +from quantlib.instruments.api import BondForward, FixedRateBond |
| 5 | +from quantlib.termstructures.yield_term_structure import HandleYieldTermStructure |
| 6 | +from quantlib.pricingengines.api import DiscountingBondEngine |
| 7 | +from quantlib.position import Position |
| 8 | +from .utilities import flat_rate |
| 9 | + |
| 10 | +def build_bond(issue, maturity, cpn): |
| 11 | + sch = Schedule.from_rule(issue, maturity, Period(Annual), TARGET(), Following, Following, DateGeneration.Backward, False) |
| 12 | + return FixedRateBond(2, 100_000, sch, [cpn], ActualActual(ActualActual.ISDA)) |
| 13 | + |
| 14 | +def build_bond_forward(underlying, handle: HandleYieldTermStructure, deliver: Date, pos_type: Position): |
| 15 | + value_date = handle.current_link.reference_date |
| 16 | + return BondForward(value_date, deliver, pos_type, 0.0, 2, ActualActual(ActualActual.ISDA), |
| 17 | + TARGET(), Following, underlying, handle, handle) |
| 18 | + |
| 19 | + |
| 20 | +class TestBondForward(unittest.TestCase): |
| 21 | + |
| 22 | + def setUp(self): |
| 23 | + today = Date(7, 3, 2022) |
| 24 | + Settings().evaluation_date = today |
| 25 | + self.curve_handle = HandleYieldTermStructure(flat_rate(0.0004977, Actual365Fixed(), reference_date=today)) |
| 26 | + |
| 27 | + def test_futures_replication(self): |
| 28 | + """Testing futures prices replication""" |
| 29 | + |
| 30 | + issue = Date(15, 8, 2015) |
| 31 | + maturity = Date(15, 8, 2046) |
| 32 | + cpn = 0.025 |
| 33 | + |
| 34 | + bnd = build_bond(issue, maturity, cpn) |
| 35 | + pricer = DiscountingBondEngine(self.curve_handle) |
| 36 | + bnd.set_pricing_engine(pricer) |
| 37 | + |
| 38 | + delivery = Date(10, 3, 2022) |
| 39 | + conversion_factor = 0.76871 |
| 40 | + bnd_fwd = build_bond_forward(bnd, self.curve_handle, delivery, Position.Long) |
| 41 | + |
| 42 | + futures_price = bnd_fwd.clean_forward_price / conversion_factor |
| 43 | + expected_futures_price = 207.47 |
| 44 | + self.assertAlmostEqual(futures_price, expected_futures_price, 2) |
| 45 | + |
| 46 | + def test_clean_forward_price_replication(self): |
| 47 | + """Testing clean forward price replication""" |
| 48 | + |
| 49 | + issue = Date(15, 8, 2015) |
| 50 | + maturity = Date(15, 8, 2046) |
| 51 | + cpn = 0.025 |
| 52 | + |
| 53 | + bnd = build_bond(issue, maturity, cpn) |
| 54 | + pricer = DiscountingBondEngine(self.curve_handle) |
| 55 | + bnd.set_pricing_engine(pricer) |
| 56 | + |
| 57 | + delivery = Date(10, 3, 2022) |
| 58 | + bnd_fwd = build_bond_forward(bnd, self.curve_handle, delivery, Position.Long) |
| 59 | + |
| 60 | + fwd_clean_price = bnd_fwd.clean_forward_price |
| 61 | + expected_fwd_clean_price = bnd_fwd.forward_value - bnd.accrued_amount(delivery) |
| 62 | + |
| 63 | + self.assertAlmostEqual(fwd_clean_price, expected_fwd_clean_price) |
0 commit comments