Reference

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
  1. Add a delay: the limit is per-minute calls, and a tight loop hits 429 fastest.
  2. Check ok before storing: an empty result is still ok: true with an empty array, which is normal (see When empty is not a failure).
  3. Retry 429s: read the Retry-After header 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 — quote uses symbol, technical / profile use code.
  • Reading chip as 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.