ZhuLinsen/daily_stock_analysis · error · ValueError

analysis_date_from cannot be after analysis_date_to

Error message

analysis_date_from cannot be after analysis_date_to

What it means

Plain ValueError raised at the top of the backtest batch run method when both analysis_date_from and analysis_date_to are supplied and from > to. It is a request-argument sanity check that fires before any normalization or data access, so an invalid window fails fast.

Source

Thrown at src/services/backtest_service.py:59

        self.db = db_manager or DatabaseManager.get_instance()
        self.repo = BacktestRepository(self.db)
        self.stock_repo = StockRepository(self.db)

    def run_backtest(
        self,
        *,
        code: Optional[str] = None,
        force: bool = False,
        eval_window_days: Optional[int] = None,
        min_age_days: Optional[int] = None,
        analysis_date_from: Optional[date] = None,
        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))

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Swap or correct the arguments so analysis_date_from <= analysis_date_to (both ISO YYYY-MM-DD).
  2. Validate/normalize the range client-side before calling the API.
  3. If the range is optional, send only one bound or neither instead of an inverted pair.

Example fix

# before
run_backtests(analysis_date_from=date(2026, 6, 1), analysis_date_to=date(2026, 5, 1))

# after
run_backtests(analysis_date_from=date(2026, 5, 1), analysis_date_to=date(2026, 6, 1))
Defensive patterns

Strategy: validation

Validate before calling

if analysis_date_from and analysis_date_to and analysis_date_from > analysis_date_to:
    analysis_date_from, analysis_date_to = analysis_date_to, analysis_date_from  # or reject with 400

Type guard

function isValidDateRange(from?: string, to?: string): boolean {
  if (!from || !to) return true;
  return new Date(from) <= new Date(to);
}

Try / catch

try:
    result = backtest_service.run_backtests(
        analysis_date_from=from_date, analysis_date_to=to_date
    )
except ValueError as exc:
    return JSONResponse(status_code=400, content={"detail": str(exc)})

Prevention

When it happens

Trigger: Calling the backtest service/API with analysis_date_from='2026-06-01' and analysis_date_to='2026-05-01' — swapped date pickers, wrong ISO order, or timezone/day-boundary mistakes.

Common situations: UI date-range pickers returning end-before-start; client sending dates in DD/MM/YYYY parsed as YYYY-MM-DD; DST or server-timezone shifts making an 'same day' range invert; hardcoded test dates left in config.

Related errors


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