{"record":{"id":"bf28b65d7974c9b3","repo":"HKUDS/Vibe-Trading","slug":"csi300-no-symbol-survived-corporate-action-adjust","errorCode":null,"errorMessage":"csi300: no symbol survived corporate-action adjustment — pro.adj_factor returned nothing usable for any of the {len(codes)} names, which usually means the Tushare token lacks adj_factor permission. Benching on unadjusted prices is not an alternative: an ex-date injects a fabricated cross-sectional return, measured at -47.2% on 300750.SZ 2023-04-26.","messagePattern":"csi300: no symbol survived corporate-action adjustment — pro\\.adj_factor returned nothing usable for any of the (.+?) names, which usually means the Tushare token lacks adj_factor permission\\. Benching on unadjusted prices is not an alternative: an ex-date injects a fabricated cross-sectional return, measured at -47\\.2% on 300750\\.SZ 2023-04-26\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"agent/src/tools/alpha_bench_tool.py","lineNumber":410,"sourceCode":"        return code, _apply_qfq(df, factor)\n\n    fetched: dict[str, pd.DataFrame] = {}\n    with ThreadPoolExecutor(max_workers=_CSI300_FETCH_WORKERS) as pool:\n        futures = [pool.submit(_fetch_one, code) for code in codes]\n        for fut in as_completed(futures):\n            try:\n                code, frame = fut.result()\n            except Exception as exc:  # noqa: BLE001 — _retry already logged\n                logger.warning(\"csi300 fetch worker raised: %s\", exc)\n                continue\n            if frame is not None and not frame.empty:\n                fetched[code] = frame\n\n    # A name with no usable adjustment factors is dropped rather than benched on\n    # raw prices, so the drop has to be visible or it becomes its own silent bias.\n    dropped = sorted(set(codes) - set(fetched))\n    if not fetched:\n        raise RuntimeError(\n            \"csi300: no symbol survived corporate-action adjustment — \"\n            \"pro.adj_factor returned nothing usable for any of the \"\n            f\"{len(codes)} names, which usually means the Tushare token lacks \"\n            \"adj_factor permission. Benching on unadjusted prices is not an \"\n            \"alternative: an ex-date injects a fabricated cross-sectional \"\n            \"return, measured at -47.2% on 300750.SZ 2023-04-26.\"\n        )\n    if dropped:\n        logger.warning(\n            \"csi300: dropped %d/%d name(s) with no usable adjustment factors: %s\",\n            len(dropped),\n            len(codes),\n            \", \".join(dropped[:10]) + (\"...\" if len(dropped) > 10 else \"\"),\n        )\n\n    panel = _wide_from_fetched(fetched, include_amount=True)\n    # CN equity vwap: Tushare ``amount`` is in 千元, ``volume`` in 手. True VWAP\n    # = (amount * 1000 CNY) / (volume * 100 shares). Matches","sourceCodeStart":392,"sourceCodeEnd":428,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/tools/alpha_bench_tool.py#L392-L428","documentation":"Every csi300 name whose pro.adj_factor call yielded nothing usable is dropped rather than benched on raw prices (an ex-date would inject a fabricated cross-sectional return, measured at -47.2% on 300750.SZ 2023-04-26). If NO symbol survives, this RuntimeError names the most common cause: the Tushare token lacks adj_factor permission.","triggerScenarios":"Calling csi300 loading with a token tier that cannot call pro.adj_factor; a network condition where all per-symbol adj_factor fetches fail; API quota exhausted across all requests.","commonSituations":"Free/low-point Tushare accounts without adj_factor access; rate-limit exhaustion (Tushare points-based limits); intermittent network dropping every fetch.","solutions":["Upgrade the Tushare account/points so adj_factor is permitted, then retry","If failures are rate-limit related, add backoff between per-symbol calls or reduce the universe window and retry","Check dropped symbols logging — partial drops are visible; only total loss raises","Never work around by benching unadjusted prices; the bias is documented and large"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"# preflight: token can fetch adj_factor for one symbol\nprobe = pro.adj_factor(ts_code='000001.SZ', start_date=sd, end_date=ed)\nassert probe is not None and not probe.empty","typeGuard":null,"tryCatchPattern":"try:\n    panel = _load_csi300_panel(s, e)\nexcept RuntimeError as e:\n    if 'adj_factor permission' in str(e):\n        notify_user_to_upgrade_tushare_points()","preventionTips":["Verify adj_factor access with a one-symbol probe before full runs","Rate-limit per-symbol fetches to avoid quota exhaustion masking as permission errors"],"tags":["tushare","permissions","data-quality","corporate-actions"],"backgroundTag":"api-permission-denied","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}