{"record":{"id":"247f11146a2236e7","repo":"HKUDS/Vibe-Trading","slug":"a-return-needs-an-opening-and-a-closing-valuation","errorCode":null,"errorMessage":"a return needs an opening and a closing valuation; got {len(raw_items)}","messagePattern":"a return needs an opening and a closing valuation; got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/quantlib/performance.py","lineNumber":321,"sourceCode":"        raw_items: list[tuple[object, object]] = list(valuations.items())\n    else:\n        raw_items = []\n        for index, item in enumerate(valuations):\n            if isinstance(item, (str, bytes)) or not isinstance(item, Sequence):\n                raise ValueError(\n                    f\"valuations[{index}] must be a (date, value) pair, got \"\n                    f\"{type(item).__name__}\"\n                )\n            pair = tuple(item)\n            if len(pair) != 2:\n                raise ValueError(\n                    f\"valuations[{index}] must have exactly two elements \"\n                    f\"(date, value), got {len(pair)}\"\n                )\n            raw_items.append((pair[0], pair[1]))\n\n    if len(raw_items) < 2:\n        raise ValueError(\n            \"a return needs an opening and a closing valuation; got \"\n            f\"{len(raw_items)}\"\n        )\n\n    resolved: list[tuple[date, float]] = []\n    for raw_date, raw_value in raw_items:\n        when = normalize_date(raw_date, field_name=\"valuation date\")\n        try:\n            value = float(raw_value)\n        except (TypeError, ValueError) as exc:\n            raise ValueError(\n                f\"valuation on {when} must be numeric, got {raw_value!r}\"\n            ) from exc\n        if not math.isfinite(value):\n            raise ValueError(\n                f\"valuation on {when} must be finite, got {raw_value!r}; a \"\n                \"missing mark must be fixed at the source, not carried as NaN\"\n            )","sourceCodeStart":303,"sourceCodeEnd":339,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/quantlib/performance.py#L303-L339","documentation":"Every return calculation needs at least a starting and an ending valuation. After normalisation, fewer than two usable (date, value) pairs means no period can be measured, so _normalize_valuations raises this error reporting how many items survived.","triggerScenarios":"Calling any of the three return functions with a single valuation, e.g. [('2024-12-31', 105.0)], or with an empty list/empty dict (the length check runs before date parsing, so even malformed single items count once parsed).","commonSituations":"Newly opened accounts with one mark; a date filter that accidentally trims the series to one point; passing the wrong variable (a single valuation instead of the series) after refactoring.","solutions":["Ensure at least two valuations spanning the period; for empty inputs, decide policy (raise is fine) and guard upstream.","Check len(valuations) >= 2 before calling, and log the count in ingestion pipelines.","For DataFrame input, confirm the date filter leaves >= 2 rows."],"exampleFix":"# before\ntwr = time_weighted_return(account.valuations[-1:])  # one mark\n\n# after\nmarks = account.valuations\nif len(marks) < 2:\n    return None  # or raise your own domain error\ntwr = time_weighted_return(marks)","handlingStrategy":"validation","validationCode":"if len(valuations) < 2:\n    return None  # or raise your own domain-specific error\n","typeGuard":"def has_open_and_close(v) -> bool:\n    return len(list(v)) >= 2","tryCatchPattern":"try:\n    r = time_weighted_return(valuations)\nexcept ValueError as e:\n    if 'opening and a closing valuation' in str(e):\n        return None  # period not measurable\n    raise","preventionTips":["Guard len(valuations) >= 2 before calling.","Check date filters leave >= 2 marks.","Decide an explicit policy for new accounts with one mark."],"tags":["performance","valuation","minimum-data","input-validation"],"backgroundTag":"insufficient-data-for-operation","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}