{"record":{"id":"5cdb0224a0f6aff0","repo":"HKUDS/Vibe-Trading","slug":"cash-flow-on-when-coincides-with-the-opening-val","errorCode":null,"errorMessage":"cash flow on {when} coincides with the opening valuation and flow_timing={FLOW_TIMING_END!r} places it inside the opening value, where it would be counted twice. Use flow_timing={FLOW_TIMING_START!r}, or start the valuations one period earlier.","messagePattern":"cash flow on (.+?) coincides with the opening valuation and flow_timing=(.+?) places it inside the opening value, where it would be counted twice\\. Use flow_timing=(.+?), or start the valuations one period earlier\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/quantlib/performance.py","lineNumber":489,"sourceCode":"    Returns:\n        One net flow per interval, so ``len(dates) - 1`` entries.\n\n    Raises:\n        ValueError: If a flow falls outside the valuation window. Dropping it\n            silently would move the client's money into the manager's return.\n    \"\"\"\n    first, last = dates[0], dates[-1]\n    buckets = [0.0] * (len(dates) - 1)\n    for when, amount in flows:\n        if when < first or when > last:\n            raise ValueError(\n                f\"cash flow on {when} lies outside the valuation window \"\n                f\"{first}..{last}; extend the valuations or trim the flows \"\n                \"rather than dropping the flow\"\n            )\n        if flow_timing == FLOW_TIMING_END:\n            if when == first:\n                raise ValueError(\n                    f\"cash flow on {when} coincides with the opening valuation \"\n                    f\"and flow_timing={FLOW_TIMING_END!r} places it inside the \"\n                    \"opening value, where it would be counted twice. Use \"\n                    f\"flow_timing={FLOW_TIMING_START!r}, or start the \"\n                    \"valuations one period earlier.\"\n                )\n            # First interval whose closing date is at or after the flow.\n            index = next(k for k in range(1, len(dates)) if dates[k] >= when) - 1\n        else:\n            if when == last:\n                raise ValueError(\n                    f\"cash flow on {when} coincides with the closing valuation \"\n                    f\"and flow_timing={FLOW_TIMING_START!r} places it after the \"\n                    \"window ends. Use flow_timing=\"\n                    f\"{FLOW_TIMING_END!r}, or extend the valuations.\"\n                )\n            # Last interval whose opening date is at or before the flow.\n            index = max(k for k in range(len(dates) - 1) if dates[k] <= when)","sourceCodeStart":471,"sourceCodeEnd":507,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/quantlib/performance.py#L471-L507","documentation":"With flow_timing=END, a flow is treated as arriving at the end of its sub-period, so a flow on the same date as the opening valuation would be baked into the opening value and counted again as a flow — double counting. The library refuses this combination instead of producing an inflated/deflated return.","triggerScenarios":"Calling time_weighted_return with flow_timing=FLOW_TIMING_END (the end-of-day convention) while an external flow's date equals the first valuation date.","commonSituations":"An account funded on the first reporting date (contribution and opening mark share a day); using the default flow timing with same-day deposit; daily marks where flows land exactly on mark dates.","solutions":["Pass flow_timing=FLOW_TIMING_START for same-day opening flows.","Start the valuations one period earlier so the opening mark predates the flow.","Alternatively, fold the same-day flow into the opening valuation and drop the flow record."],"exampleFix":"# before\ntime_weighted_return(valuations=marks, flows=flows, flow_timing=FLOW_TIMING_END)\n# flow lands on marks[0].date -> ValueError\n\n# after\nfrom quantlib.performance import FLOW_TIMING_START\ntime_weighted_return(valuations=marks, flows=flows, flow_timing=FLOW_TIMING_START)","handlingStrategy":"validation","validationCode":"if flow_timing == FLOW_TIMING_END:\n    assert all(f.date != marks[0][0] for f in selected_flows), 'flow on opening valuation date'","typeGuard":null,"tryCatchPattern":"try:\n    twr = time_weighted_return(marks, flows, flow_timing=FLOW_TIMING_END)\nexcept ValueError as e:\n    if 'coincides with the opening valuation' in str(e):\n        twr = time_weighted_return(marks, flows, flow_timing=FLOW_TIMING_START)\n    else:\n        raise","preventionTips":["Prefer FLOW_TIMING_START when contributions land on mark dates.","Pick one flow-timing convention per data source and document it.","Unit-test the same-day-open edge case in your reporting suite."],"tags":["quantlib","twr","flow-timing","double-counting"],"backgroundTag":"flow-timing-boundary-conflict","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}