PYield 0.12.0__tar.gz → 0.12.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyield-0.12.0 → pyield-0.12.2}/PKG-INFO +1 -1
- pyield-0.12.2/pyield/__about__.py +1 -0
- {pyield-0.12.0 → pyield-0.12.2}/pyield/bonds/ntnf.py +61 -18
- {pyield-0.12.0 → pyield-0.12.2}/pyield/di.py +1 -3
- {pyield-0.12.0 → pyield-0.12.2}/pyproject.toml +2 -2
- pyield-0.12.0/pyield/__about__.py +0 -1
- {pyield-0.12.0 → pyield-0.12.2}/LICENSE +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/README.md +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/pyield/__init__.py +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/pyield/bday.py +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/pyield/bonds/__init__.py +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/pyield/bonds/lft.py +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/pyield/bonds/ltn.py +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/pyield/bonds/ntnb.py +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/pyield/bonds/utils.py +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/pyield/date_converter.py +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/pyield/fetchers/__init__.py +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/pyield/fetchers/anbima.py +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/pyield/fetchers/futures_data/__init__.py +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/pyield/fetchers/futures_data/common.py +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/pyield/fetchers/futures_data/historical.py +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/pyield/fetchers/futures_data/intraday.py +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/pyield/fetchers/futures_data/xml.py +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/pyield/fetchers/indicators.py +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/pyield/fetchers/projections.py +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/pyield/holidays/__init__.py +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/pyield/holidays/br_holidays_new.txt +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/pyield/holidays/br_holidays_old.txt +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/pyield/holidays/holidays_manager.py +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/pyield/interpolator.py +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/pyield/py.typed +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/tests/__init__.py +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/tests/data/SPRD231222.zip +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/tests/data/SPRD240426.zip +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/tests/test_bday.py +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/tests/test_futures.py +0 -0
- {pyield-0.12.0 → pyield-0.12.2}/tests/test_futures_xml.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.12.2"
|
|
@@ -321,43 +321,86 @@ def gross_di_spreads(reference_date: str | pd.Timestamp) -> pd.Series:
|
|
|
321
321
|
return df["DISpread"]
|
|
322
322
|
|
|
323
323
|
|
|
324
|
-
def net_di_spread(
|
|
325
|
-
|
|
324
|
+
def net_di_spread( # noqa
|
|
325
|
+
settlement_date: str | pd.Timestamp,
|
|
326
326
|
maturity_date: str | pd.Timestamp,
|
|
327
|
+
ytm: float,
|
|
328
|
+
di_rates: list[float] | pd.Series,
|
|
329
|
+
di_expirations: list[pd.Timestamp] | pd.Series,
|
|
330
|
+
initial_guess: float | None = None,
|
|
327
331
|
) -> float:
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
332
|
+
"""
|
|
333
|
+
Calculate the net DI spread for a bond given the YTM and the DI rates.
|
|
334
|
+
|
|
335
|
+
This function determines the spread over the DI curve that equates the present value
|
|
336
|
+
of the bond's cash flows to its market price. It interpolates the DI rates to match
|
|
337
|
+
the bond's cash flow payment dates and uses the Brent method to find the spread
|
|
338
|
+
(in bps) that zeroes the difference between the bond's market price and its
|
|
339
|
+
discounted cash flows.
|
|
340
|
+
|
|
341
|
+
Parameters:
|
|
342
|
+
----------
|
|
343
|
+
settlement_date : pd.Timestamp
|
|
344
|
+
The date on which the bond is settled.
|
|
345
|
+
maturity_date : pd.Timestamp
|
|
346
|
+
The date on which the bond matures.
|
|
347
|
+
ytm : float
|
|
348
|
+
The yield to maturity of the bond.
|
|
349
|
+
di_rates : list[float]
|
|
350
|
+
A list of DI rates corresponding to the DI expirations.
|
|
351
|
+
di_expirations : list[pd.Timestamp]
|
|
352
|
+
A list of DI expiration dates.
|
|
331
353
|
|
|
332
|
-
|
|
333
|
-
|
|
354
|
+
Returns:
|
|
355
|
+
-------
|
|
356
|
+
float
|
|
357
|
+
The net DI spread in basis points. Returns NaN if a solution cannot be found.
|
|
358
|
+
"""
|
|
359
|
+
|
|
360
|
+
# Create an interpolator for the DI rates using the flat-forward method
|
|
361
|
+
settlement_date = dc.convert_date(settlement_date)
|
|
362
|
+
maturity_date = dc.convert_date(maturity_date)
|
|
334
363
|
|
|
335
364
|
ff_interpolator = Interpolator(
|
|
336
365
|
"flat_forward",
|
|
337
|
-
bday.count(settlement_date,
|
|
338
|
-
|
|
366
|
+
bday.count(settlement_date, di_expirations),
|
|
367
|
+
di_rates,
|
|
339
368
|
)
|
|
340
369
|
|
|
341
|
-
#
|
|
342
|
-
|
|
370
|
+
# Ensure the DI rates and expirations lists are of equal length
|
|
371
|
+
if len(di_rates) != len(di_expirations):
|
|
372
|
+
raise ValueError("di_rates and di_expirations must have the same length.")
|
|
343
373
|
|
|
374
|
+
# Calculate cash flows and business days between settlement and payment dates
|
|
344
375
|
df = cash_flows(settlement_date, maturity_date).reset_index()
|
|
345
376
|
df["BDays"] = bday.count(settlement_date, df["PaymentDate"])
|
|
346
377
|
|
|
378
|
+
# Calculate business years (252 business days per year)
|
|
347
379
|
byears = bday.count(settlement_date, df["PaymentDate"]) / 252
|
|
348
|
-
|
|
380
|
+
di_interp = df["BDays"].apply(ff_interpolator)
|
|
349
381
|
bond_price = price(settlement_date, maturity_date, ytm)
|
|
350
382
|
bond_cash_flows = df["CashFlow"]
|
|
351
383
|
|
|
352
384
|
def price_difference(p):
|
|
353
|
-
|
|
385
|
+
# Calculate the difference between the bond's price and its disc. cash flows
|
|
386
|
+
return (bond_cash_flows / (1 + di_interp + p) ** byears).sum() - bond_price
|
|
354
387
|
|
|
355
388
|
try:
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
389
|
+
if initial_guess:
|
|
390
|
+
# Search interval is 50 bps above and below the initial guess
|
|
391
|
+
a = initial_guess - 50 / 10_000 # 50 bps below the initial guess
|
|
392
|
+
b = initial_guess + 50 / 10_000 # 50 bps above the initial guess
|
|
393
|
+
else:
|
|
394
|
+
# Search interval is from -0.01 to 0.01 (i.e., -100 to 100 bps)
|
|
395
|
+
a = -0.01
|
|
396
|
+
b = 0.01
|
|
397
|
+
|
|
398
|
+
# Find the spread (p) that zeroes the price difference
|
|
399
|
+
p_solution = brentq(price_difference, a, b, maxiter=100)
|
|
400
|
+
# Convert the solution to basis points (bps) and round to two decimal places
|
|
401
|
+
p_solution = round((p_solution * 10_000), 2)
|
|
359
402
|
except (ValueError, RuntimeError):
|
|
360
|
-
#
|
|
403
|
+
# If no solution is found, return NaN
|
|
361
404
|
p_solution = float("nan")
|
|
362
405
|
|
|
363
|
-
return p_solution
|
|
406
|
+
return p_solution
|
|
@@ -44,7 +44,7 @@ class DIData:
|
|
|
44
44
|
adjust_exp_date: bool = False,
|
|
45
45
|
) -> pd.DataFrame:
|
|
46
46
|
cls._check_for_updates()
|
|
47
|
-
df = cls._df.copy()
|
|
47
|
+
df = cls._df[["TradeDate", "ExpirationDate", "SettlementRate"]].copy()
|
|
48
48
|
|
|
49
49
|
if trade_date:
|
|
50
50
|
trade_date = dc.convert_date(trade_date)
|
|
@@ -56,8 +56,6 @@ class DIData:
|
|
|
56
56
|
expiration_date = bday.offset(expiration_date, 0)
|
|
57
57
|
df.query("ExpirationDate == @expiration_date", inplace=True)
|
|
58
58
|
|
|
59
|
-
df = df[["TradeDate", "ExpirationDate", "SettlementRate"]].copy()
|
|
60
|
-
|
|
61
59
|
if adjust_exp_date:
|
|
62
60
|
df["ExpirationDate"] = (
|
|
63
61
|
df["ExpirationDate"].dt.to_period("M").dt.to_timestamp()
|
|
@@ -34,7 +34,7 @@ dependencies = [
|
|
|
34
34
|
"pyarrow",
|
|
35
35
|
]
|
|
36
36
|
dynamic = []
|
|
37
|
-
version = "0.12.
|
|
37
|
+
version = "0.12.2"
|
|
38
38
|
|
|
39
39
|
[project.license]
|
|
40
40
|
file = "LICENSE"
|
|
@@ -80,4 +80,4 @@ select = [
|
|
|
80
80
|
|
|
81
81
|
[tool.ruff.format]
|
|
82
82
|
docstring-code-format = true
|
|
83
|
-
docstring-code-line-length =
|
|
83
|
+
docstring-code-line-length = 88
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.12.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|