HKUDS/Vibe-Trading · error · ValueError

coupon_frequency cannot be negative, got {self.coupon_freque

Error message

coupon_frequency cannot be negative, got {self.coupon_frequency!r}

What it means

Bond.__post_init__ coerces coupon_frequency with int() and rejects negative values. Frequency is coupons per year (e.g. 2 for semi-annual); 0 is a valid sentinel meaning zero-coupon, but negative counts are invalid.

Source

Thrown at agent/src/entities/models.py:377

        if self.face_value is not None:
            face = float(self.face_value)
            if face <= 0:
                raise ValueError(f"face_value must be positive, got {self.face_value!r}")
            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

  1. Pass a non-negative integer frequency (0 for zero-coupon, 1 annual, 2 semi-annual, 4 quarterly)
  2. Use None or a proper optional field for unknown frequency rather than -1
  3. Validate the frequency column at ingest against {0,1,2,12,...}

Example fix

# before
Bond(instrument_id='b1', coupon_rate=0.05, coupon_frequency=-1)

# after
Bond(instrument_id='b1', coupon_rate=0.05, coupon_frequency=2)
Defensive patterns

Strategy: validation

Validate before calling

freq = int(row['coupon_frequency'])
if freq < 0:
    raise ValueError(f'negative coupon_frequency {freq} on row {row_id}')
Bond(..., coupon_frequency=freq)

Type guard

def is_valid_frequency(f) -> bool:
    return f is None or int(f) >= 0

Prevention

When it happens

Trigger: Bond(..., coupon_frequency=-1) or -2, or a negative value arising from arithmetic (e.g. subtracting a default frequency). Floats like 2.0 are int()-truncated to 2 and accepted.

Common situations: Misparsed spreadsheet columns with minus signs; intermediate calculations that compute frequency as a difference; sentinel values like -1 for 'unknown' leaking into the field.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/fef2e172191f7fbe. Report an issue: GitHub.