Tutorial

A-Share Financial Red Flags: Finding Risk Signals with Data

Avoiding landmines beats picking winners: profits without cash, surging holder counts, large lock-up expiries — all visible in public data through four endpoints. This tutorial identifies risks only; it makes no recommendations.

Why check for landmines first

Before studying growth or valuation, confirm the company has no obvious red flags — do it in the wrong order and the rest of the analysis is wasted.

All four steps below use public filings and disclosure data and run through the API. No buy/sell advice is given; the goal is to surface risk signals.

Step 1: cross-check the statements (profit vs cash)

Python (key required)
import requests

KEY = "ct-your-key"
H = {"Authorization": "Bearer " + KEY}

r = requests.get("https://api.ashareapi.com/v1/finance",
                 headers=H, params={"code": "sh600667"}, timeout=20)
tabs = r.json()["data"]            # three tables: income / balance sheet / cash flow
names = ["income", "balance sheet", "cash flow"]
for name, tab in zip(names, tabs):
    latest = tab[0]                # periods are descending: first row is the latest
    print(name, latest["EndDate"], latest.get("OperatingRevenue"))
  • What to look at: net profit vs net operating cash flow — a persistent gap (high profit, chronically negative cash flow) is a classic signal
  • Look at multiple periods: seasonality distorts single quarters; use at least 4–8 periods (`num`)
  • Receivables growing faster than revenue: possibly buying revenue with looser credit

Step 2: shareholder counts (concentrating or dispersing)

Python
r = requests.get("https://api.ashareapi.com/v1/shareholder",
                 headers=H, params={"code": "sh600667"}, timeout=20)
print(r.json().get("structured") or r.json()["data"])
# Returns: top holders / shareholder count (with change %) / institutional holdings
  • Rising counts = dispersing (more retail, often high-level churn or institutional distribution)
  • Falling counts = concentrating (possible accumulation, or just deteriorating liquidity)
  • Read it with price position: falling counts at a low vs surging counts at a high mean opposite things

Step 3: events (lock-ups / reductions / dividends)

Python
# All event tags (42 types: lock-up / buyback / placement / dividend / results …)
r = requests.get("https://api.ashareapi.com/v1/events",
                 headers=H, params={"code": "sh600667"}, timeout=20)
print(r.json().get("structured") or r.json()["data"])

# Dividend history (continuity)
r = requests.get("https://api.ashareapi.com/v1/dividend",
                 headers=H, params={"code": "sh600667"}, timeout=20)
print(r.json().get("structured") or r.json()["data"])
  • Large lock-up expiries: the bigger the share of free float, the larger the potential supply
  • Dividend continuity: steady payers are not automatically good, but an abrupt stop deserves a question
  • Events are facts: a lock-up expiry is not a reduction — check announcements and actual filings

The four-step checklist

Four red flags is a different magnitude from one. Screening for landmines rules out extremes; it does not score stocks.

① Cross-check
Net profit vs operating cash flow
Persistent gap (profit without cash)
② Ownership
Shareholder count change
Surging counts at a high price
③ Events
Lock-up / reduction / placement
Large lock-up expiry near highs
④ Dividends
Continuity
Abrupt stop after years of paying

Common mistakes and boundaries

  • Calling negative cash flow fraud → growth-stage companies often have negative cash flow; check whether it matches revenue and capex
  • Concluding from one quarter → compare multiple periods (seasonality, one-offs)
  • Ignoring disclosure cadence → financials update on reporting dates; if a period has not been disclosed, there is no data (not an API problem)
  • Units → `amount` fields are generally in CNY; follow each field’s documentation
  • This is not investment advice → risk-signal identification only

FAQ

Do these endpoints need a key?

Yes, all of them. `/v1/finance`, `/v1/shareholder`, `/v1/events` and `/v1/dividend` are paid endpoints; the free five are quote, kline, hot, market overview and breadth.

Why is the latest report missing?

Financial data updates on disclosure dates, not in real time. If the company has not reported yet, that period simply does not exist — that is the reporting cadence, not an API issue. Use `/v1/calendar` to check the disclosure schedule.

How often do shareholder counts update?

They are disclosed in periodic reports (quarterly / semi-annual / annual), so updates are quarterly. Always check the report period behind "latest".

Is negative operating cash flow always a red flag?

No. A growing company investing heavily (inventory, receivables, capex) can run negative. Read it together with revenue growth, receivables growth and capex to tell expansion from cash that never comes back.

Can this data avoid every risk?

No. Public data only surfaces public signals (cross-check anomalies, lock-ups, holder-count shifts). Fraud or sudden operational accidents cannot be fully predicted. Screening rules out obvious anomalies; it does not guarantee safety.

Last updated: 2026-09-23

Code and fields come from live responses (verified 2026-09-25: finance returns three statement tables in descending period order, latest period 2026-06-30; shareholder returns 10 rows with holder counts; events returns 25 event types; dividend returns 3 records). Disclosure cadence and units follow the endpoint docs.