virattt/ai-hedge-fund · error · ValueError

unknown rebalance cadence {cadence!r}

Error message

unknown rebalance cadence {cadence!r}

What it means

Raised by rebalance_grid() in hedge_fund/backtesting/fund.py:141 when the cadence string is anything other than 'daily', 'weekly', or 'monthly'. The function picks rebalance dates off a sorted list of trading days and only knows those three cadences; an unrecognized value means the mandate YAML contains a typo or an unsupported rebalance frequency.

Source

Thrown at hedge_fund/backtesting/fund.py:141

        dates=grid,
        nav=nav,
        benchmark_nav=benchmark_nav,
        metrics=_metrics(spec.capital, grid, nav, benchmark_nav,
                         spec.rebalance, records),
        records=records,
    )


def rebalance_grid(days: list[str], cadence: str) -> list[str]:
    """Pick the rebalance dates out of sorted trading *days* (YYYY-MM-DD).

    daily: every day. weekly: the last trading day of each ISO week.
    monthly: the last trading day of each calendar month.
    """
    if cadence == "daily":
        return list(days)
    if cadence not in ("weekly", "monthly"):
        raise ValueError(f"unknown rebalance cadence {cadence!r}")

    last_of_period: dict[tuple[int, int], str] = {}
    for day in days:
        d = _date.fromisoformat(day)
        if cadence == "weekly":
            iso = d.isocalendar()
            key = (iso[0], iso[1])
        else:
            key = (d.year, d.month)
        last_of_period[key] = day  # days are sorted — the last write wins
    return sorted(last_of_period.values())


# ---------------------------------------------------------------------------
# Private helpers
# ---------------------------------------------------------------------------

def _metrics(

View on GitHub (pinned to eff8a7320f)

Solutions

  1. Set rebalance to one of the exact lowercase strings: 'daily', 'weekly', or 'monthly' in the mandate YAML.
  2. If you control the loading path, normalize the value before it reaches the engine: spec.rebalance = spec.rebalance.strip().lower() (or better, add a field_validator on FundSpec.rebalance so it fails at load time with the YAML path in hand).
  3. For genuinely unsupported cadences (quarterly), implement them in rebalance_grid (e.g. key on (d.year, (d.month-1)//3)) or file a feature request instead of passing an unknown string.

Example fix

# before
# mandate.yaml
rebalance: Quarterly   # raises: unknown rebalance cadence 'Quarterly'

# after
# mandate.yaml
rebalance: monthly

# or normalize at load time (spec.py)
@field_validator("rebalance")
@classmethod
def _lower_rebalance(cls, v: str) -> str:
    v = v.strip().lower()
    if v not in ("daily", "weekly", "monthly"):
        raise ValueError(f"rebalance must be daily|weekly|monthly, got {v!r}")
    return v
Defensive patterns

Strategy: validation

Validate before calling

VALID_CADENCES = {"daily", "weekly", "monthly"}

def check_cadence(spec) -> None:
    if spec.rebalance not in VALID_CADENCES:
        raise SystemExit(
            f"mandate rebalance={spec.rebalance!r} invalid; "
            f"use one of {sorted(VALID_CADENCES)}"
        )

Type guard

from typing import TypedDict

def is_valid_cadence(c: str) -> bool:
    return isinstance(c, str) and c in {"daily", "weekly", "monthly"}

Prevention

When it happens

Trigger: Calling rebalance_grid(days, cadence) with a value like 'Weekly' (capitalized), 'quarterly', 'bi-weekly', 'none', or None. In practice this comes from a FundSpec whose rebalance field was hand-edited in the YAML mandate, or from passing spec.rebalance through after loading an old mandate written against a newer schema.

Common situations: Capitalization mismatch ('Monthly' vs 'monthly'); a user asking for quarterly rebalancing that the engine doesn't support; a YAML auto-formatter quoting the value differently; upgrading a config that used an older cadence vocabulary.

Related errors


AI-assisted analysis of virattt/ai-hedge-fund@eff8a7320f (2026-08-15). Data as JSON: /api/errors/8b71badb99722e23. Report an issue: GitHub.