{"record":{"id":"dc0a50c747a92a49","repo":"ZhuLinsen/daily_stock_analysis","slug":"daily-data-missing-missing-text-column","errorCode":null,"errorMessage":"daily data missing {missing_text} column","messagePattern":"daily data missing (.+?) column","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/services/alert_indicators.py","lineNumber":201,"sourceCode":") -> pd.DataFrame:\n    if df is None or getattr(df, \"empty\", True):\n        return pd.DataFrame()\n    if not isinstance(df, pd.DataFrame):\n        return pd.DataFrame()\n\n    output = pd.DataFrame(index=df.index.copy())\n    output[\"date\"] = _date_series(df)\n\n    missing = []\n    for canonical in required_columns:\n        source = _find_column(df, canonical)\n        if source is None:\n            missing.append(canonical)\n            continue\n        output[canonical] = pd.to_numeric(df[source], errors=\"coerce\")\n    if missing:\n        missing_text = \", \".join(missing)\n        raise ValueError(f\"daily data missing {missing_text} column\")\n\n    output = output.dropna(subset=list(required_columns)).copy()\n    if output.empty:\n        return output\n    output = _drop_partial_today(output, now=now)\n    if output.empty:\n        return output.reset_index(drop=True)\n    output = output.sort_values(by=\"date\", kind=\"stable\", na_position=\"first\").reset_index(drop=True)\n    return output\n\n\ndef _evaluate_ma(stock_code: str, params: Dict[str, Any], df: pd.DataFrame) -> IndicatorEvaluation:\n    window = int(params[\"window\"])\n    direction = str(params[\"direction\"])\n    series = df[\"close\"].rolling(window=window).mean()\n    latest = _latest_timestamp(df)\n    prev_close, curr_close = float(df[\"close\"].iloc[-2]), float(df[\"close\"].iloc[-1])\n    prev_ma, curr_ma = float(series.iloc[-2]), float(series.iloc[-1])","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/src/services/alert_indicators.py#L183-L219","documentation":"Raised in the daily-bar normalization helper of src/services/alert_indicators.py:201 when building the canonical OHLCV frame: for each required canonical column (open/high/low/close/volume style names), _find_column tries case-insensitive aliases in the source DataFrame, and any column with no resolvable alias is collected and reported, comma-joined, in this error. The evaluator refuses to compute indicators on frames missing required inputs.","triggerScenarios":"Evaluating a technical alert against a daily K-line DataFrame whose columns are abbreviated (e.g. only '开盘'/'收盘' Chinese names not in the alias map), renamed by a data-provider change (e.g. 'vol' removed in favor of 'volume' when the alias table only maps one), or a DataFrame of weekly/monthly bars with different column naming.","commonSituations":"A data provider in data_provider/ changes its column schema after an upgrade; a user feeds cached CSV data with hand-edited headers; a new market (HK/US) returns English-only headers missing an alias the A-share provider had.","solutions":["Rename the DataFrame columns to the canonical names (or a supported alias) before evaluation: df = df.rename(columns={'vol': 'volume'}).","If a provider changed its schema, update _find_column's alias map (or the provider adapter's standardization) to cover the new name.","Log df.columns.tolist() when the error fires to see exactly which alias is missing."],"exampleFix":"# before\ndf = pd.read_csv('bars.csv')  # columns: date, open, high, low, close, vol\neval = evaluate_alert(rule, df)\n\n# after\ndf = pd.read_csv('bars.csv').rename(columns={'vol': 'volume'})\neval = evaluate_alert(rule, df)","handlingStrategy":"validation","validationCode":"CANONICAL = {'open', 'high', 'low', 'close', 'volume'}\nmissing = CANONICAL - set(map(str.lower, df.columns))\nif missing:\n    df = df.rename(columns=ALIAS_MAP)  # or raise a clear upstream error\nif CANONICAL - set(map(str.lower, df.columns)):\n    raise ValueError(f'bar data lacks canonical columns: {missing}')","typeGuard":"def has_required_bar_columns(df) -> bool:\n    cols = {str(c).strip().lower() for c in df.columns}\n    return {'open','high','low','close','volume'} <= cols  # adjust to the canonical set in _find_column","tryCatchPattern":"try:\n    evaluation = evaluate_indicator(alert, df)\nexcept ValueError as e:\n    if 'daily data missing' in str(e):\n        logger.error('column mismatch: %s vs %s', df.columns.tolist(), e)\n        return skip_rule(alert, reason='bad_source_columns')\n    raise","preventionTips":["Standardize column names in the data-provider adapter, not at evaluation time.","Add alias-table unit tests whenever a provider's schema changes.","Log df.columns on any 'daily data missing' error so alias gaps are found in minutes."],"tags":["data-quality","dataframe","indicators","columns","alerts"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}