Batch fetching
Only some endpoints accept several codes at once, and each one stitches the result back differently — one adds a symbol column, one folds the code into the column names. Check which kind it is before you send a list.
Three batch behaviours
Sending sh600519,sz000001 produces three completely different results:
| Behaviour | What you get | Endpoints |
|---|---|---|
| Proper merge (extra code column, one row per symbol) | row count doubles and every row carries a code column | quote (adds symbol) · technical · profile |
| Prefixed column names (wide table, row count unchanged) | column count doubles, names become sh600519_code / sz000001_code |
chip |
| First code only | later codes are ignored, with no error | fund · dividend · block-trade · minute · snapshot |
⚠️ One special case: margin-trade’s description claims batch support, but sending two codes returned the same structure as one — trust the measurement over the description.
How to read each behaviour
① Proper merge (quote / technical / profile) — filter by the code column:
rows = resp["data"]
moutai = [r for r in rows if r["code"] == "sh600519"] # technical / profile
# quote's code column is called symbol, not code
moutai_q = [r for r in rows if r["symbol"] == "sh600519"]
⚠️ quote uses symbol; technical / profile use code — the column names do not match.
② Prefixed columns (chip) — the row count stays put and the code moves into the column names:
rows = resp["data"]
for r in rows:
code = r.get("sh600519_code") or r.get("sz000001_code")
if code and code != "-":
profit = r.get(f"{code}_chipProfitRate")
⚠️ Half of each row is - (the two symbols sit side by side in the same row) — do not read that as missing data.
③ First code only — you must loop:
import time, requests
CODES = ["sh600519", "sz000001", "sh601318"]
out = {}
for c in CODES:
r = requests.get("https://api.ashareapi.com/v1/dividend",
params={"code": c}, headers={"Authorization": f"Bearer {KEY}"},
timeout=10).json()
if r.get("ok"):
out[c] = r["data"]
time.sleep(0.25) # ← slow down; do not saturate the limit
- Add a delay: the limit is per-minute calls, and a tight loop hits 429 fastest.
- Check
okbefore storing: an empty result is stillok: truewith an empty array, which is normal (see When empty is not a failure). - Retry 429s: read the
Retry-Afterheader and wait before retrying — do not retry at full speed.
Common misuses
- Assuming every endpoint batches — only some do; the rest silently use just the first code (data lost, no error).
- Filtering every endpoint by the same column —
quoteusessymbol,technical/profileusecode. - Reading
chipas a row array — it is a wide table with prefixed columns; the row count does not double and half of each row is-. - Looping with no delay — straight into 429.
- Treating 429 as a failure and discarding — it is a rate limit, not an error; wait and retry.
- Estimating cost by row count — billing is per request, and one batch request counts as one.
Last updated: 2026-10-07
Support and response structure measured endpoint by endpoint on 2026-10-07 by sending one code and then sh600519,sz000001 and comparing row count, column count and column names.