ZhuLinsen/daily_stock_analysis · error · ValueError

{field_name} must be between {minimum} and {maximum}

Error message

{field_name} must be between {minimum} and {maximum}

What it means

Raised by _int_in_range (src/services/alert_indicators.py:384) when an integer field parses fine but falls outside the inclusive range [minimum, maximum], which defaults to [2, 250] and applies to window, period, fast/slow/signal/k/d periods. Period-1 indicators need at least 2 points; 250 caps single-field history demand (see also error 327 for the summed-bars cap of 365).

Source

Thrown at src/services/alert_indicators.py:384


def _direction(value: Any, allowed: frozenset[str], *, default: str) -> str:
    direction = str(value or default).strip().lower()
    if direction not in allowed:
        raise ValueError(f"invalid direction: {direction}")
    return direction


def _int_in_range(value: Any, field_name: str, *, default: int, minimum: int = 2, maximum: int = 250) -> int:
    raw_value = default if value is None or value == "" else value
    try:
        number = int(raw_value)
    except (TypeError, ValueError) as exc:
        raise ValueError(f"invalid {field_name}: {value}") from exc
    if str(raw_value).strip() not in {str(number), f"{number}.0"}:
        raise ValueError(f"{field_name} must be an integer")
    if number < minimum or number > maximum:
        raise ValueError(f"{field_name} must be between {minimum} and {maximum}")
    return number


def _finite_float(value: Any, field_name: str) -> float:
    try:
        number = float(value)
    except (TypeError, ValueError) as exc:
        raise ValueError(f"invalid {field_name}: {value}") from exc
    if not isfinite(number):
        raise ValueError(f"{field_name} must be finite")
    return number


def _float_in_range(
    value: Any,
    field_name: str,
    *,
    minimum: float,

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Clamp each integer field to 2..250 (e.g. window=200 is fine, window=300 is not).
  2. If you need >250-day windows, that single field cannot express it; reconsider the indicator or raise the cap in code after verifying data availability.
  3. Validate client-side with min=2 max=250 inputs.

Example fix

// before
{ "alert_type": "ma_price_cross", "parameters": { "window": 300 } }

// after
{ "alert_type": "ma_price_cross", "parameters": { "window": 250 } }
Defensive patterns

Strategy: validation

Validate before calling

for k, v in params.items():
    if k in INT_FIELDS:
        n = int(v)
        if not (2 <= n <= 250):
            raise ValueError(f'{k} must be within 2..250; adjust the strategy instead of inflating periods')

Type guard

def is_int_in_2_250(v) -> bool:
    try:
        return 2 <= int(v) <= 250
    except (TypeError, ValueError):
        return False

Try / catch

try:
    normalize_indicator_parameters(alert_type, params)
except ValueError as e:
    if 'must be between 2 and 250' in str(e):
        params.update({k: min(250, max(2, int(v))) for k, v in params.items() if k in INT_FIELDS})
        normalize_indicator_parameters(alert_type, params)
    else:
        raise

Prevention

When it happens

Trigger: parameters like {"window": 1} or {"window": 0} (below minimum 2); {"period": 300} or {"period": 365} (above maximum 250). Note each individual field maxes at 250 even though the summed-bars check separately allows sums up to 365.

Common situations: Copy-pasting settings from another platform allowing period=1 (some RSI(1) tricks) or 300-day windows; template configs tuned for intraday bars reused on daily bars; 'more is smoother' period inflation.

Related errors


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