{"record":{"id":"3b5fa884f720f1af","repo":"HKUDS/Vibe-Trading","slug":"n-groups-must-be-1-got-n-groups","errorCode":null,"errorMessage":"n_groups must be >= 1, got {n_groups}","messagePattern":"n_groups must be >= 1, got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/factors/factor_analysis_core.py","lineNumber":65,"sourceCode":"    return ic.astype(float)\n\n\ndef compute_group_equity(\n    factor_df: pd.DataFrame, return_df: pd.DataFrame, n_groups: int\n) -> pd.DataFrame:\n    \"\"\"Layered backtest: rank by factor value daily, hold equal-weight, compute cumulative NAV.\n\n    Args:\n        factor_df: Factor values; index=date, columns=codes.\n        return_df: Returns; index=date, columns=codes.\n        n_groups: Number of quantile groups.\n\n    Returns:\n        DataFrame with index=date and columns Group_1 ... Group_N holding cumulative NAV.\n    \"\"\"\n    if n_groups < 1:\n        # qcut/cut reject non-positive bins; range(n_groups) is also empty for <=0\n        raise ValueError(f\"n_groups must be >= 1, got {n_groups}\")\n\n    common_dates = sorted(factor_df.index.intersection(return_df.index))\n    common_codes = factor_df.columns.intersection(return_df.columns)\n    if len(common_dates) == 0 or len(common_codes) == 0:\n        return pd.DataFrame()\n\n    factor_df = factor_df.loc[common_dates, common_codes]\n    return_df = return_df.loc[common_dates, common_codes]\n\n    group_returns: dict[str, list[float]] = {f\"Group_{i+1}\": [] for i in range(n_groups)}\n    valid_dates = []\n\n    for date in common_dates:\n        f = factor_df.loc[date].dropna()\n        r = return_df.loc[date].dropna()\n        shared = f.index.intersection(r.index)\n        if len(shared) < n_groups:\n            continue","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/factors/factor_analysis_core.py#L47-L83","documentation":"compute_group_equity builds N quantile group NAV curves using qcut/cut, which reject non-positive bin counts; range(n_groups) would also be empty. n_groups < 1 is therefore rejected up front with ValueError.","triggerScenarios":"Calling compute_group_equity(factor, ret, n_groups=0) or a negative value, or run_factor_analysis with a bad groups config.","commonSituations":"Config with groups: 0 meaning 'no grouping', computed group counts that hit 0, or a UI slider defaulting to 0 before the user sets it.","solutions":["Use n_groups >= 1 (typical values 5 or 10)","If 'no grouping' is desired, skip group equity computation entirely rather than passing 0","Validate the config value before running analysis"],"exampleFix":"# before\ncompute_group_equity(f, r, n_groups=0)\n# after\ncompute_group_equity(f, r, n_groups=5)","handlingStrategy":"validation","validationCode":"if not isinstance(n_groups, int) or n_groups < 1: raise ValueError(f'n_groups must be >= 1, got {n_groups!r}')","typeGuard":"def is_valid_n_groups(v: object) -> bool:\n    return isinstance(v, int) and not isinstance(v, bool) and v >= 1","tryCatchPattern":null,"preventionTips":["Validate analysis config before running","Treat groups=0 as 'skip grouping', not a parameter value"],"tags":["quantile","validation","factor-analysis"],"backgroundTag":"invalid-parameter-value","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}