{"record":{"id":"5c7cfd3d52af9cb6","repo":"HKUDS/Vibe-Trading","slug":"no-factor-could-be-built-characteristics-carries","errorCode":null,"errorMessage":"no factor could be built; characteristics carries none of the columns any definition needs: {sorted(characteristics.columns)}","messagePattern":"no factor could be built; characteristics carries none of the columns any definition needs: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/quantlib/factormodel.py","lineNumber":370,"sourceCode":"            try:\n                standardised = standardise_exposures(\n                    raw, market_caps=market_caps, winsorise=winsorise\n                )\n            except ValueError:\n                # A single unusable characteristic must not take the whole factor\n                # down when the factor has other inputs.\n                continue\n            parts.append(standardised * sign)\n\n        if not parts:\n            continue\n\n        combined = pd.concat(parts, axis=1).mean(axis=1)\n        filled[factor] = int(combined.isna().sum())\n        columns[factor] = combined.fillna(0.0)\n\n    if not columns:\n        raise ValueError(\n            \"no factor could be built; characteristics carries none of the \"\n            f\"columns any definition needs: {sorted(characteristics.columns)}\"\n        )\n    return pd.DataFrame(columns), filled\n\n\ndef cross_sectional_factor_returns(\n    returns: pd.Series,\n    exposures: pd.DataFrame,\n    market_caps: pd.Series | None = None,\n    date: object = None,\n) -> FactorReturnFit:\n    \"\"\"Regress one date's asset returns on their exposures.\n\n    The coefficients are that date's factor returns. Weighting is by square-root\n    market cap when caps are supplied, which is the standard choice: it respects\n    that small-cap residuals are noisier without letting megacaps set the fit.\n","sourceCodeStart":352,"sourceCodeEnd":388,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/quantlib/factormodel.py#L352-L388","documentation":"Each factor definition maps a factor name to the characteristic columns it needs; build_style_exposures raises this when none of the supplied columns match any definition's inputs, so no factor at all could be built. The message lists the frame's columns to aid diagnosis.","triggerScenarios":"Passing a characteristics frame whose column names (e.g. 'btm', 'pe') match none of the definition keys (e.g. 'book_to_price', 'earnings_yield') — renames, aliases, or a different naming convention.","commonSituations":"Column renames between pipeline versions, vendor column names vs library-internal names, or passing the wrong frame (returns instead of characteristics).","solutions":["Compare sorted(characteristics.columns) (printed in the message) against the keys used in your definitions dict.","Rename columns to the definition's expected names, or supply definitions keyed by the columns you actually have."],"exampleFix":"# before\nexposures, _ = build_style_exposures(characteristics, definitions)  # cols are 'btm'\n# after\ncharacteristics = characteristics.rename(columns={\"btm\": \"book_to_price\"})\nexposures, _ = build_style_exposures(characteristics, definitions)","handlingStrategy":"validation","validationCode":"needed = {c for recipe in definitions.values() for c in recipe}\nassert needed & set(characteristics.columns), sorted(characteristics.columns)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Centralise column-name mappings between vendor and library conventions.","Print definition keys next to frame columns during onboarding."],"tags":["factormodel","column-mismatch","dataframe"],"backgroundTag":"missing-column-mapping","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}