{"record":{"id":"59bbe8ca3015adb1","repo":"ZhuLinsen/daily_stock_analysis","slug":"not-found-59bbe8","errorCode":"not_found","errorMessage":"未找到整体回测汇总","messagePattern":"未找到整体回测汇总","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"warning","filePath":"api/v1/endpoints/backtest.py","lineNumber":173,"sourceCode":"    eval_window_days: Optional[int] = Query(None, ge=1, le=120, description=\"评估窗口过滤\"),\n    analysis_date_from: Optional[date] = Query(None, description=\"分析日期起始（含）\"),\n    analysis_date_to: Optional[date] = Query(None, description=\"分析日期结束（含）\"),\n    analysis_phase: Optional[BacktestAnalysisPhaseQuery] = Query(None, description=\"分析阶段过滤：premarket/intraday/postmarket/unknown\"),\n    db_manager: DatabaseManager = Depends(get_database_manager),\n) -> PerformanceMetrics:\n    try:\n        _validate_analysis_date_range(analysis_date_from, analysis_date_to)\n        service = BacktestService(db_manager)\n        summary = service.get_summary(\n            scope=\"overall\",\n            code=None,\n            eval_window_days=eval_window_days,\n            analysis_date_from=analysis_date_from,\n            analysis_date_to=analysis_date_to,\n            analysis_phase=analysis_phase,\n        )\n        if summary is None:\n            raise HTTPException(\n                status_code=404,\n                detail={\"error\": \"not_found\", \"message\": \"未找到整体回测汇总\"},\n            )\n        return PerformanceMetrics(**summary)\n    except ValueError as exc:\n        raise HTTPException(\n            status_code=400,\n            detail={\"error\": \"invalid_params\", \"message\": str(exc)},\n        )\n    except HTTPException:\n        raise\n    except Exception as exc:\n        logger.error(f\"查询整体表现失败: {exc}\", exc_info=True)\n        raise HTTPException(\n            status_code=500,\n            detail={\"error\": \"internal_error\", \"message\": f\"查询整体表现失败: {str(exc)}\"},\n        )\n","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/api/v1/endpoints/backtest.py#L155-L191","documentation":"GET /backtest/performance returns HTTP 404 code=not_found '未找到整体回测汇总' when BacktestService.get_summary(scope='overall', ...) finds no aggregated summary row for the given filter combination (backtest.py:173-177). It means the query succeeded but no persisted backtest data matches — most commonly because no backtest has been run yet.","triggerScenarios":"Calling /performance before any POST /backtest/run has produced data; filters (eval_window_days, analysis_date_from/to, analysis_phase) that exclude every stored run; DB reset or pointing at an empty database; data written by an older schema the summary query no longer matches.","commonSituations":"Fresh deployment where the UI eagerly loads the performance tab; after switching filter defaults (e.g. eval_window_days) so historical rows no longer match; separating write and read instances so results go to one DB and summaries are read from another.","solutions":["Run POST /backtest/run (or wait for the scheduled backfill) to generate summary data, then retry","Loosen or clear the query filters (eval_window_days, date range, analysis_phase) to match existing stored runs","Verify the API's DB target actually contains backtest tables/rows (same DSN/file as the runner)","Treat 404 as an empty-state signal in clients: show 'no data yet' rather than an error page"],"exampleFix":"// before\nconst metrics = await api.get('/backtest/performance'); // 404 -> crash\n\n// after\nconst res = await fetch('/api/v1/backtest/performance');\nif (res.status === 404) {\n  return { empty: true, hint: 'run a backtest first' };\n}\nconst metrics = await res.json();","handlingStrategy":"type-guard","validationCode":"# Python client: model the empty state explicitly\nclass PerformanceResult(TypedDict, total=False):\n    empty: bool\n    metrics: dict\n\ndef fetch_overall_performance(params) -> PerformanceResult:\n    r = get('/backtest/performance', params)\n    if r.status_code == 404:\n        return {'empty': True}\n    r.raise_for_status()\n    return {'metrics': r.json()}","typeGuard":"def is_no_summary(resp) -> bool:\n    \"\"\"True when the backtest API answered 'no overall summary' (404 not_found).\"\"\"\n    return (\n        resp.status_code == 404\n        and isinstance(resp.json().get('detail'), dict)\n        and resp.json()['detail'].get('error') == 'not_found'\n        and '整体回测汇总' in resp.json()['detail'].get('message', '')\n    )","tryCatchPattern":"try:\n    summary = get_overall_performance(filters)\nexcept HTTPError as e:\n    if is_no_summary(e.response):\n        render_empty_state('run a backtest to see performance')\n    else:\n        raise","preventionTips":["Treat 404 on performance endpoints as an empty state, not an error","Trigger one backtest run on first visit so the performance tab has data","Keep filter defaults aligned with the values your scheduled backtests write"],"tags":["backtest","http-404","empty-state","performance"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}