HKUDS/Vibe-Trading · error · ValueError
coupon_frequency=0 marks a zero-coupon bond, but coupon_rate
Error message
coupon_frequency=0 marks a zero-coupon bond, but coupon_rate={self.coupon_rate!r} is non-zero What it means
Bond.__post_init__ enforces consistency: coupon_frequency=0 marks a zero-coupon bond, so a non-zero coupon_rate alongside frequency 0 is contradictory and rejected. A truthy coupon_rate with frequency 0 triggers the error.
Source
Thrown at agent/src/entities/models.py:381
object.__setattr__(self, "face_value", face)
if self.coupon_rate is not None:
rate = float(self.coupon_rate)
if rate < 0:
raise ValueError(f"coupon_rate cannot be negative, got {rate!r}")
if rate > 1.0:
raise ValueError(
f"coupon_rate must be a decimal fraction (0.05 means 5%), "
f"got {rate!r}; a value above 1.0 is almost certainly a "
"percentage"
)
object.__setattr__(self, "coupon_rate", rate)
frequency = int(self.coupon_frequency)
if frequency < 0:
raise ValueError(
f"coupon_frequency cannot be negative, got {self.coupon_frequency!r}"
)
if self.coupon_rate and frequency == 0:
raise ValueError(
f"coupon_frequency=0 marks a zero-coupon bond, but coupon_rate="
f"{self.coupon_rate!r} is non-zero"
)
object.__setattr__(self, "coupon_frequency", frequency)
if self.maturity_date is not None:
object.__setattr__(
self,
"maturity_date",
normalize_date(self.maturity_date, field_name="maturity_date"),
)
if self.inception_date is not None and self.maturity_date < self.inception_date:
raise ValueError(
f"maturity_date {self.maturity_date} precedes inception_date "
f"{self.inception_date}"
)
View on GitHub (pinned to 80ffdda44c)
Solutions
- Set coupon_frequency to the actual pay frequency (>=1) when coupon_rate is non-zero
- Or set coupon_rate=None/0.0 when the bond truly is zero-coupon
- Avoid defaults that pick frequency=0; make both fields explicit at construction
Example fix
# before Bond(instrument_id='b1', coupon_rate=0.05, coupon_frequency=0) # after Bond(instrument_id='b1', coupon_rate=0.05, coupon_frequency=2)
Defensive patterns
Strategy: validation
Validate before calling
cr = row.get('coupon_rate')
freq = int(row.get('coupon_frequency', 0) or 0)
if cr and freq == 0:
freq = 2 # or raise: inconsistent source data
Bond(..., coupon_rate=cr, coupon_frequency=freq) Type guard
def coupon_fields_consistent(rate, freq) -> bool:
return rate is None or not rate or int(freq) != 0 Prevention
- Set coupon_rate and coupon_frequency together, never via partial defaults
- Avoid constructor defaults of frequency=0 when coupon data may be supplied
When it happens
Trigger: Bond(..., coupon_rate=0.05, coupon_frequency=0) — e.g. a defaulted frequency of 0 combined with a real coupon from the data, or coupon_rate=0.0 with frequency 2 is fine but the inverse combination is not.
Common situations: Constructor defaults setting coupon_frequency=0 while caller supplies coupon_rate; partial updates where one field is refreshed and the other left at its zero-coupon default; merging records from sources with different conventions.
Related errors
- face_value must be positive, got {self.face_value!r}
- coupon_rate cannot be negative, got {rate!r}
- coupon_rate must be a decimal fraction (0.05 means 5%), got
- coupon_frequency cannot be negative, got {self.coupon_freque
- maturity_date {self.maturity_date} precedes inception_date {
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/2bf5e9e8ef6b414f.
Report an issue: GitHub.