> Source: https://ashareapi.com/en/docs/guides/quote-realtime-price/  ·  Markdown version for LLMs / AI agents

Guide

# 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.

 Python: latest price for one stock
```
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%)

 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**.

 Python: fetch several stocks concurrently
```
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**.

 Python: challenge → solve → call
```
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

 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
 Why do I get a close price instead of a realtime price?
 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.

 Is volume in shares or lots? Is amount in CNY or thousands?
 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.

 Can I fetch several stocks in one call?
 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.

 Do I need the market prefix? Can I pass just 600667?
 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.

 Is this endpoint free?
 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.

 Related

-
[Endpoint reference (quote)](/en/docs/endpoints/quote)

-
[Technical indicators from K-line](/en/docs/guides/kline-technical-indicators)

-
[Getting A-share quotes in Python: 3 approaches](/en/docs/guides/python-ashare-quotes)

-
[Error codes & rate limits](/en/docs/errors)

 [← All tutorials](/en/docs/guides)
