ZhuLinsen/daily_stock_analysis · warning · HTTPException

not_found

not_found

Error message

未找到整体回测汇总

What it means

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.

Source

Thrown at api/v1/endpoints/backtest.py:173

    eval_window_days: Optional[int] = Query(None, ge=1, le=120, description="评估窗口过滤"),
    analysis_date_from: Optional[date] = Query(None, description="分析日期起始(含)"),
    analysis_date_to: Optional[date] = Query(None, description="分析日期结束(含)"),
    analysis_phase: Optional[BacktestAnalysisPhaseQuery] = Query(None, description="分析阶段过滤:premarket/intraday/postmarket/unknown"),
    db_manager: DatabaseManager = Depends(get_database_manager),
) -> PerformanceMetrics:
    try:
        _validate_analysis_date_range(analysis_date_from, analysis_date_to)
        service = BacktestService(db_manager)
        summary = service.get_summary(
            scope="overall",
            code=None,
            eval_window_days=eval_window_days,
            analysis_date_from=analysis_date_from,
            analysis_date_to=analysis_date_to,
            analysis_phase=analysis_phase,
        )
        if summary is None:
            raise HTTPException(
                status_code=404,
                detail={"error": "not_found", "message": "未找到整体回测汇总"},
            )
        return PerformanceMetrics(**summary)
    except ValueError as exc:
        raise HTTPException(
            status_code=400,
            detail={"error": "invalid_params", "message": str(exc)},
        )
    except HTTPException:
        raise
    except Exception as exc:
        logger.error(f"查询整体表现失败: {exc}", exc_info=True)
        raise HTTPException(
            status_code=500,
            detail={"error": "internal_error", "message": f"查询整体表现失败: {str(exc)}"},
        )

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Run POST /backtest/run (or wait for the scheduled backfill) to generate summary data, then retry
  2. Loosen or clear the query filters (eval_window_days, date range, analysis_phase) to match existing stored runs
  3. Verify the API's DB target actually contains backtest tables/rows (same DSN/file as the runner)
  4. Treat 404 as an empty-state signal in clients: show 'no data yet' rather than an error page

Example fix

// before
const metrics = await api.get('/backtest/performance'); // 404 -> crash

// after
const res = await fetch('/api/v1/backtest/performance');
if (res.status === 404) {
  return { empty: true, hint: 'run a backtest first' };
}
const metrics = await res.json();
Defensive patterns

Strategy: type-guard

Validate before calling

# Python client: model the empty state explicitly
class PerformanceResult(TypedDict, total=False):
    empty: bool
    metrics: dict

def fetch_overall_performance(params) -> PerformanceResult:
    r = get('/backtest/performance', params)
    if r.status_code == 404:
        return {'empty': True}
    r.raise_for_status()
    return {'metrics': r.json()}

Type guard

def is_no_summary(resp) -> bool:
    """True when the backtest API answered 'no overall summary' (404 not_found)."""
    return (
        resp.status_code == 404
        and isinstance(resp.json().get('detail'), dict)
        and resp.json()['detail'].get('error') == 'not_found'
        and '整体回测汇总' in resp.json()['detail'].get('message', '')
    )

Try / catch

try:
    summary = get_overall_performance(filters)
except HTTPError as e:
    if is_no_summary(e.response):
        render_empty_state('run a backtest to see performance')
    else:
        raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15). Data as JSON: /api/errors/59bbe8ca3015adb1. Report an issue: GitHub.