Realtime quotes and daily close with /v1/quote
Getting "what is this stock worth right now" takes one GET: `/v1/quote` is free, needs no Key and no signup, and returns the last 30 trading days of OHLC plus volume/value/turnover. `data[0]` is the most recent day.
1. The 5 lines you actually need
`/v1/quote` is a free endpoint (no Key, no signup). The only required param is `code`. It returns a unified envelope `{ ok, endpoint, tier, elapsed_ms, source, data }`, where `data` is a day array, newest first (30 by default) and `data[0]` is the latest trading day.
import requests
r = requests.get(
"https://api.ashareapi.com/v1/quote",
params={"code": "sh600667"}, # market prefix required
timeout=10,
)
body = r.json()
if not body.get("ok"):
raise RuntimeError(body) # failures return ok=false + error
bar = body["data"][0] # most recent trading day
print(bar["date"], bar["last"], bar["turnover"])- `code` needs a market prefix: `sh600667` (Shanghai) / `sz000001` (Shenzhen) / `bj920002` (Beijing) / `hk00700` (HK) / `usAAPL` (US). A bare 6-digit code returns an empty result.
- `data` is an array (30 by default, `data[0]` newest), not a single object.
2. Fields and units (the part people get wrong)
| Field | Meaning | Unit / note |
|---|---|---|
| date | Trading date | YYYY-MM-DD — the data date, not query date |
| open / high / low | Open / high / low | numeric strings |
| last | Close (previous session) | not the intraday live price — see section 3 |
| volume | Volume | lots (×100 = shares) |
| amount | Turnover value | CNY (not thousands/millions) |
| turnover | Turnover rate | percent (4.92 = 4.92%) |
Unit reminders: `volume` is in lots, `amount` in CNY, `turnover` is a percent — the three classic newbie traps. The same fields in `/v1/kline` are identically named and valued, so you can mix them safely.
3. Realtime or close? — data-date semantics
`last` is the close for that trading day, and `date` tells you which day. When you call during market hours, `data[0].date` is today and `last` is the latest price up to the request moment (usable as the current price); after the close it is that day's close. So check whether `date` equals today to tell which one you are looking at.
This is by design: one endpoint serves both "realtime snapshot" and "historical close", disambiguated by `date`. For a live display, check `date` first so you never show yesterday's close as the current price.
- During hours: `date` = today → `last` is the current price
- After close / holiday: `date` = last trading day → `last` is the close
- How to tell: `bar["date"] == today` (or use the trading calendar)
4. Multiple stocks (concurrency + rate limits)
`/v1/quote` takes one `code` per call (not comma-separated). For many stocks, use a thread pool — and mind the anonymous limit: 5 requests/minute.
from concurrent.futures import ThreadPoolExecutor
import requests
def q(code):
r = requests.get("https://api.ashareapi.com/v1/quote",
params={"code": code}, timeout=10)
j = r.json()
if not j.get("ok"): # 429 / 401 also land here
return code, j.get("error")
return code, j["data"][0]["last"]
codes = ["sh600667", "sz000001", "sh600519"]
with ThreadPoolExecutor(max_workers=3) as ex:
for code, price in ex.map(q, codes):
print(code, price)- Anonymous: 5 requests/minute — beyond that returns 429. For more, solve one PoW challenge to reach 60/min (see section 5), or apply for a Key.
- Keep concurrency modest: 3-5 workers is plenty; more just hits the limit sooner.
5. Hitting 429? There is a free speed-up
Anonymous calls have a per-minute quota; over it you get `429 Too Many Requests`. `/v1/challenge` is the free upgrade path: fetch a challenge (PoW), solve it, and send it back in `X-PoW` to raise the anonymous quota from 5/min to 60/min.
import requests
# 1) fetch a challenge (difficulty can only be raised, not lowered)
ch = requests.get("https://api.ashareapi.com/v1/challenge", timeout=10).json()
# ch = {"challenge": ..., "difficulty": 18, ...}
# 2) solve the PoW: find a nonce so sha256(challenge+nonce) has 'difficulty' leading zero bits
# (details in /docs/errors; for most cases applying for a Key is simpler)
# 3) call with the X-PoW header for the higher quota
# r = requests.get("https://api.ashareapi.com/v1/quote",
# params={"code": "sh600667"},
# headers={"X-PoW": solved}, timeout=10)- Usually enough: 5/min covers a single-machine display or review flow; batch jobs are better off with a Key (see /pricing).
- Do not retry 429 in a tight loop — back off a few seconds or slow down.
6. quote vs kline — which one?
| /v1/quote | /v1/kline | |
|---|---|---|
| Use for | Quote snapshot + last 30 days | Historical bars (custom period/count) |
| Params | code | code / period / count |
| Default | last 30 trading days | last 30 bars (count up to 1212) |
| Adjustment | raw prices | forward-adjusted (no gap) |
| Fields | date/open/high/low/last/volume/amount/turnover | same names, same values |
One line: use `quote` for "current / last few days", and `kline` (forward-adjusted) for full history, indicators or backtests. The fields line up between the two.
FAQ
Check `data[0].date`: when it equals today, `last` is the live price up to now (usable as the current price); when it is a past date, it is that session close. The endpoint intentionally serves both snapshot and close use cases, disambiguated by date — so you never mistake yesterday close for the current price.
volume is in lots (1 lot = 100 shares), amount is in CNY, and turnover is a percent (4.92 means 4.92%). These are the three most common unit mistakes — worth a code comment.
No — one code per call. Use a thread pool for batches and mind the anonymous limit (5/min); for higher rates apply for a Key or solve the PoW challenge to reach 60/min.
A prefix is required (sh600667 / sz000001 / bj920002 / hk00700 / usAAPL). A bare 6-digit code returns an empty result (not an error) — the most common newbie pitfall.
Yes — no signup, no Key, anonymous calls are fine (5 requests/minute). Higher quotas are on /pricing.
Last updated: 2026-10-01
Data from live ashareapi /v1/quote responses (measured 2026-10-01: 600667 returned 30 rows, data[0] date=2026-09-30 last=17.29 high=18.28 volume=1029096 amount=1804480000 turnover=4.92); fields and units verified against live responses.