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
- Set rebalance to one of the exact lowercase strings: 'daily', 'weekly', or 'monthly' in the mandate YAML.
- 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).
- 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
- Add a field_validator on FundSpec.rebalance that lowercases and whitelists, so bad values die at YAML load time with the file context.
- Document the three accepted values next to every rebalance example in the mandate template.
- Assert cadence validity in tests that load shipped mandate YAMLs so config drift is caught in CI.
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
- duplicate strategy names: {sorted(duplicates)}
- unknown model {m.name!r} in strategy {strategy.name!r}; avai
- {spec.name}: no {spec.benchmark} bars in [{start}, {end}] —
- universe is empty — a run needs at least one ticker
- No v2 client for {provider} (model {model}). Supported: {',
AI-assisted analysis of virattt/ai-hedge-fund@eff8a7320f (2026-08-15).
Data as JSON: /api/errors/8b71badb99722e23.
Report an issue: GitHub.