Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main'
Browse files Browse the repository at this point in the history
  • Loading branch information
attack68 committed Jan 11, 2024
2 parents c01f1f7 + 2c92a1f commit 32c24f1
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 3 deletions.
2 changes: 1 addition & 1 deletion rateslib/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class NoInput(Enum):
"""
Enumerable type to handle setting default values.
See :ref:`<default values <defaults-doc>`.
See :ref:`default values <defaults-doc>`.
"""
blank = 0
inherit = 1
Expand Down
9 changes: 9 additions & 0 deletions rateslib/fx.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ def _convert_dual(k, v):

# find currencies
self.pairs = [k for k in self.fx_rates.keys()]
self.pairs_settlement = {pair: settlement for pair in self.pairs}
self.variables = tuple(f"fx_{pair}" for pair in self.pairs)
self.currencies = {
k: i
Expand Down Expand Up @@ -838,6 +839,9 @@ def update(
fx_rates=fx_rates_obj,
fx_curves=sub_curves,
)
settlement_pairs = {
pair: fx_rates_obj.settlement for pair in fx_rates_obj.pairs
}
else:
# calculate additional FX rates from previous objects
# in the same settlement frame.
Expand All @@ -860,6 +864,9 @@ def update(
self.fx_curves, fx_rates_obj.currencies_list + pre_currencies
)
acyclic_fxf = FXForwards(fx_rates=combined_fx_rates, fx_curves=sub_curves)
settlement_pairs.update(
{pair: fx_rates_obj.settlement for pair in fx_rates_obj.pairs}
)

if base is not NoInput.blank:
acyclic_fxf.base = base.lower()
Expand All @@ -874,6 +881,7 @@ def update(
"pairs",
]:
setattr(self, attr, getattr(acyclic_fxf, attr))
self.pairs_settlement = settlement_pairs
else:
self.currencies = self.fx_rates.currencies
self.q = len(self.currencies.keys())
Expand All @@ -885,6 +893,7 @@ def update(
self.pairs = self.fx_rates.pairs
self.variables = tuple(f"fx_{pair}" for pair in self.pairs)
self.fx_rates_immediate = self._update_fx_rates_immediate()
self.pairs_settlement = self.fx_rates.pairs_settlement

def __init__(
self,
Expand Down
4 changes: 2 additions & 2 deletions rateslib/instruments.py
Original file line number Diff line number Diff line change
Expand Up @@ -1967,7 +1967,7 @@ class FixedRateBond(Sensitivities, BondMixin, BaseMixin):
- "ust": US Treasury street convention. Same as "ukg" except long stub periods have linear
proportioning only in the segregated short stub part.
- "ust_31bii": US Treasury convention that reprices examples in federal documents: Section
31-B-ii).
31-B-ii). Otherwise referred to as the 'Treasury' method.
- "sgb": Swedish government bond convention. Accrued ignores the convention and calculates
using 30e360, also for back stubs.
- "cadgb" Canadian government bond convention. Accrued is calculated using an ACT365F
Expand Down Expand Up @@ -2878,7 +2878,7 @@ def rate(
Only used if ``fx`` is an ``FXRates`` or ``FXForwards`` object.
metric : str, optional
Metric returned by the method. Available options are {"clean_price",
"dirty_price", "ytm"}
"dirty_price", "ytm", "index_clean_price", "index_dirty_price"}
forward_settlement : datetime, optional
The forward settlement date. If not given uses the discount *Curve* and the ``settle``
attribute of the bond.
Expand Down
32 changes: 32 additions & 0 deletions tests/test_fx.py
Original file line number Diff line number Diff line change
Expand Up @@ -903,6 +903,38 @@ def test_fxforwards_cyclic_system_restructured():
assert abs(result - expected) < 1e-2


def test_fxforwards_settlement_pairs():
fxr1 = FXRates({"eurusd": 1.05}, settlement=dt(2022, 1, 3))
fxr2 = FXRates({"usdcad": 1.1}, settlement=dt(2022, 1, 2))
fxr3 = FXRates({"gbpusd": 1.2}, settlement=dt(2022, 1, 3))
fxf = FXForwards(
fx_rates=[fxr1, fxr2, fxr3], # FXRates as list
fx_curves={
"usdusd": Curve({dt(2022, 1, 1): 1.0, dt(2022, 2, 1): 0.999}),
"eureur": Curve({dt(2022, 1, 1): 1.0, dt(2022, 2, 1): 0.999}),
"cadcad": Curve({dt(2022, 1, 1): 1.0, dt(2022, 2, 1): 0.999}),
"usdeur": Curve({dt(2022, 1, 1): 1.0, dt(2022, 2, 1): 0.999}),
"cadeur": Curve({dt(2022, 1, 1): 1.0, dt(2022, 2, 1): 0.999}),
"gbpcad": Curve({dt(2022, 1, 1): 1.0, dt(2022, 2, 1): 0.999}),
"gbpgbp": Curve({dt(2022, 1, 1): 1.0, dt(2022, 2, 1): 0.999}),
},
)
assert fxf.pairs_settlement["eurusd"] == dt(2022, 1, 3)
assert fxf.pairs_settlement["usdcad"] == dt(2022, 1, 2)
assert fxf.pairs_settlement["gbpusd"] == dt(2022, 1, 3)

fxf = FXForwards(
fx_rates=fxr1, # FXRates as list
fx_curves={
"usdusd": Curve({dt(2022, 1, 1): 1.0, dt(2022, 2, 1): 0.999}),
"eureur": Curve({dt(2022, 1, 1): 1.0, dt(2022, 2, 1): 0.999}),
"usdeur": Curve({dt(2022, 1, 1): 1.0, dt(2022, 2, 1): 0.999}),
},
)
assert fxf.pairs_settlement["eurusd"] == dt(2022, 1, 3)



def test_fxforwards_positions_when_immediate_aligns_with_settlement():
fxr1 = FXRates({"eurusd": 1.05}, settlement=dt(2022, 1, 1))
fxr2 = FXRates({"usdcad": 1.1}, settlement=dt(2022, 1, 1))
Expand Down
28 changes: 28 additions & 0 deletions tests/test_instruments_bonds.py
Original file line number Diff line number Diff line change
Expand Up @@ -1009,6 +1009,34 @@ def test_fixed_rate_bond_fwd_rate(self):
# def test_convexity(self):
# assert False

def test_latest_fixing(self):
# this is German government inflation bond with fixings given for a specific settlement
# calculation

ibnd = IndexFixedRateBond(
effective=dt(2021, 2, 11),
front_stub=dt(2022, 4, 15),
termination=dt(2033, 4, 15),
convention="ActActICMA",
calendar="tgt",
frequency="A",
index_lag=3,
index_base=124.17000 / 1.18851, # implying from 1st Jan 2024 on webpage
index_method="daily",
payment_lag=0,
currency="eur",
fixed_rate=0.1,
ex_div=1,
settle=1,
index_fixings=Series(
data=[124.17, 123.46],
index=[dt(2024, 1, 1), dt(2024, 2, 1)]
),
)
result = ibnd.ytm(price=100.32, settlement=dt(2024, 1, 5))
expected = 0.065
assert (result - expected) < 1e-2


class TestBill:
def test_bill_discount_rate(self):
Expand Down

0 comments on commit 32c24f1

Please sign in to comment.