ZhuLinsen/daily_stock_analysis · error · ValueError
eval_window_days must be a positive integer
Error message
eval_window_days must be a positive integer
What it means
BacktestService.run_backtest validates eval_window_days before running an evaluation: it must be a non-boolean int greater than 0. When the argument is None the service falls back to config.backtest_eval_window_days (default 10), so the error fires either on a bad explicit argument or a corrupt config value. It is raised as a plain ValueError, which the FastAPI backtest endpoint translates to HTTP 400 invalid_params.
Source
Thrown at src/services/backtest_service.py:71
analysis_date_to: Optional[date] = None,
limit: int = 200,
) -> Dict[str, Any]:
config = get_config()
if analysis_date_from and analysis_date_to and analysis_date_from > analysis_date_to:
raise ValueError("analysis_date_from cannot be after analysis_date_to")
query_code = self._normalize_code(code)
diagnostic_code = self._normalize_code_for_display(code)
if eval_window_days is None:
eval_window_days = getattr(config, "backtest_eval_window_days", 10)
if (
isinstance(eval_window_days, bool)
or not isinstance(eval_window_days, int)
or eval_window_days <= 0
):
raise ValueError("eval_window_days must be a positive integer")
if min_age_days is None:
min_age_days = getattr(config, "backtest_min_age_days", 14)
engine_version = getattr(config, "backtest_engine_version", "v1")
neutral_band_pct = float(getattr(config, "backtest_neutral_band_pct", 2.0))
eval_config = EvaluationConfig(
eval_window_days=int(eval_window_days),
neutral_band_pct=neutral_band_pct,
engine_version=str(engine_version),
)
limit_int = int(limit)
candidates = self._get_run_candidates(
code=query_code,
min_age_days=int(min_age_days),
limit=limit_int,
eval_window_days=int(eval_window_days),View on GitHub (pinned to 5159bd72e8)
Solutions
- Pass eval_window_days as a positive int (e.g. 10) or omit it so the config default (10) applies.
- Check the effective config: python -c "from src.config.config import get_config; print(get_config().backtest_eval_window_days)" and fix .env / BACKTEST_EVAL_WINDOW_DAYS.
- If the value arrives from a client as a string, coerce with int() and validate > 0 before calling the service (the API schema should already enforce ge=1, le=120).
Example fix
# before service.run_backtest(code="600519", eval_window_days="20") # after service.run_backtest(code="600519", eval_window_days=20)
Defensive patterns
Strategy: validation
Validate before calling
def valid_eval_window(v) -> bool:
return isinstance(v, int) and not isinstance(v, bool) and v > 0
if eval_window_days is not None and not valid_eval_window(eval_window_days):
raise HTTPException(400, "eval_window_days must be a positive integer")
service.run_backtest(code=code, eval_window_days=eval_window_days) Type guard
def isPositiveInt(v: object) -> bool:
return isinstance(v, int) and not isinstance(v, bool) and v > 0 Try / catch
try:
service.run_backtest(code=code, eval_window_days=eval_window_days)
except ValueError as exc:
if "eval_window_days" in str(exc):
return JSONResponse(status_code=400, content={"error": "invalid_params", "message": str(exc)})
raise Prevention
- Declare eval_window_days as Optional[int] with ge=1 in request schemas so FastAPI rejects bad input first.
- Keep BACKTEST_EVAL_WINDOW_DAYS a plain positive integer in .env.
- Never pass bools where ints are expected; add isinstance(v, bool) guards in coercion helpers.
When it happens
Trigger: Calling POST /api/v1/backtest/run (or BacktestService.run_backtest) with eval_window_days=0, a negative int, a string like "10", a float like 7.5, or True/False; or setting backtest_eval_window_days=0/-1/"7d" in .env/config so the fallback value itself is invalid.
Common situations: Typos in .env (BACKTEST_EVAL_WINDOW_DAYS=10.5 or empty string parsed as 0), passing a bool because the value came from a JSON query string ("true" coerced), or a frontend sending the field as a string from a form input.
Related errors
- invalid_params
- eval_window_days must be positive
- analysis_date_from cannot be after analysis_date_to
- 非法股票代码格式: {code}
- Phase-filtered summary candidate set matches too many rows;
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/6db0a5480e768dae.
Report an issue: GitHub.