{"record":{"id":"ee887f61de2dbd1f","repo":"TauricResearch/TradingAgents","slug":"alpha-vantage-rate-limit-exceeded-notice","errorCode":null,"errorMessage":"Alpha Vantage rate limit exceeded: {notice}","messagePattern":"Alpha Vantage rate limit exceeded: (.+?)","errorType":"exception","errorClass":"AlphaVantageRateLimitError","httpStatus":null,"severity":"warning","filePath":"tradingagents/dataflows/alpha_vantage_common.py","lineNumber":106,"sourceCode":"\n    response_text = response.text\n\n    # Error responses are JSON; data responses are usually CSV (or data-keyed\n    # JSON). A non-JSON body is normal data.\n    try:\n        response_json = json.loads(response_text)\n    except json.JSONDecodeError:\n        return response_text\n\n    # Alpha Vantage reports problems via \"Information\" / \"Note\". Classify so a\n    # genuine rate limit and an invalid/missing key aren't conflated (#991):\n    # rate-limit phrasing is checked first because those notices also mention\n    # \"API key\" (\"your API key ... 25 requests per day\").\n    notice = response_json.get(\"Information\") or response_json.get(\"Note\")\n    if notice:\n        low = notice.lower()\n        if any(m in low for m in (\"rate limit\", \"requests per day\", \"call frequency\", \"premium\")):\n            raise AlphaVantageRateLimitError(f\"Alpha Vantage rate limit exceeded: {notice}\")\n        if \"api key\" in low or \"apikey\" in low:\n            # Reuse the existing \"not configured\" error so a bad key surfaces as\n            # a real, actionable failure rather than a mislabeled rate limit (#991).\n            raise AlphaVantageNotConfiguredError(f\"Alpha Vantage API key invalid or missing: {notice}\")\n\n    return response_text\n\n\n\ndef _filter_csv_by_date_range(csv_data: str, start_date: str, end_date: str) -> str:\n    \"\"\"\n    Filter CSV data to include only rows within the specified date range.\n\n    Args:\n        csv_data: CSV string from Alpha Vantage API\n        start_date: Start date in yyyy-mm-dd format\n        end_date: End date in yyyy-mm-dd format\n","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/TauricResearch/TradingAgents/blob/a33fd4c0f134485a43553a2c23a63cb14adbd88f/tradingagents/dataflows/alpha_vantage_common.py#L88-L124","documentation":"Raised by _make_api_request() in tradingagents/dataflows/alpha_vantage_common.py when Alpha Vantage's JSON response carries an 'Information' or 'Note' field whose text mentions 'rate limit', 'requests per day', 'call frequency', or 'premium'. It is an AlphaVantageRateLimitError (subclass of VendorRateLimitError, not a ValueError), signalling a transient throttle so the router in interface.py skips to the next configured vendor instead of aborting.","triggerScenarios":"Exceeding the free-tier limit (25 requests/day on current free keys) or the 5-requests/minute limit; calling premium endpoints on a free key, which return a notice mentioning 'premium'. Rate-limit phrasing is deliberately checked before 'api key' because those notices also mention the key.","commonSituations":"Long backtest loops hammering the API without sleeps; sharing one free key across processes/CI; upgrading endpoints without upgrading the key tier; running a multi-ticker analysis where each ticker triggers several indicator calls.","solutions":["Throttle your calls: on free keys sleep >= 60s between requests (5/min limit) or spread them under the daily cap","Upgrade to a premium Alpha Vantage key for higher limits","Configure a vendor chain for multi-vendor fallback, e.g. data_vendors=\"alpha_vantage,yfinance\", so the router skips to yfinance on rate limit","Cache responses (the repo already caches OHLCV per symbol/day) and reuse them across runs instead of refetching"],"exampleFix":"# before\nfor symbol in [\"AAPL\", \"MSFT\", \"GOOG\", \"NVDA\", \"AMZN\", \"TSLA\"]:\n    get_historical_prices(symbol, \"2025-01-10\", \"2025-01-15\")  # 6 calls back-to-back\n# -> AlphaVantageRateLimitError: Alpha Vantage rate limit exceeded: ...\n\n# after\nimport time\nfor symbol in [...]:\n    get_historical_prices(symbol, \"2025-01-10\", \"2025-01-15\")\n    time.sleep(65)  # respect 5 requests/minute on free tier\n# and/or config: {\"data_vendors\": {\"stock_data\": \"alpha_vantage,yfinance\"}}","handlingStrategy":"retry","validationCode":"# Throttling is prevention: pace calls under the free-tier 5/min (or your tier's) limit\nimport time\n\nclass RateLimiter:\n    def __init__(self, min_interval: float = 61.0):\n        self.min_interval = min_interval\n        self._last = 0.0\n    def wait(self):\n        delta = time.monotonic() - self._last\n        if delta < self.min_interval:\n            time.sleep(self.min_interval - delta)\n        self._last = time.monotonic()","typeGuard":null,"tryCatchPattern":"from tradingagents.dataflows.alpha_vantage_common import AlphaVantageRateLimitError\n\ntry:\n    result = fetch(symbol)\nexcept AlphaVantageRateLimitError:\n    time.sleep(60)          # honor the throttle window\n    result = fetch(symbol)  # single retry; switch vendors if it persists","preventionTips":["Serialize Alpha Vantage calls through one rate limiter per process; never parallelize on a free key","Cache per symbol+day (the repo does) and reuse cache across backtest iterations","Configure a fallback vendor chain so a throttle skips to yfinance automatically","Upgrade the key tier for batch jobs instead of engineering around the cap"],"tags":["rate-limit","alpha-vantage","network","throttling"],"backgroundTag":null,"analyzedSha":"a33fd4c0f134485a43553a2c23a63cb14adbd88f","analyzedAt":"2026-08-14T19:45:16.920Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}