ZhuLinsen/daily_stock_analysis · error · ValueError
fast_period must be < slow_period
Error message
fast_period must be < slow_period
What it means
Raised by the macd_cross branch of normalize_indicator_parameters (src/services/alert_indicators.py:65) when fast_period >= slow_period after both are parsed as integers. MACD is mathematically defined as fast EMA minus slow EMA, so the fast period must be strictly smaller; defaults are fast=12, slow=26.
Source
Thrown at src/services/alert_indicators.py:65
if alert_type == "ma_price_cross":
normalized = {
"direction": _direction(parameters.get("direction"), ABOVE_BELOW_DIRECTIONS, default="above"),
"window": _int_in_range(parameters.get("window"), "window", default=20),
}
return _ensure_required_bars_fetchable(alert_type, normalized)
if alert_type == "rsi_threshold":
normalized = {
"direction": _direction(parameters.get("direction"), ABOVE_BELOW_DIRECTIONS, default="above"),
"period": _int_in_range(parameters.get("period"), "period", default=12),
"threshold": _float_in_range(parameters.get("threshold"), "threshold", minimum=0.0, maximum=100.0),
}
return _ensure_required_bars_fetchable(alert_type, normalized)
if alert_type == "macd_cross":
fast_period = _int_in_range(parameters.get("fast_period"), "fast_period", default=12)
slow_period = _int_in_range(parameters.get("slow_period"), "slow_period", default=26)
if fast_period >= slow_period:
raise ValueError("fast_period must be < slow_period")
normalized = {
"direction": _direction(parameters.get("direction"), CROSS_DIRECTIONS, default="bullish_cross"),
"fast_period": fast_period,
"slow_period": slow_period,
"signal_period": _int_in_range(parameters.get("signal_period"), "signal_period", default=9),
}
return _ensure_required_bars_fetchable(alert_type, normalized)
if alert_type == "kdj_cross":
normalized = {
"direction": _direction(parameters.get("direction"), CROSS_DIRECTIONS, default="bullish_cross"),
"period": _int_in_range(parameters.get("period"), "period", default=9),
"k_period": _int_in_range(parameters.get("k_period"), "k_period", default=3),
"d_period": _int_in_range(parameters.get("d_period"), "d_period", default=3),
}
return _ensure_required_bars_fetchable(alert_type, normalized)
if alert_type == "cci_threshold":
normalized = {
"direction": _direction(parameters.get("direction"), ABOVE_BELOW_DIRECTIONS, default="above"),View on GitHub (pinned to 5159bd72e8)
Solutions
- Set fast_period strictly less than slow_period (classic 12/26, or e.g. 5/35).
- When overriding one period, always send both explicitly so defaults cannot invert the relationship.
- Add a client-side check `fast < slow` in the alert form before submitting.
Example fix
// before
{ "alert_type": "macd_cross", "parameters": { "fast_period": 26, "slow_period": 12, "signal_period": 9 } }
// after
{ "alert_type": "macd_cross", "parameters": { "fast_period": 12, "slow_period": 26, "signal_period": 9 } } Defensive patterns
Strategy: validation
Validate before calling
fast = params.get('fast_period', 12)
slow = params.get('slow_period', 26)
assert int(fast) < int(slow), 'send fast_period < slow_period (both when overriding either)' Type guard
def is_valid_macd_periods(p: dict) -> bool:
try:
return int(p.get('fast_period', 12)) < int(p.get('slow_period', 26))
except (TypeError, ValueError):
return False Try / catch
try:
normalize_indicator_parameters('macd_cross', params)
except ValueError as e:
if 'fast_period must be < slow_period' in str(e):
params['fast_period'], params['slow_period'] = sorted([params['fast_period'], params['slow_period']])
normalize_indicator_parameters('macd_cross', params)
else:
raise Prevention
- Always send both periods together, never override just one.
- Validate fast < slow in the form's submit handler with a visible error.
- Use the canonical 12/26 unless you have a reason; document non-default MACD settings.
When it happens
Trigger: Creating or updating an alert with alert_type="macd_cross" and parameters like {"fast_period": 26, "slow_period": 12}, {"fast_period": 20, "slow_period": 20}, or omitting slow_period while overriding fast_period to a value >= 26 (e.g. fast_period=30 with default slow_period=26).
Common situations: Users swapping the two fields by intuition ('fast' sounds like the bigger number to some); overriding only one period and forgetting the other's default; UI form not cross-validating the pair before submit.
Related errors
- {alert_type} periods require {required_bars} bars, but at mo
- unsupported alert_type for current EventMonitor runtime: {al
- Event alert rules must be a JSON array
- Event alert rules list must contain only objects; invalid en
- Event alert rule must be an object
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/3d52d3008d032573.
Report an issue: GitHub.