Reading A-share block trades: discount rate & institutional seats
A block trade is a large off-orderbook transfer agreed between two parties. It never shows on the intraday chart, yet it often reveals intent before price moves. This guide covers: how to read the fields, what the discount rate means, and how to scan in bulk with Python (with live 2026-09-29 data).
1. What a block trade is (30 seconds)
A block trade is a large transfer executed through the exchange block-trading system by mutual agreement. Because it bypasses continuous auction: it does not appear on the intraday tape, and the trade is disclosed the next day (T+1).
That is the value: you can see who took how much, at what price, from whom — information the normal order book does not give.
- Sellers wanting to offload → use blocks (fast exit without crashing the price)
- Buyers wanting size → take blocks (faster than buying in the market)
- Discount = seller concedes for speed (common); premium = buyer is eager (rare, stronger signal)
2. One request to fetch it
`/v1/block-trade` is a paid endpoint. Only two parameters: `code` (optional) and `date` (optional; default = latest).
import requests
BASE = "https://api.ashareapi.com/v1"
H = {"Authorization": "Bearer ct-your-key"}
r = requests.get(f"{BASE}/block-trade",
params={"code": "sh600519"}, # Kweichow Moutai
headers=H, timeout=30)
body = r.json()
# Note: data may be an array; do NOT write body["structured"] (KeyError)
rows = body.get("data") if isinstance(body.get("data"), list) else body.get("structured")
if not body.get("ok"):
print("no block trade that day (not an API failure)") # see section 4
else:
for x in rows:
print(x["TurnoverPrice"], x["CloseDiscountRate"],
x["BuySalesDepartment"], x["SellSalesDepartment"])- `data` may be an array or Markdown — branch on type (or fall back to `body.get("structured")`)
- `ok:false` with an empty array = no block trade that day (a normal result, not a fault) — see section 4
3. The seven fields
| Field | Meaning | Unit | How to use |
|---|---|---|---|
| TurnoverPrice | Trade price | CNY | Compare with the close to get premium/discount |
| TurnoverValue | Trade value | CNY | > 100m = large; judge the scale of impact |
| CloseDiscountRate | Discount rate | % | + = premium / - = discount / 0 = flat |
| BuySalesDepartment | Buy-side brokerage | - | Institutional seat or a named branch |
| SellSalesDepartment | Sell-side brokerage | - | Who sold |
| TradingType | Trade type | - | Agreement trade / after-hours fixing, etc. |
| SerialNumber | Sequence | - | Which trade of the day |
Volume caveat: `TurnoverValue` is a single trade. Sum same-day trades for a daily total. The upstream reports "number of trading days with blocks" and "total trade count" as two different measures — state which one you use.
4. The discount rate is the most informative field
`CloseDiscountRate` is relative to the closing price of the day:
| Rate | Meaning | Usual read |
|---|---|---|
| Positive (premium) | Buyer paid above market | Buyer is eager (rare) - stronger signal |
| 0 (flat) | Traded at market | Common, neutral |
| Negative (discount) | Seller conceded for speed | Common - deeper discount, more urgency |
Key point: discounts are the norm — large stakes are hard to sell at market, so a discount alone is not a bearish signal. What carries more information is an unusually deep discount (e.g. -8%) combined with who bought (institutional seat vs an ordinary branch).
5. Live data (2026-09-29)
| Stock | Price | Value | Rate | Buy side |
|---|---|---|---|---|
| sh600519 Kweichow Moutai | 1299.52 | 90.97m | 0.00 | GF Securities Beijing Lugu Rd |
| sh600276 Hengrui Pharma | 49.75 | 252.19m | -8.01 | Huatai Securities Shanghai Br. |
| sh601899 Zijin Mining | 29.42 | 12.06m | 0.00 | Industrial Securities Shanghai |
| sz300750 CATL | 286.80 | 3.16m | 0.00 | Institutional seat |
| sh601318 Ping An | 56.63 | 3.12m | 0.00 | CITIC HQ (non-branch) |
How to read it: the Hengrui trade — 252m at an 8.01% discount — shows a clearly motivated seller, with the buyer a brokerage branch. That combination (large + deep discount) is worth a closer look (no directional conclusion — it just shows seller urgency).
6. Scanning in bulk (find large / deep-discount trades)
CODES = ["sh600519", "sh600276", "sh601899", "sz300750",
"sh601318", "sh600036", "sz000858", "sh600030"]
hits = []
for code in CODES:
b = requests.get(f"{BASE}/block-trade", params={"code": code},
headers=H, timeout=30).json()
if not b.get("ok"):
continue # no block trade that day
rows = b.get("data") or b.get("structured") or []
for x in rows:
amt = float(x.get("TurnoverValue") or 0)
dis = float(x.get("CloseDiscountRate") or 0)
if amt >= 1e8 or dis <= -5: # large or deep discount
hits.append((code, amt / 1e8, dis, x.get("BuySalesDepartment", "")))
for code, amt, dis, buyer in sorted(hits, key=lambda z: -z[1]):
print("%-10s %.2f bn rate %+.2f%% %s" % (code, amt, dis, buyer[:24]))- Large: value ≥ 100m CNY (big enough to shift the shareholder structure)
- Deep discount: rate ≤ -5% (clear seller concession)
- Combined: "large + deep discount + institutional buyer" is a relatively rare and informative mix
7. The date parameter (historical days)
`date=YYYY-MM-DD` queries a specific day — non-trading days fall back to the most recent trading day (measured: `2026-09-26`, a Saturday, returned `2026-09-24`).
b = requests.get(f"{BASE}/block-trade",
params={"code": "sh600276", "date": "2026-09-26"},
headers=H, timeout=30).json()
print(b["ok"], b.get("data"))- Measured: the first table (date / close and other meta) follows the date, falling back to the latest trading day
- Detail table behaviour: repeated queries returned the same trade details in our tests — either that stock had only one block, or the detail table only returns the latest. Verify with a sample whose days clearly differ before assuming multi-day history
8. Two common misreads (important)
- 1. `ok:false` does not mean the API is broken — it means no block trade for that stock on that day (a normal result). Most stocks have none on most days. To check the endpoint is fine, try a liquid large cap (e.g. `sh600519`)
- 2. A discount is not automatically bearish — large disposals need a discount to clear fast. "Has a discount" is normal; "unusually deep discount + institutional buyer" is what deserves attention
FAQ
No. It means no block trade for that stock that day. Block trades are not an everyday event for most stocks. Try a liquid large cap (e.g. sh600519) - if it returns data, the endpoint is fine.
Block trades are disclosed T+1. Our tests returned the latest disclosed trading day (the date field in the response tells you which day).
The closing price of the day. Positive = premium (buyer paid above market), negative = discount (seller conceded), 0 = flat. Discounts are the norm and not automatically bearish.
structured / tables are conditional fields - only attached when data is Markdown text. For block-trade, data is already an array (structured by nature), so the extra layer is unnecessary. Use body.get("structured") or branch on the data type.
Last updated: 2026-09-29
Field semantics from the endpoint docs and measured responses; sample data are live ashareapi /v1/block-trade responses (2026-09-29: Kweichow Moutai / Hengrui Pharma / Zijin Mining / CATL / Ping An); date behaviour verified across multiple dates including a weekend fallback.