{"record":{"id":"5c597c2343876644","repo":"HKUDS/Vibe-Trading","slug":"style-drift-needs-at-least-2-dates-got-exposure","errorCode":null,"errorMessage":"style drift needs at least 2 dates, got {exposure_history.shape[0]}","messagePattern":"style drift needs at least 2 dates, got (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/quantlib/factormodel.py","lineNumber":542,"sourceCode":"\n\ndef style_drift(exposure_history: pd.DataFrame) -> StyleDrift:\n    \"\"\"Summarise how a portfolio's exposures moved over time.\n\n    Args:\n        exposure_history: Rows indexed by date in chronological order, one\n            column per factor, each cell a portfolio-level exposure from\n            :func:`portfolio_style_exposure`.\n\n    Returns:\n        A :class:`StyleDrift`.\n\n    Raises:\n        ValueError: If fewer than two dates are supplied -- drift is a change,\n            and one observation cannot express one.\n    \"\"\"\n    if exposure_history.shape[0] < 2:\n        raise ValueError(\n            f\"style drift needs at least 2 dates, got {exposure_history.shape[0]}\"\n        )\n\n    frame = exposure_history.drop(columns=[\"unmatched_weight\"], errors=\"ignore\")\n    return StyleDrift(\n        mean_exposure=frame.mean(),\n        std_exposure=frame.std(ddof=1),\n        first_exposure=frame.iloc[0],\n        last_exposure=frame.iloc[-1],\n        total_change=frame.iloc[-1] - frame.iloc[0],\n        max_abs_change=frame.diff().abs().max(),\n    )\n\n\ndef factor_return_attribution(\n    portfolio_exposures: pd.Series,\n    factor_returns: pd.Series,\n    portfolio_return: float,","sourceCodeStart":524,"sourceCodeEnd":560,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/quantlib/factormodel.py#L524-L560","documentation":"style_drift measures change in exposures over time and needs a time series; with fewer than 2 rows in exposure_history there is no possible delta, so it raises.","triggerScenarios":"Calling style_drift with a one-row (or zero-row) history DataFrame, e.g. style_drift(exposure_history.iloc[[-1]]).","commonSituations":"Backfill produced only one rebalance date; date filtering (.loc[date:]) sliced history to a single point; new portfolio with one day of history.","solutions":["Check exposure_history.shape[0] >= 2 before calling","Widen the date window used to build the history","If only one date exists, report zero drift instead of calling the API"],"exampleFix":"// before\ndrift = style_drift(hist)\n// after\ndrift = style_drift(hist) if len(hist) >= 2 else None","handlingStrategy":"validation","validationCode":"assert exposure_history.shape[0] >= 2, 'need >= 2 dates for drift'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Check history length after any date slicing","Report zero drift explicitly when only one rebalance exists"],"tags":["quantlib","factormodel","time-series","validation"],"backgroundTag":"insufficient-data-validation","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}