Skip to content

fix(curves): align CDSCurve df and survival_prob vectorization and day count (#191) - #408

Merged
domokane merged 1 commit into
domokane:masterfrom
huuan26:fix/curve-day-count-inconsistency-191
Oct 19, 2026
Merged

domokane merged 1 commit into
domokane:masterfrom
huuan26:fix/curve-day-count-inconsistency-191

Conversation

@huuan26

@huuan26 huuan26 commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

Summary & Context

Fixes #191

In issue #191, an inconsistency was identified regarding how day count conventions are handled when computing discount factors from curves. While the core DiscountCurve.df(self, dt) was refactored in commit 310bab06 to consistently use self.curve_dc_type, CDSCurve in financepy/market/curves/cds_curve.py retained several day-count inconsistencies and broken vectorization:

  1. Day Count Inconsistency in CDSCurve.df(self, dt):
    When passed a Date, CDSCurve.df manually calculated t = (dt - self.anchor_dt) / G_DAYS_IN_YEAR (hardcoded ACT/365), completely bypassing self.libor_curve.curve_dc_type.
  2. Broken Vectorization on Date Lists:
    Both CDSCurve.df(self, dt) and CDSCurve.survival_prob(self, dt) advertise vectorization support in their docstrings. However, when passed a list[Date]:
    • CDSCurve.df ran t = np.array(dt), creating an object array of Date instances and passing it to libor_curve.df_t(t), which crashed with TypeError: float() argument must be a string or a real number, not 'Date'.
    • CDSCurve.survival_prob similarly passed an object array of Date instances to _uinterpolate, causing an AttributeError / TypeError.

Changes

  1. CDSCurve.df(self, dt):
    • Delegates directly to self.libor_curve.df(dt) when dt is a Date or list[Date]. This ensures the underlying discount curve's curve_dc_type is respected and returns vectorized results (np.ndarray) seamlessly.
    • Delegates to self.libor_curve.df_t when dt is numeric (float, int, or numeric np.ndarray).
  2. CDSCurve.survival_prob(self, dt):
    • Converts Date or list[Date] via times_from_dates(self.anchor_dt, dt, self.dc_type) into year fractions before calling _uinterpolate.
    • Properly handles scalar dates, date lists, floats, and numeric numpy arrays.
  3. CDSCurve.build_curve:
    • Uses times_from_dates(self.anchor_dt, maturity_dt, self.dc_type) for maturity conversion, ensuring consistency with survival_prob.
  4. tests/unit/test_FinCDSCurve.py:
    • Re-enabled previously commented-out test_fin_cds_curve() updated for the modern API (removed deprecated use_cache, updated cds.value return tuple).
    • Added explicit assertions verifying:
      • Scalar Date evaluations for df and survival_prob.
      • Vectorized list[Date] evaluations matching scalar calls.
      • Numeric float and array evaluations.
      • Day-count consistency when the underlying discount curve uses an alternative day-count convention (e.g. ACT_360).

Validation

  • Verified with pytest tests/unit/test_FinCDSCurve.py (passed).
  • Verified full test suite across the repository (pytest tests/unit/): 1366 passed, 0 failures, 0 errors.

…y count (domokane#191)

- Delegate CDSCurve.df directly to libor_curve.df (or df_t for float/array) to respect libor_curve.curve_dc_type and fix vectorization when passing a list of Dates.
- Update survival_prob to convert Date or list[Date] using times_from_dates with self.dc_type, preventing crashes on list of Dates.
- Update build_curve to use times_from_dates with self.dc_type for maturity date conversion.
- Re-enable test_fin_cds_curve in tests/unit/test_FinCDSCurve.py with updated API and add tests verifying scalar and vectorized df and survival_prob evaluations across different day-count conventions.
@domokane
domokane merged commit 0b1d286 into domokane:master Oct 19, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Inconsistency in Day Count in Index Curve?

2 participants