Tutorial

Batch Fetching: 5,000 Requests Down to 23

Scanning all 5,000+ A-shares one by one costs 5,000+ requests. With batch endpoints at 250 symbols per call it takes 23. Table, code and quota rules below.

When to use batch endpoints

If your loop calls the same endpoint over and over for a list of symbols, switch to the batch version. Typical cases: full-market screening, refreshing a watchlist on a schedule, preparing data before a multi-symbol backtest.

Batch endpoints are not just faster — they bill per returned symbol, and failed symbols are not billed, so they are also cheaper and easier to handle errors with.

Loop /v1/snapshot
5,000+ requests
~30 min (rate-limited)
/v1/snapshot-batch (250 per call)
23 requests
~10 seconds

The nine batch endpoints: caps and daily quotas

Per-call caps and daily quotas differ per endpoint because the upstream sources differ. Quotas count calls, and reset at 00:00 Beijing time.

/v1/quote-batch quotes
200 / 1000
200
1000
/v1/kline-batch K-lines
200 / 1000
200
1000
/v1/snapshot-batch full snapshot
200 / 250
200
1000
/v1/fund-batch money flow
200 / 1000
200
1000
/v1/technical-batch indicators
500 / 1000
200
500
/v1/chip-batch chips
200 / 300
200
1000
/v1/shareholder-batch shareholders
200 / 300
200
1000
/v1/profile-batch company profile
100 / 150
100
300
/v1/finance-batch financials
10 / 20
100
500

The "max per call" column shows Pro / Institutional. finance-batch allows only 10–20 symbols per call, so a full-market pass needs 250+ calls — still within its 500/day quota, but plan for it.

Runnable example: 50 full snapshots in one call

The response marks every symbol individually: {code, ok, data} or {code, ok:false, error}. One bad code never breaks the batch — just filter on ok.

Python (replace KEY)
import requests

KEY = "ct-your-key"
codes = ["sh600519", "sz000001", "sz300750"]   # up to 250 (Institutional)

r = requests.get(
    "https://api.ashareapi.com/v1/snapshot-batch",
    params={"codes": ",".join(codes), "key": KEY},
    timeout=20,
).json()

print(r["requested"], r["returned"], r["failed"])   # 3 3 0
for item in r["data"]:
    if item["ok"]:
        d = item["data"]
        print(item["code"], d["name"], d["price"], d["pe"])
    else:
        print(item["code"], "failed:", item.get("error"))

Full-market scan in 23 requests

Use the endpoint cap from the table above as your chunk size. A smaller chunk is not an error — it just wastes call quota, which is the most common way people burn through a daily quota.

Python (chunked)
def chunks(seq, n):
    for i in range(0, len(seq), n):
        yield seq[i:i + n]

all_rows, failed = [], []
for i, batch in enumerate(chunks(all_codes, 250), 1):   # 5,000+ => about 23 batches
    r = requests.get(
        "https://api.ashareapi.com/v1/snapshot-batch",
        params={"codes": ",".join(batch), "key": KEY},
        timeout=30,
    ).json()
    all_rows += [x for x in r["data"] if x["ok"]]
    failed   += [x["code"] for x in r["data"] if not x["ok"]]
    print(f"batch {i}, {len(all_rows)} symbols so far")

How quota is counted

Check today's remaining calls
u = requests.get("https://api.ashareapi.com/v1/usage",
                  params={"key": KEY}).json()

print(u["heavy_quotas"]["snapshot-batch"])
# {'used': 0, 'limit': 1000, 'left': 1000}
  • Billed per returned symbol: request 250, get 248 back, billed 248
  • Failed symbols are refunded automatically — no action needed
  • The daily quota counts calls, not symbols
  • Resets at 00:00 Beijing time; when exhausted the API returns 429 with retry_after_s
  • Check remaining quota anytime: GET /v1/usage?key=..., field heavy_quotas

Check quota before starting a batch job — cheaper than hitting 429 halfway through.

Three pitfalls

  • A-shares only: snapshot-batch / profile-batch accept sh / sz / bj only; HK/US symbols return ok:false
  • Prefixes are required: sh600519, not 600519
  • Exceeding the cap rejects the whole call: 300 symbols to snapshot-batch (cap 250) is an error, not a silent truncation

FAQ

Is a 250-symbol call slow?

snapshot-batch does 300 symbols in 0.40s (10x faster than /v1/quote-batch); profile-batch is the slowest at ~10s for 150. Use a 30s timeout, or 60s for finance-batch.

What happens when the daily quota runs out?

It resets at 00:00 Beijing time. To do more today, use another batch endpoint (each has its own quota) or upgrade the tier.

Is the data identical to the single-symbol endpoints?

Yes — same fields. snapshot-batch returns exactly the /v1/snapshot payload (35+ fields), just packed into an array. Units are unchanged (volume in lots, amount in 10k CNY, market cap in 100M CNY).

Why did 250 symbols return only 200?

Fifty of them were malformed or outside the A-share universe. Check the ok:false entries and their error field — failed symbols are not billed.

Last updated: 2026-11-02

Caps and daily quotas read from backend config (verified 2026-11-02: full HEAVY_DAILY and _batch_cap tables). Timings measured: snapshot-batch 300 symbols 0.40s, profile-batch 150 symbols 10.02s.