> Source: https://ashareapi.com/en/docs/guides/block-trade-signals/  ·  Markdown version for LLMs / AI agents

Guide

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

 Python: block trades for one stock
```
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

 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

 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)

 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)

 Python: scan a list, pick out large or 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`).

 Python: query a specific date
```
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
 It returns ok:false with an empty array - is the API broken?
 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.

 Is the data real-time?
 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 discount rate is relative to what?
 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.

 Why is structured null?
 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.

 Related

-
[Endpoint reference (block-trade)](/en/docs/endpoints/block-trade)

-
[Money flow in one endpoint: fund](/en/docs/endpoints/fund)

-
[Factor screening basics (incl. health check)](/en/docs/guides/factor-screening)

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

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