{"record":{"id":"8b71badb99722e23","repo":"virattt/ai-hedge-fund","slug":"unknown-rebalance-cadence-cadence-r","errorCode":null,"errorMessage":"unknown rebalance cadence {cadence!r}","messagePattern":"unknown rebalance cadence (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"hedge_fund/backtesting/fund.py","lineNumber":141,"sourceCode":"        dates=grid,\n        nav=nav,\n        benchmark_nav=benchmark_nav,\n        metrics=_metrics(spec.capital, grid, nav, benchmark_nav,\n                         spec.rebalance, records),\n        records=records,\n    )\n\n\ndef rebalance_grid(days: list[str], cadence: str) -> list[str]:\n    \"\"\"Pick the rebalance dates out of sorted trading *days* (YYYY-MM-DD).\n\n    daily: every day. weekly: the last trading day of each ISO week.\n    monthly: the last trading day of each calendar month.\n    \"\"\"\n    if cadence == \"daily\":\n        return list(days)\n    if cadence not in (\"weekly\", \"monthly\"):\n        raise ValueError(f\"unknown rebalance cadence {cadence!r}\")\n\n    last_of_period: dict[tuple[int, int], str] = {}\n    for day in days:\n        d = _date.fromisoformat(day)\n        if cadence == \"weekly\":\n            iso = d.isocalendar()\n            key = (iso[0], iso[1])\n        else:\n            key = (d.year, d.month)\n        last_of_period[key] = day  # days are sorted — the last write wins\n    return sorted(last_of_period.values())\n\n\n# ---------------------------------------------------------------------------\n# Private helpers\n# ---------------------------------------------------------------------------\n\ndef _metrics(","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/virattt/ai-hedge-fund/blob/eff8a7320fcf0b473b135690fa1a5b0d9b022a83/hedge_fund/backtesting/fund.py#L123-L159","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\n# mandate.yaml\nrebalance: Quarterly   # raises: unknown rebalance cadence 'Quarterly'\n\n# after\n# mandate.yaml\nrebalance: monthly\n\n# or normalize at load time (spec.py)\n@field_validator(\"rebalance\")\n@classmethod\ndef _lower_rebalance(cls, v: str) -> str:\n    v = v.strip().lower()\n    if v not in (\"daily\", \"weekly\", \"monthly\"):\n        raise ValueError(f\"rebalance must be daily|weekly|monthly, got {v!r}\")\n    return v","handlingStrategy":"validation","validationCode":"VALID_CADENCES = {\"daily\", \"weekly\", \"monthly\"}\n\ndef check_cadence(spec) -> None:\n    if spec.rebalance not in VALID_CADENCES:\n        raise SystemExit(\n            f\"mandate rebalance={spec.rebalance!r} invalid; \"\n            f\"use one of {sorted(VALID_CADENCES)}\"\n        )","typeGuard":"from typing import TypedDict\n\ndef is_valid_cadence(c: str) -> bool:\n    return isinstance(c, str) and c in {\"daily\", \"weekly\", \"monthly\"}","tryCatchPattern":null,"preventionTips":["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."],"tags":["backtesting","config","validation","rebalance"],"backgroundTag":null,"analyzedSha":"eff8a7320fcf0b473b135690fa1a5b0d9b022a83","analyzedAt":"2026-08-15T00:22:46.567Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}