PYield 0.25.2__tar.gz → 0.25.4__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.
Files changed (34) hide show
  1. {pyield-0.25.2 → pyield-0.25.4}/PKG-INFO +1 -1
  2. pyield-0.25.4/pyield/__about__.py +1 -0
  3. {pyield-0.25.2 → pyield-0.25.4}/pyield/bonds/ntnb.py +53 -44
  4. {pyield-0.25.2 → pyield-0.25.4}/pyield/bonds/ntnf.py +31 -30
  5. pyield-0.25.2/pyield/__about__.py +0 -1
  6. {pyield-0.25.2 → pyield-0.25.4}/.gitignore +0 -0
  7. {pyield-0.25.2 → pyield-0.25.4}/LICENSE +0 -0
  8. {pyield-0.25.2 → pyield-0.25.4}/README.md +0 -0
  9. {pyield-0.25.2 → pyield-0.25.4}/pyield/__init__.py +0 -0
  10. {pyield-0.25.2 → pyield-0.25.4}/pyield/anbima.py +0 -0
  11. {pyield-0.25.2 → pyield-0.25.4}/pyield/b3_futures/__init__.py +0 -0
  12. {pyield-0.25.2 → pyield-0.25.4}/pyield/b3_futures/common.py +0 -0
  13. {pyield-0.25.2 → pyield-0.25.4}/pyield/b3_futures/historical.py +0 -0
  14. {pyield-0.25.2 → pyield-0.25.4}/pyield/b3_futures/intraday.py +0 -0
  15. {pyield-0.25.2 → pyield-0.25.4}/pyield/b3_futures/xml.py +0 -0
  16. {pyield-0.25.2 → pyield-0.25.4}/pyield/bday.py +0 -0
  17. {pyield-0.25.2 → pyield-0.25.4}/pyield/bonds/__init__.py +0 -0
  18. {pyield-0.25.2 → pyield-0.25.4}/pyield/bonds/bond_tools.py +0 -0
  19. {pyield-0.25.2 → pyield-0.25.4}/pyield/bonds/lft.py +0 -0
  20. {pyield-0.25.2 → pyield-0.25.4}/pyield/bonds/ltn.py +0 -0
  21. {pyield-0.25.2 → pyield-0.25.4}/pyield/conftest.py +0 -0
  22. {pyield-0.25.2 → pyield-0.25.4}/pyield/data_cache.py +0 -0
  23. {pyield-0.25.2 → pyield-0.25.4}/pyield/date_converter.py +0 -0
  24. {pyield-0.25.2 → pyield-0.25.4}/pyield/di.py +0 -0
  25. {pyield-0.25.2 → pyield-0.25.4}/pyield/holidays/__init__.py +0 -0
  26. {pyield-0.25.2 → pyield-0.25.4}/pyield/holidays/br_holidays_new.txt +0 -0
  27. {pyield-0.25.2 → pyield-0.25.4}/pyield/holidays/br_holidays_old.txt +0 -0
  28. {pyield-0.25.2 → pyield-0.25.4}/pyield/holidays/brholidays.py +0 -0
  29. {pyield-0.25.2 → pyield-0.25.4}/pyield/indicators.py +0 -0
  30. {pyield-0.25.2 → pyield-0.25.4}/pyield/interpolator.py +0 -0
  31. {pyield-0.25.2 → pyield-0.25.4}/pyield/projections.py +0 -0
  32. {pyield-0.25.2 → pyield-0.25.4}/pyield/py.typed +0 -0
  33. {pyield-0.25.2 → pyield-0.25.4}/pyield/tools.py +0 -0
  34. {pyield-0.25.2 → pyield-0.25.4}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: PYield
3
- Version: 0.25.2
3
+ Version: 0.25.4
4
4
  Summary: A Python library for analysis of fixed income instruments in Brazil
5
5
  Project-URL: Source, https://github.com/crdcj/PYield
6
6
  Author-email: Carlos Carvalho <cr.cj@outlook.com>
@@ -0,0 +1 @@
1
+ __version__ = "0.25.4"
@@ -127,7 +127,7 @@ def maturities(reference_date: DateScalar) -> pd.Series:
127
127
  return s_maturities
128
128
 
129
129
 
130
- def _generate_coupon_dates_map(
130
+ def _generate_all_coupon_dates(
131
131
  start: DateScalar,
132
132
  end: DateScalar,
133
133
  ) -> pd.Series:
@@ -336,6 +336,7 @@ def spot_rates(
336
336
  settlement: DateScalar,
337
337
  maturities: pd.Series,
338
338
  rates: pd.Series,
339
+ show_coupons: bool = False,
339
340
  ) -> pd.DataFrame:
340
341
  """
341
342
  Calculate the spot rates for NTN-B bonds using the bootstrap method.
@@ -349,6 +350,8 @@ def spot_rates(
349
350
  settlement (DateScalar): The reference date for settlement.
350
351
  maturities (pd.Series): Series of maturity dates for the bonds.
351
352
  rates (pd.Series): Series of yield to maturity rates.
353
+ show_coupons (bool, optional): If True, the result will include the
354
+ intermediate coupon dates. Defaults to False.
352
355
 
353
356
  Returns:
354
357
  pd.DataFrame: DataFrame with columns "MaturityDate", "SpotRate".
@@ -363,21 +366,21 @@ def spot_rates(
363
366
  ... maturities=df_rates["MaturityDate"],
364
367
  ... rates=df_rates["IndicativeRate"],
365
368
  ... )
366
- MaturityDate SpotRate
367
- 0 2025-05-15 0.063894
368
- 1 2026-08-15 0.066141
369
- 2 2027-05-15 0.064087
370
- 3 2028-08-15 0.063057
371
- 4 2029-05-15 0.061458
372
- 5 2030-08-15 0.059491
373
- 6 2032-08-15 0.059652
374
- 7 2033-05-15 0.059497
375
- 8 2035-05-15 0.059151
376
- 9 2040-08-15 0.058326
377
- 10 2045-05-15 0.060371
378
- 11 2050-08-15 0.060772
379
- 12 2055-05-15 0.059909
380
- 13 2060-08-15 0.060652
369
+ MaturityDate BDToMat SpotRate
370
+ 0 2025-05-15 185 0.063894
371
+ 1 2026-08-15 502 0.066141
372
+ 2 2027-05-15 687 0.064087
373
+ 3 2028-08-15 1002 0.063057
374
+ 4 2029-05-15 1186 0.061458
375
+ 5 2030-08-15 1500 0.059491
376
+ 6 2032-08-15 2004 0.059652
377
+ 7 2033-05-15 2191 0.059497
378
+ 8 2035-05-15 2690 0.059151
379
+ 9 2040-08-15 4009 0.058326
380
+ 10 2045-05-15 5196 0.060371
381
+ 11 2050-08-15 6511 0.060772
382
+ 12 2055-05-15 7700 0.059909
383
+ 13 2060-08-15 9017 0.060652
381
384
 
382
385
  Notes:
383
386
  The calculation of the spot rates for NTN-B bonds considers the following steps:
@@ -387,6 +390,7 @@ def spot_rates(
387
390
  - Calculate the real spot rates for each maturity date.
388
391
  - Columns in the returned DataFrame:
389
392
  - MaturityDate: The maturity date of the bond.
393
+ - BDToMat: The number of business days from settlement to maturities.
390
394
  - SpotRate: The real spot rate for the bond.
391
395
  """
392
396
  # Process and validate the input data
@@ -394,7 +398,7 @@ def spot_rates(
394
398
  maturities = pd.to_datetime(maturities, errors="raise", dayfirst=True)
395
399
  _check_maturities(maturities)
396
400
 
397
- # Create the interpolator object
401
+ # Create the interpolator to calculate the YTM rates for intermediate dates
398
402
  ff_interpolator = ip.Interpolator(
399
403
  method="flat_forward",
400
404
  known_bdays=bday.count(settlement, maturities),
@@ -402,15 +406,15 @@ def spot_rates(
402
406
  )
403
407
 
404
408
  # Generate coupon dates up to the longest maturity date
405
- all_coupon_dates = _generate_coupon_dates_map(
409
+ all_coupon_dates = _generate_all_coupon_dates(
406
410
  start=settlement, end=maturities.max()
407
411
  )
408
412
 
409
413
  # Create a DataFrame with all coupon dates and the corresponding YTM
410
414
  df = pd.DataFrame(data=all_coupon_dates, columns=["MaturityDate"])
411
- df["BDays"] = bday.count(settlement, df["MaturityDate"])
412
- df["BYears"] = df["BDays"] / 252
413
- df["YTM"] = df["BDays"].apply(ff_interpolator)
415
+ df["BDToMat"] = bday.count(settlement, df["MaturityDate"])
416
+ df["BYears"] = df["BDToMat"] / 252
417
+ df["YTM"] = df["BDToMat"].apply(ff_interpolator)
414
418
  df["Coupon"] = COUPON_PMT
415
419
  df["SpotRate"] = np.nan
416
420
 
@@ -419,9 +423,9 @@ def spot_rates(
419
423
  # Get the cash flow dates for the bond
420
424
  cf_dates = payment_dates(settlement, row["MaturityDate"])
421
425
 
422
- # If there is only one coupon date and this date is the first maturity date
423
- # of an existing bond, the ytm rate is also a spot rate.
424
- if len(cf_dates) == 1 and cf_dates[0] == maturities[0]:
426
+ # If there is only one cash flow date, it means the bond is a single payment
427
+ # bond, so the spot rate is equal to the YTM rate
428
+ if len(cf_dates) == 1:
425
429
  df.at[index, "SpotRate"] = row["YTM"]
426
430
  continue
427
431
 
@@ -439,11 +443,14 @@ def spot_rates(
439
443
  price_factor = FINAL_PMT / (bond_price - cf_present_value)
440
444
  df.at[index, "SpotRate"] = price_factor ** (1 / row["BYears"]) - 1
441
445
 
442
- df = df[["MaturityDate", "SpotRate"]].copy()
446
+ df = df[["MaturityDate", "BDToMat", "SpotRate"]].copy()
443
447
  # Force Float64 type in float columns to standardize the output
444
448
  df["SpotRate"] = df["SpotRate"].astype("Float64")
445
- # Return the result without the intermediate coupon dates (virtual bonds)
446
- return df.query("MaturityDate in @maturities").reset_index(drop=True)
449
+
450
+ # Filter the result without the intermediate coupon dates (virtual bonds)
451
+ if not show_coupons:
452
+ df = df.query("MaturityDate in @maturities").reset_index(drop=True)
453
+ return df
447
454
 
448
455
 
449
456
  def bei_rates(
@@ -473,6 +480,7 @@ def bei_rates(
473
480
 
474
481
  Returned columns:
475
482
  - MaturityDate: The maturity date of the bonds.
483
+ - BDToMat: The number of business days from the settlement to the maturity.
476
484
  - RIR: The calculated Real Interest Rates based on the spot rates.
477
485
  - NIR: The Nominal Interest Rates interpolated for the maturity date.
478
486
  - BEI: The calculated Breakeven Inflation Rates.
@@ -500,21 +508,21 @@ def bei_rates(
500
508
  ... nominal_maturities=df_di["ExpirationDate"],
501
509
  ... nominal_rates=df_di["SettlementRate"],
502
510
  ... )
503
- MaturityDate RIR NIR BEI
504
- 0 2025-05-15 0.061749 0.113836 0.049058
505
- 1 2026-08-15 0.066133 0.117126 0.04783
506
- 2 2027-05-15 0.063816 0.117169 0.050152
507
- 3 2028-08-15 0.063635 0.11828 0.051376
508
- 4 2029-05-15 0.062532 0.11838 0.052561
509
- 5 2030-08-15 0.061809 0.118499 0.05339
510
- 6 2032-08-15 0.062135 0.118084 0.052676
511
- 7 2033-05-15 0.061897 0.11787 0.05271
512
- 8 2035-05-15 0.061711 0.117713 0.052747
513
- 9 2040-08-15 0.060468 0.11759 0.053865
514
- 10 2045-05-15 0.0625 0.11759 0.05185
515
- 11 2050-08-15 0.063016 0.11759 0.051339
516
- 12 2055-05-15 0.062252 0.11759 0.052095
517
- 13 2060-08-15 0.063001 0.11759 0.051354
511
+ MaturityDate BDToMat RIR NIR BEI
512
+ 0 2025-05-15 171 0.061749 0.113836 0.049058
513
+ 1 2026-08-15 488 0.066133 0.117126 0.04783
514
+ 2 2027-05-15 673 0.063816 0.117169 0.050152
515
+ 3 2028-08-15 988 0.063635 0.11828 0.051376
516
+ 4 2029-05-15 1172 0.062532 0.11838 0.052561
517
+ 5 2030-08-15 1486 0.061809 0.118499 0.05339
518
+ 6 2032-08-15 1990 0.062135 0.118084 0.052676
519
+ 7 2033-05-15 2177 0.061897 0.11787 0.05271
520
+ 8 2035-05-15 2676 0.061711 0.117713 0.052747
521
+ 9 2040-08-15 3995 0.060468 0.11759 0.053865
522
+ 10 2045-05-15 5182 0.0625 0.11759 0.05185
523
+ 11 2050-08-15 6497 0.063016 0.11759 0.051339
524
+ 12 2055-05-15 7686 0.062252 0.11759 0.052095
525
+ 13 2060-08-15 9003 0.063001 0.11759 0.051354
518
526
 
519
527
  """
520
528
  # Normalize input dates
@@ -523,7 +531,7 @@ def bei_rates(
523
531
 
524
532
  # Calculate Real Interest Rate (RIR)
525
533
  df = spot_rates(settlement, ntnb_maturities, ntnb_rates)
526
- df["BDays"] = bday.count(settlement, df["MaturityDate"])
534
+ df["BDToMat"] = bday.count(settlement, df["MaturityDate"])
527
535
  df = df.rename(columns={"SpotRate": "RIR"})
528
536
 
529
537
  nir_interplator = ip.Interpolator(
@@ -533,12 +541,13 @@ def bei_rates(
533
541
  extrapolate=True,
534
542
  )
535
543
 
536
- df["NIR"] = df["BDays"].apply(nir_interplator).astype("Float64")
544
+ df["NIR"] = df["BDToMat"].apply(nir_interplator).astype("Float64")
537
545
  # Calculate Breakeven Inflation Rate (BEI)
538
546
  df["BEI"] = ((df["NIR"] + 1) / (df["RIR"] + 1)) - 1
539
547
 
540
548
  cols_reordered = [
541
549
  "MaturityDate",
550
+ "BDToMat",
542
551
  "RIR",
543
552
  "NIR",
544
553
  "BEI",
@@ -239,7 +239,7 @@ def spot_rates( # noqa
239
239
  ltn_rates: pd.Series,
240
240
  ntnf_maturities: pd.Series,
241
241
  ntnf_rates: pd.Series,
242
- show_coupon_rates: bool = False,
242
+ show_coupons: bool = False,
243
243
  ) -> pd.DataFrame:
244
244
  """
245
245
  Calculate the spot rates (zero coupon rates) for NTN-F bonds using the bootstrap
@@ -259,11 +259,12 @@ def spot_rates( # noqa
259
259
  ltn_rates (pd.Series): The LTN known rates.
260
260
  ntnf_maturities (pd.Series): The NTN-F known maturities.
261
261
  ntnf_rates (pd.Series): The NTN-F known rates.
262
- show_coupon_rates (bool): If True, show also July rates corresponding to the
262
+ show_coupons (bool): If True, show also July rates corresponding to the
263
263
  coupon payments. Defaults to False.
264
264
 
265
265
  Returns:
266
- pd.DataFrame: DataFrame with columns "MaturityDate" and "SpotRate"
266
+ pd.DataFrame: DataFrame with columns "BDToMat", "MaturityDate" and "SpotRate".
267
+ "BDToMat" is the business days from the settlement date to the maturities.
267
268
 
268
269
  Examples:
269
270
 
@@ -276,14 +277,13 @@ def spot_rates( # noqa
276
277
  ... ntnf_maturities=df_ntnf["MaturityDate"],
277
278
  ... ntnf_rates=df_ntnf["IndicativeRate"],
278
279
  ... )
279
- MaturityDate SpotRate
280
- 0 2025-01-01 0.108837
281
- 1 2027-01-01 0.119981
282
- 2 2029-01-01 0.122113
283
- 3 2031-01-01 0.122231
284
- 4 2033-01-01 0.121355
285
- 5 2035-01-01 0.121398
286
-
280
+ MaturityDate BDToMat SpotRate
281
+ 0 2025-01-01 83 0.108837
282
+ 1 2027-01-01 584 0.119981
283
+ 2 2029-01-01 1083 0.122113
284
+ 3 2031-01-01 1584 0.122231
285
+ 4 2033-01-01 2088 0.121355
286
+ 5 2035-01-01 2587 0.121398
287
287
  """
288
288
  # Process and validate the input data
289
289
  settlement = dc.convert_input_dates(settlement)
@@ -305,16 +305,16 @@ def spot_rates( # noqa
305
305
 
306
306
  # Create a DataFrame with all coupon dates and the corresponding YTM
307
307
  df = pd.DataFrame(data=all_coupon_dates, columns=["MaturityDate"])
308
- df["BDays"] = bday.count(start=settlement, end=df["MaturityDate"])
309
- df["BYears"] = df["BDays"] / 252
308
+ df["BDToMat"] = bday.count(start=settlement, end=df["MaturityDate"])
309
+ df["BYears"] = df["BDToMat"] / 252
310
310
  df["Coupon"] = COUPON_PMT
311
- df["YTM"] = df["BDays"].apply(ntnf_rate_interpolator)
311
+ df["YTM"] = df["BDToMat"].apply(ntnf_rate_interpolator)
312
312
 
313
313
  # The Bootstrap loop to calculate spot rates
314
314
  for index, row in df.iterrows():
315
315
  if row["MaturityDate"] <= ltn_maturities.max():
316
316
  # Use LTN rates for maturities before the last LTN maturity date
317
- df.at[index, "SpotRate"] = ltn_rate_interpolator(row["BDays"])
317
+ df.at[index, "SpotRate"] = ltn_rate_interpolator(row["BDToMat"])
318
318
  continue
319
319
 
320
320
  # Calculate the present value of the coupon payments
@@ -323,19 +323,20 @@ def spot_rates( # noqa
323
323
  cf_present_value = bt.calculate_present_value(
324
324
  cash_flows=cf_df["Coupon"],
325
325
  rates=cf_df["SpotRate"],
326
- periods=cf_df["BDays"] / 252,
326
+ periods=cf_df["BDToMat"] / 252,
327
327
  )
328
328
 
329
329
  bond_price = price(settlement, row["MaturityDate"], row["YTM"])
330
330
  price_factor = FINAL_PMT / (bond_price - cf_present_value)
331
331
  df.at[index, "SpotRate"] = price_factor ** (1 / row["BYears"]) - 1
332
332
 
333
- df = df[["MaturityDate", "SpotRate"]].copy()
333
+ df = df[["MaturityDate", "BDToMat", "SpotRate"]].copy()
334
334
  df["SpotRate"] = df["SpotRate"].astype("Float64")
335
- if show_coupon_rates:
336
- return df
337
- else:
338
- return df.query("MaturityDate in @ntnf_maturities").reset_index(drop=True)
335
+
336
+ if not show_coupons:
337
+ df = df.query("MaturityDate in @ntnf_maturities").reset_index(drop=True)
338
+
339
+ return df
339
340
 
340
341
 
341
342
  def di_spreads(reference_date: DateScalar) -> pd.DataFrame:
@@ -485,10 +486,10 @@ def di_net_spread( # noqa
485
486
 
486
487
  # Calculate cash flows and business days between settlement and payment dates
487
488
  df = cash_flows(settlement, ntnf_maturity).reset_index()
488
- df["BDays"] = bday.count(settlement, df["PaymentDate"])
489
+ df["BDToMat"] = bday.count(settlement, df["PaymentDate"])
489
490
 
490
491
  byears = bday.count(settlement, df["PaymentDate"]) / 252
491
- di_interp = df["BDays"].apply(ff_interpolator)
492
+ di_interp = df["BDToMat"].apply(ff_interpolator)
492
493
  bond_price = price(settlement, ntnf_maturity, ntnf_rate)
493
494
  bond_cash_flows = df["CashFlow"]
494
495
 
@@ -551,8 +552,8 @@ def premium(
551
552
  settlement = dc.convert_input_dates(settlement)
552
553
 
553
554
  df = cash_flows(settlement, ntnf_maturity, adj_payment_dates=True)
554
- df["BDays"] = bday.count(settlement, df["PaymentDate"])
555
- df["BYears"] = df["BDays"] / 252
555
+ df["BDToMat"] = bday.count(settlement, df["PaymentDate"])
556
+ df["BYears"] = df["BDToMat"] / 252
556
557
 
557
558
  ff_interpolator = ip.Interpolator(
558
559
  "flat_forward",
@@ -560,13 +561,13 @@ def premium(
560
561
  di_rates,
561
562
  )
562
563
 
563
- df["DIRate"] = df["BDays"].apply(ff_interpolator)
564
+ df["DIRate"] = df["BDToMat"].apply(ff_interpolator)
564
565
 
565
566
  # Calculate the present value of the cash flows using the DI rate
566
567
  bond_price = bt.calculate_present_value(
567
568
  cash_flows=df["CashFlow"],
568
569
  rates=df["DIRate"],
569
- periods=df["BDays"] / 252,
570
+ periods=df["BDToMat"] / 252,
570
571
  )
571
572
 
572
573
  # Calculate the rate corresponding to this price
@@ -600,8 +601,8 @@ def historical_premium(
600
601
  ntnf_ytm = float(ntnf_ytms.iloc[0])
601
602
 
602
603
  df = cash_flows(reference_date, maturity, adj_payment_dates=True)
603
- df["BDays"] = bday.count(reference_date, df["PaymentDate"])
604
- df["BYears"] = df["BDays"] / 252
604
+ df["BDToMat"] = bday.count(reference_date, df["PaymentDate"])
605
+ df["BYears"] = df["BDToMat"] / 252
605
606
  df["ReferenceDate"] = reference_date
606
607
 
607
608
  dif = di.DIFutures() # Instantiate the DI Futures class
@@ -615,7 +616,7 @@ def historical_premium(
615
616
  bond_price = bt.calculate_present_value(
616
617
  cash_flows=df["CashFlow"],
617
618
  rates=df["DIRate"],
618
- periods=df["BDays"] / 252,
619
+ periods=df["BDToMat"] / 252,
619
620
  )
620
621
 
621
622
  # Calculate the rate corresponding to this price
@@ -1 +0,0 @@
1
- __version__ = "0.25.2"
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