Read market temperature from advance/decline
Market breadth (advancing vs declining) is the most direct way to tell whether "today was a broad rally or a split" — it reflects the true sentiment of the whole market better than a single index. This guide uses a free endpoint, covering how to read temperature, track several days, and spot a turning point.
1. Why look at advance/decline (30 seconds)
An index (e.g. Shanghai Composite) can be dragged by a few heavyweights; advance/decline reflects the whole market:
- Broad rally: far more advancers than decliners → warm sentiment (good money-making effect)
- Broad selloff: far more decliners → cold (loss-making effect)
- Split: roughly even → structural market (picking the right sector matters more than the index)
- Limit-ups: extreme sentiment — many limit-ups = active themes / euphoric money
2. Fetch the data (free endpoint)
`/v1/changedist` is a free endpoint (no Key). Returns two parts: breadth overview + percentage-change buckets, with `structured` for programmatic use.
import requests
r = requests.get("https://api.ashareapi.com/v1/changedist", timeout=30)
j = r.json()
s = j.get("structured") # for code
print(s) # [{"上涨": "3006", "上涨占比": "53%", "下跌": "2303", ...}]
# data is Markdown (for humans); structured is a 2D array (for code)
tables = j.get("tables") # [overview row, bucket rows...]
for t in tables:
print(t)- Free endpoint: no Key needed
- `structured` is a conditional field — only attached when data is Markdown (changedist qualifies)
- Use `structured` / `tables` for programmatic work, do not parse Markdown
3. Reading the fields
| Field | Meaning | Use |
|---|---|---|
| advance/decline | Up/down counts | Quick breadth read |
| advance ratio | advance / total | > 60% warm / < 40% cold |
| limit-up/down | Extreme sentiment | many limit-ups = active themes (watch for overheating) |
| suspended/flat | Non move | small, ignore |
| two-market turnover | Liquidity activity | rising on volume = healthy / falling on low volume = weak |
The buckets (>7% / 7-5% / 5-2% / 2-0% etc.) reveal strength — "3000 up" with lots of >5% gains is very different from "3000 up but mostly +1%".
4. How to read "market temperature"
- Never judge off one day — sentiment has inertia; track several days to find the turning point
- Overheat: high ratio + many limit-ups + rising turnover → possible sentiment top (pullback risk next day)
- Freezing: very low ratio + many limit-downs → often a sentiment bottom (bounce probability rises, but combine with other)
| Advance ratio | Limit-ups | Read |
|---|---|---|
| > 60% | many (≥40) | Warm / euphoric (watch for overheating) |
| 50-60% | moderate | Neutral-warm |
| 40-50% | few | Neutral-cold |
| < 40% | very few | Cold / weak |
| < 30% | near 0 | Freezing (extreme, cautious) |
5. Live data (2026-09-29)
| Metric | Value | Read |
|---|---|---|
| Advance / decline | 3006 / 2303 | Broad rally (clear more advancers) |
| Advance ratio | 53% | Neutral-warm |
| Limit-up / down | 42 / 9 | 40+ limit-ups, some theme activity |
| Two-market turnover | ~618bn CNY | (sample; check the day) |
Read: 53% ratio + 42 limit-ups = "neutral-warm, some theme heat" — not freezing, not overheated. This lukewarm state especially needs the multi-day trend (next section).
6. Track several days and spot the turning point
import requests, time
def breadth():
j = requests.get("https://api.ashareapi.com/v1/changedist", timeout=30).json()
s = j["structured"][0]
return int(s.get("上涨", 0)), int(s.get("下跌", 0)), int(s.get("涨停", 0))
# simulate logging (in practice store daily)
history = []
for day in range(5):
up, down, zt = breadth()
history.append((up, down, zt))
time.sleep(1)
for i, (up, down, zt) in enumerate(history):
ratio = up / (up + down) if (up + down) else 0
print("day%d ratio %.0f%% limit-up %d" % (i + 1, ratio * 100, zt))- Trend: ratio climbing → warming; falling → cooling
- Spike: jumps to >70% (with many limit-ups) → watch overheat; drops to <30% → watch freezing
- Discipline: breadth is a thermometer (describes state), not a predictor (does not guarantee reversal/continuation). Use it for environment, then set strategy preference (not a direct buy/sell)
7. Common misreads (important)
- ① Data basis: `/v1/changedist` is the current period. For a historical day use another means (this guide focuses on "today")
- ② Index vs breadth: the index may look fine due to heavyweights while the market is really split — breadth exposes that illusion
- ③ Many limit-ups ≠ necessarily euphoric: check persistence and theme concentration (scattered vs one sector clustering differ)
FAQ
No. changedist is one of the 5 free endpoints (quote / kline / hot / market-overview / changedist), no Key.
structured is conditional — only attached when data is Markdown. changedist qualifies, so use j.get("structured") for the array, or j.get("tables") for all tables (overview + buckets); do not parse Markdown.
Currently changedist returns the current period. Historical breadth needs other means; this guide focuses on reading today.
No absolute threshold. Generally >70% with many limit-ups and rising turnover is euphoric (higher pullback risk next day); <30% with many limit-downs is freezing. But it is an environment description, not a buy/sell conclusion.
Last updated: 2026-09-29
Data from live ashareapi /v1/changedist responses (measured 2026-09-29: advance 3006 / decline 2303 / limit-up 42 / limit-down 9 / advance ratio 53%); fields and structured/tables structure measured live.