ZhuLinsen/daily_stock_analysis · error · RateLimitError
efinance 可能被限流: {failure_message}
Error message
efinance 可能被限流: {failure_message} What it means
Raised as RateLimitError from EfinanceFetcher._fetch_stock_data when _build_history_failure_message classifies the caught exception as 'rate_limit_or_anti_bot' — Eastmoney throttled or bot-challenged the request. Distinct from generic failure (error 151) so callers can back off rather than fail over blindly.
Source
Thrown at data_provider/efinance_fetcher.py:471
f"endpoint={EASTMONEY_HISTORY_ENDPOINT}, stock_code={stock_code}, "
f"range={beg_date}~{end_date_fmt}, elapsed={api_elapsed:.2f}s"
)
return df
except Exception as e:
api_elapsed = time.time() - api_start
category, failure_message = self._build_history_failure_message(
stock_code=stock_code,
beg_date=beg_date,
end_date=end_date_fmt,
exc=e,
elapsed=api_elapsed,
)
if category == "rate_limit_or_anti_bot":
logger.warning(failure_message)
raise RateLimitError(f"efinance 可能被限流: {failure_message}") from e
logger.error(failure_message)
raise DataFetchError(f"efinance 获取数据失败: {failure_message}") from e
def _fetch_etf_data(self, stock_code: str, start_date: str, end_date: str) -> pd.DataFrame:
"""
获取 ETF 基金历史数据
Exchange-traded ETFs have OHLCV data just like regular stocks, so we use
ef.stock.get_quote_history (the stock K-line API) which returns full
open/high/low/close/volume data.
Previously this method used ef.fund.get_quote_history which only returns
NAV data (单位净值/累计净值) without volume or OHLC, causing:
- Issue #541: 'got an unexpected keyword argument beg'
- Issue #527: ETF volume/turnover always showing 0
Args:View on GitHub (pinned to 5159bd72e8)
Solutions
- Back off and retry after a delay — the fetcher already does random_sleep, so add exponential backoff around the call or reduce batch size.
- Let DataFetcherManager fail over to akshare/tushare for the affected codes in this run.
- Cache daily bars so repeated analyses within a day don't re-hit Eastmoney.
Example fix
# before
for code in codes:
df = manager.get_daily_data(code, ...)
# after
import time
for i, code in enumerate(codes):
try:
df = manager.get_daily_data(code, ...)
except RateLimitError:
time.sleep(30 * (i // 10 + 1)) # exponential-ish backoff
df = manager.get_daily_data(code, ...) Defensive patterns
Strategy: retry
Try / catch
from data_provider.base import RateLimitError # efinance rate-limit signal
for attempt in range(3):
try:
df = efinance_fetcher.get_daily_data(code, ...)
break
except RateLimitError:
time.sleep(2 ** attempt * 30)
else:
df = manager.get_daily_data(code, ...) # fail over after backoff Prevention
- Throttle A-share batch loops (sleep between calls, batch size caps).
- Cache daily K-lines per day so repeated runs don't re-hit Eastmoney.
- Distinguish RateLimitError from DataFetchError: backoff vs failover.
When it happens
Trigger: ef.stock.get_quote_history raising with HTTP 4xx/5xx patterns, connection resets, or anti-bot payloads during bursty A-share K-line fetching; classification depends on _build_history_failure_message's category rules.
Common situations: Batch jobs fetching hundreds of A-share codes sequentially; running alongside other Eastmoney consumers from the same IP; CI network-smoke runs hitting Eastmoney repeatedly.
Related errors
- Akshare(EM) 可能被限流: {e}
- Akshare 所有渠道获取失败: {last_error}
- Akshare 可能被限流: {e}
- [AlphaVantage] Rate limited: {data['Note']}
- 所有数据源获取 {stock_code} 失败: {errors joined by newline}
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/d9772138503615c6.
Report an issue: GitHub.