Coverage for tests/test_bonds.py: 99%
70 statements
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-05 14:27 +0000
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-05 14:27 +0000
1from unittest import main, TestCase
2from rivapy.instruments import ZeroCouponBondSpecification, FixedRateBondSpecification, FloatingRateNoteSpecification, PlainVanillaCouponBondSpecification
3from rivapy.tools.enums import RollConvention, SecuritizationLevel, DayCounterType, Currency
4from rivapy.pricing import SimpleCashflowPricer
5from rivapy.marketdata import DiscountCurveParametrized, ConstantRate
6from datetime import date, datetime
9class BondSpecificationTests(TestCase):
11 def test_bond_specification(self):
12 # zero coupon bond
13 zero_coupon_bond = ZeroCouponBondSpecification('US500769CH58', datetime(2007, 6, 29), datetime(2037, 6, 29), 'USD', 1000, 'KfW',
14 SecuritizationLevel.SENIOR_UNSECURED)
15 self.assertEqual(zero_coupon_bond.obj_id, 'US500769CH58')
16 self.assertEqual(zero_coupon_bond.issue_date, datetime(2007, 6, 29))
17 self.assertEqual(zero_coupon_bond.maturity_date, datetime(2037, 6, 29))
18 self.assertEqual(zero_coupon_bond.currency, 'USD')
19 self.assertEqual(zero_coupon_bond.notional, 1000)
20 self.assertEqual(zero_coupon_bond.issuer, 'KfW')
21 self.assertEqual(zero_coupon_bond.securitization_level, 'SENIOR_UNSECURED')
22 # fixed rate bond
23 fixed_rate_bond = FixedRateBondSpecification.from_master_data('DE000CZ40NT7', datetime(2019, 3, 11), datetime(2024, 9, 11), 0.0125,
24 '1Y', True, True, RollConvention.FOLLOWING, 'DE', 'EUR',
25 100000, 'Commerzbank',
26 SecuritizationLevel.NON_PREFERRED_SENIOR)
27 self.assertEqual(fixed_rate_bond.obj_id, 'DE000CZ40NT7')
28 self.assertEqual(fixed_rate_bond.issue_date, datetime(2019, 3, 11))
29 self.assertEqual(fixed_rate_bond.maturity_date, datetime(2024, 9, 11))
30 self.assertEqual(fixed_rate_bond.coupon_payment_dates, [datetime(2019, 9, 11), datetime(2020, 9, 11), datetime(2021, 9, 13),
31 datetime(2022, 9, 12), datetime(2023, 9, 11),
32 datetime(2024, 9, 11)])
33 self.assertEqual(fixed_rate_bond.coupons, [0.0125, 0.0125, 0.0125, 0.0125, 0.0125, 0.0125])
34 self.assertEqual(fixed_rate_bond.currency, 'EUR')
35 self.assertEqual(fixed_rate_bond.notional, 100000)
36 self.assertEqual(fixed_rate_bond.issuer, 'Commerzbank')
37 self.assertEqual(fixed_rate_bond.securitization_level, 'NON_PREFERRED_SENIOR')
38 fixed_rate_bond = FixedRateBondSpecification('DE000CZ40NT7', datetime(2019, 3, 11), datetime(2024, 9, 11),
39 fixed_rate_bond.coupon_payment_dates, fixed_rate_bond.coupons, 'EUR', 100000,
40 'Commerzbank', SecuritizationLevel.NON_PREFERRED_SENIOR)
41 self.assertEqual(fixed_rate_bond.obj_id, 'DE000CZ40NT7')
42 self.assertEqual(fixed_rate_bond.issue_date, datetime(2019, 3, 11))
43 self.assertEqual(fixed_rate_bond.maturity_date, datetime(2024, 9, 11))
44 self.assertEqual(fixed_rate_bond.coupon_payment_dates, [datetime(2019, 9, 11), datetime(2020, 9, 11), datetime(2021, 9, 13),
45 datetime(2022, 9, 12), datetime(2023, 9, 11),
46 datetime(2024, 9, 11)])
47 self.assertEqual(fixed_rate_bond.coupons, [0.0125, 0.0125, 0.0125, 0.0125, 0.0125, 0.0125])
48 self.assertEqual(fixed_rate_bond.currency, 'EUR')
49 self.assertEqual(fixed_rate_bond.notional, 100000)
50 self.assertEqual(fixed_rate_bond.issuer, 'Commerzbank')
51 self.assertEqual(fixed_rate_bond.securitization_level, 'NON_PREFERRED_SENIOR')
53 # floating rate bond
54 floating_rate_note = FloatingRateNoteSpecification.from_master_data('DE000HLB3DU1', datetime(2016, 6, 23), datetime(2024, 6, 27),
55 '3M', True, False, RollConvention.FOLLOWING, 'DE',
56 DayCounterType.ThirtyU360, 0.0, 'EURIBOR_3M', 'EUR', 1000,
57 'Helaba', SecuritizationLevel.NON_PREFERRED_SENIOR)
58 self.assertEqual(floating_rate_note.obj_id, 'DE000HLB3DU1')
59 self.assertEqual(floating_rate_note.issue_date, datetime(2016, 6, 23))
60 self.assertEqual(floating_rate_note.maturity_date, datetime(2024, 6, 27))
61 self.assertEqual(floating_rate_note.coupon_period_dates, [datetime(2016, 6, 23), datetime(2016, 9, 27),
62 datetime(2016, 12, 27), datetime(2017, 3, 27),
63 datetime(2017, 6, 27), datetime(2017, 9, 27),
64 datetime(2017, 12, 27), datetime(2018, 3, 27),
65 datetime(2018, 6, 27), datetime(2018, 9, 27),
66 datetime(2018, 12, 27), datetime(2019, 3, 27),
67 datetime(2019, 6, 27), datetime(2019, 9, 27),
68 datetime(2019, 12, 27), datetime(2020, 3, 27),
69 datetime(2020, 6, 29), datetime(2020, 9, 28),
70 datetime(2020, 12, 28), datetime(2021, 3, 29),
71 datetime(2021, 6, 28), datetime(2021, 9, 27),
72 datetime(2021, 12, 27), datetime(2022, 3, 28),
73 datetime(2022, 6, 27), datetime(2022, 9, 27),
74 datetime(2022, 12, 27), datetime(2023, 3, 27),
75 datetime(2023, 6, 27), datetime(2023, 9, 27),
76 datetime(2023, 12, 27), datetime(2024, 3, 27),
77 datetime(2024, 6, 27)])
78 self.assertEqual(floating_rate_note.daycount_convention, '30U360')
79 self.assertEqual(floating_rate_note.spreads, [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
80 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
81 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])
82 self.assertEqual(floating_rate_note.reference_index, 'EURIBOR_3M')
83 self.assertEqual(floating_rate_note.currency, 'EUR')
84 self.assertEqual(floating_rate_note.notional, 1000)
85 self.assertEqual(floating_rate_note.issuer, 'Helaba')
86 self.assertEqual(floating_rate_note.securitization_level, 'NON_PREFERRED_SENIOR')
87 floating_rate_note = FloatingRateNoteSpecification('DE000HLB3DU1', datetime(2016, 6, 23), datetime(2024, 6, 27),
88 floating_rate_note.coupon_period_dates, DayCounterType.ThirtyU360,
89 floating_rate_note.spreads, 'EURIBOR_3M', 'EUR', 1000, 'Helaba',
90 SecuritizationLevel.NON_PREFERRED_SENIOR)
91 self.assertEqual(floating_rate_note.obj_id, 'DE000HLB3DU1')
92 self.assertEqual(floating_rate_note.issue_date, datetime(2016, 6, 23))
93 self.assertEqual(floating_rate_note.maturity_date, datetime(2024, 6, 27))
94 self.assertEqual(floating_rate_note.coupon_period_dates, [datetime(2016, 6, 23), datetime(2016, 9, 27),
95 datetime(2016, 12, 27), datetime(2017, 3, 27),
96 datetime(2017, 6, 27), datetime(2017, 9, 27),
97 datetime(2017, 12, 27), datetime(2018, 3, 27),
98 datetime(2018, 6, 27), datetime(2018, 9, 27),
99 datetime(2018, 12, 27), datetime(2019, 3, 27),
100 datetime(2019, 6, 27), datetime(2019, 9, 27),
101 datetime(2019, 12, 27), datetime(2020, 3, 27),
102 datetime(2020, 6, 29), datetime(2020, 9, 28),
103 datetime(2020, 12, 28), datetime(2021, 3, 29),
104 datetime(2021, 6, 28), datetime(2021, 9, 27),
105 datetime(2021, 12, 27), datetime(2022, 3, 28),
106 datetime(2022, 6, 27), datetime(2022, 9, 27),
107 datetime(2022, 12, 27), datetime(2023, 3, 27),
108 datetime(2023, 6, 27), datetime(2023, 9, 27),
109 datetime(2023, 12, 27), datetime(2024, 3, 27),
110 datetime(2024, 6, 27)])
111 self.assertEqual(floating_rate_note.daycount_convention, '30U360')
112 self.assertEqual(floating_rate_note.spreads, [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
113 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
114 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])
115 self.assertEqual(floating_rate_note.reference_index, 'EURIBOR_3M')
116 self.assertEqual(floating_rate_note.currency, 'EUR')
117 self.assertEqual(floating_rate_note.notional, 1000)
118 self.assertEqual(floating_rate_note.issuer, 'Helaba')
119 self.assertEqual(floating_rate_note.securitization_level, 'NON_PREFERRED_SENIOR')
121 # fixed-to-floating rate note
122 # if False:
123 # # not correctly working
124 # fixed_to_floating_rate_note = FixedToFloatingRateNote.from_master_data('XS1887493309', datetime(2018, 10, 4),
125 # datetime(2022, 1, 20), datetime(2023, 1, 20),
126 # 0.04247, '6M', '3M', True, True, True,
127 # False, RollConvention.MODIFIED_FOLLOWING,
128 # RollConvention.MODIFIED_FOLLOWING, 'DE',
129 # 'DE', DayCounterType.ThirtyU360, 0.0115,
130 # 'US_LIBOR_3M', 'USD', 1000000,
131 # 'Standard Chartered PLC',
132 # SecuritizationLevel.SENIOR_SECURED)
133 # self.assertEqual(fixed_to_floating_rate_note.obj_id, 'XS1887493309')
134 # # self.assertEqual(fixed_to_floating_rate_note.issue_date, datetime(2018, 10, 4))
135 # self.assertEqual(fixed_to_floating_rate_note.maturity_date, datetime(2023, 1, 20))
136 # self.assertEqual(fixed_to_floating_rate_note.coupon_payment_dates, [datetime(2019, 1, 21), datetime(2019, 7, 22),
137 # datetime(2020, 1, 20), datetime(2020, 7, 20),
138 # datetime(2021, 1, 20), datetime(2021, 7, 20),
139 # datetime(2022, 1, 20)])
140 # self.assertEqual(fixed_to_floating_rate_note.coupons, [0.04247, 0.04247, 0.04247, 0.04247, 0.04247, 0.04247,
141 # 0.04247])
142 # self.assertEqual(fixed_to_floating_rate_note.coupon_period_dates, [datetime(2022, 1, 20), datetime(2022, 4, 20),
143 # datetime(2022, 7, 20), datetime(2022, 10, 20),
144 # datetime(2023, 1, 20)])
145 # self.assertEqual(fixed_to_floating_rate_note.day_count_convention, '30U360')
146 # self.assertEqual(fixed_to_floating_rate_note.spreads, [0.0115, 0.0115, 0.0115, 0.0115])
147 # self.assertEqual(fixed_to_floating_rate_note.currency, 'USD')
148 # self.assertEqual(fixed_to_floating_rate_note.notional, 1000000)
149 # self.assertEqual(fixed_to_floating_rate_note.issuer, 'Standard Chartered PLC')
150 # self.assertEqual(fixed_to_floating_rate_note.securitization_level, 'SENIOR_SECURED')
152class BondPricingTests(TestCase):
154 def test_yield_bond(self):
155 """Simple test for yield computation: Fixed rate used to compute pv which is then used to compute yield.
156 """
157 ref_date = datetime(2023,5,1)
158 bond_spec = PlainVanillaCouponBondSpecification('PV_BOND',
159 issue_date = datetime(2023,1,1),
160 maturity_date = datetime(2025,1,2),
161 currency = Currency.EUR, notional=100.0,
162 issuer='None',
163 securitization_level=SecuritizationLevel.SUBORDINATED,
164 coupon = 0.05, coupon_freq='1Y',
165 accrual_start = datetime(2023,2,10))
166 dc = DiscountCurveParametrized('', ref_date, ConstantRate(0.05))
167 bond_price = SimpleCashflowPricer.pv_cashflows(ref_date, bond_spec, dc)
168 bond_yield = SimpleCashflowPricer.compute_yield(target_dirty_price=bond_price,
169 val_date = ref_date,
170 specification=bond_spec)
171 self.assertAlmostEqual(bond_yield,0.05, delta=1e-3)
172if __name__ == '__main__':
173 main()