> Source: https://ashareapi.com/en/docs/guides/factor-screening/  ·  Markdown version for LLMs / AI agents

Guide

# Factor screening for China A-shares with one API call
 Factor screening turns financial and market metrics into conditions and filters the whole market. This guide covers three things: how to write the expression, how to read the result, and why you must run a data health check afterwards (otherwise it is easy to mistake an outlier for an opportunity).

## 1. What factor screening is (30 seconds)
 A **factor** is a computable metric: `PE_TTM` (price/earnings), `ROETTM` (return on equity), `DividendRatioTTM` (dividend yield), `DebtAssetsRatio` (debt ratio) and so on. **Factor screening** writes these into conditions and filters the whole market of 5,000+ stocks.
 It replaces manually reading financial statements — turning an idea like "cheap + profitable + low debt" into a reproducible, backtestable rule.

-
 **Reproducible**: the same conditions give the same result every time

-
 **Backtestable**: with `--date` you can screen on a past day variation of factor values

-
 **Not investment advice**: screening only filters by objective conditions — being selected does not mean you should buy

## 2. Quick start: one request for low-PE, high-ROE
 `/v1/screen` is a paid endpoint (needs a Key). The most common form is `expr` with a multi-factor intersection — `intersect([...])` means **all conditions must hold**.

 Python: PE between 0 and 20, ROE above 15%, sorted by ROE
```
import requests

BASE = "https://api.ashareapi.com/v1"
H = {"Authorization": "Bearer ct-your-key"} # Key: https://ashareapi.com/pricing

r = requests.get(
 f"{BASE}/screen",
 params={
 "expr": "intersect([PE_TTM > 0, PE_TTM < 20, ROETTM > 15])",
 "orderby": "ROETTM",
 "desc": "1",
 "limit": 5,
 },
 headers=H,
 timeout=30,
)
body = r.json()
if not body.get("ok"):
 raise RuntimeError(body) # upstream failure returns ok=false (not counted)

for row in body["structured"]: # structured = machine-readable rows
 print(row["code"], row["name"], row["PE_TTM"], row["ROETTM"])
```

-
 **`PE_TTM > 0` is a required guard** — loss-making companies have negative PE and would otherwise appear as "low PE"

-
 **Percentage factors take plain numbers**: `ROETTM > 15` means "above 15%" (not `0.15`)

-
 **Values are strings** ("14.33") — call `float()` before arithmetic

## 3. What the result looks like (live run, 2026-09-29)
 Real output of the request above (limit=5); `structured` is the machine-readable form:
 |
| | code | name | PE_TTM | ROETTM | ClosePrice | ChangePCT

| | sz000656 | Jinke Property | 0.36 | 883.0546 | 1.25 | 3.31

| | sz300972 | Wanchen Group | 14.33 | 77.2634 | 151.22 | -2.81

| | sh600132 | Chongqing Brewery | 15.54 | 73.3501 | 37.30 | -0.80

| | sh688331 | RemeGen | 11.28 | 70.0198 | 116.31 | 0.84

| | sz001309 | Demingli | 12.32 | 69.7845 | 370.69 | -0.16

 sz000656
 Jinke Property
 0.36
 883.0546
 1.25
 3.31

 sz300972
 Wanchen Group
 14.33
 77.2634
 151.22
 -2.81

 sh600132
 Chongqing Brewery
 15.54
 73.3501
 37.30
 -0.80

 sh688331
 RemeGen
 11.28
 70.0198
 116.31
 0.84

 sz001309
 Demingli
 12.32
 69.7845
 370.69
 -0.16

 **Do not celebrate yet** — the first row (PE_TTM=0.36, ROETTM=883%) is exactly the kind of value you need to inspect. The next section shows how.

## 4. The 3-step data health check (important)
 **A factor value is a number a machine computed — not the company true operating picture.** When you see extremes (very low PE, very high ROE, huge growth), cross-check with other fields from the same financial statement:

 Python: health-check screened names (ex-non-recurring / multi-metric / leverage)
```
def health_check(code: str) -> None:
 # Inspect factor values: multi-metric ROE, ex-non-recurring, leverage, current profit
 r = requests.get(f"{BASE}/finance", params={"code": code, "limit": 1},
 headers=H, timeout=30)
 tables = r.json()["data"] # 3 tables: income / balance sheet / cash flow
 income, balance = tables[0][0], tables[1][0]

 print(code)
 print(" ROE variants:", income.get("ROE"), "/", income.get("ROETTM"),
 "/", income.get("ROEWeighted"), "/ ex-non-recurring", income.get("ROECut"))
 print(" Profit current:", income.get("NPParentCompanyOwners"),
 " TTM:", income.get("NPParentCompanyOwnersTTM"))
 print(" Debt ratio:", balance.get("DebtAssetsRatio"), "% equity:",
 balance.get("TotalShareholderEquity"))

 try:
 if float(income.get("ROECut") or 0) < 0:
 print(" [!] ex-non-recurring ROE is negative - profit may be non-recurring")
 if float(balance.get("DebtAssetsRatio") or 0) > 70:
 print(" [!] debt ratio above 70% - ROE may be leveraged")
 except (TypeError, ValueError):
 pass

health_check("sz000656")
```

-
 **1) Check ex-non-recurring**: `ROECut` and `NPDeductNonRecurringPL`. If `ROETTM` is high but `ROECut` is negative, profit likely comes from non-recurring items (asset sales, debt restructuring), not the core business

-
 **2) Check multi-metric consistency**: the same statement carries `ROE` / `ROETTM` / `ROEWeighted` / `ROECut`. If they differ by orders of magnitude (e.g. 0.44 vs 883), one of them is distorted — do not use it directly

-
 **3) Check leverage and the current period**: `DebtEquityRatio` / `DebtAssetsRatio` (leverage inflates ROE) plus `NPParentCompanyOwners` (current-period profit). If TTM profit is far from the current period, the TTM value is suspect

## 5. Real case: what that 883% ROE actually is
 The screened name sz000656 Jinke Property (PE_TTM 0.36 / ROETTM 883%) — one health check reveals the problem. From the same statement:

-
 **The verdict is not a hunch**: within one statement, ROE=0.44 vs ROETTM=883 (~2000x), ex-non-recurring is negative, and TTM vs current profit diverge — **the bases contradict each other**, so this ROETTM should not be used as-is

-
 **Correct handling**: this does not mean "the stock is bad", it means "**this factor value is unreliable**" — switch basis (use `ROECut`) or skip it

-
 **This is exactly why the check is mandatory**: the API faithfully returns every basis; whether to exclude is a rule the consumer applies (we give no buy/sell conclusions)

 |
| | Field | Value | Meaning

| | ROETTM | 883.05 | The one used by the screener (extremely high)

| | ROE | 0.44 | Same metric, different basis (~2000x apart)

| | ROECut | -1.71 | Ex-non-recurring ROE (negative = core loss)

| | NPParentCompanyOwnersTTM | 36.87 bn CNY | Net profit TTM

| | NPParentCompanyOwners | 0.019 bn CNY | Current-period profit (far from TTM)

| | DebtEquityRatio | 200.67% | Debt-to-equity (high leverage)

| | ClosePrice | 1.25 CNY | Share price (near par value)

 ROETTM
 883.05
 The one used by the screener (extremely high)

 ROE
 0.44
 Same metric, different basis (~2000x apart)

 ROECut
 -1.71
 Ex-non-recurring ROE (negative = core loss)

 NPParentCompanyOwnersTTM
 36.87 bn CNY
 Net profit TTM

 NPParentCompanyOwners
 0.019 bn CNY
 Current-period profit (far from TTM)

 DebtEquityRatio
 200.67%
 Debt-to-equity (high leverage)

 ClosePrice
 1.25 CNY
 Share price (near par value)

## 6. Common factors cheat sheet
 |
| | Group | Factor | Meaning | Unit

| | Valuation | PE_TTM | Price/earnings TTM (needs > 0) | x

| | Valuation | PB | Price/book (no PB_TTM) | x

| | Valuation | PS_TTM | Price/sales TTM | x

| | Valuation | TotalMV | Total market value | CNY

| | Valuation | DividendRatioTTM | Dividend yield TTM | %

| | Profitability | ROETTM | Return on equity TTM | percent

| | Profitability | ROECut | Ex-non-recurring ROE (health check) | percent

| | Profitability | GrossIncomeRatioTTM | Gross margin TTM | percent

| | Growth | NPParentCompanyYOY | Net profit YoY | %

| | Growth | OperatingRevenueGrowRate | Revenue growth | %

| | Leverage | DebtAssetsRatio | Debt-to-assets | %

| | Leverage | DebtEquityRatio | Debt-to-equity | %

| | Cash flow | NetOperateCashFlowTTM | Operating cash flow TTM | CNY

 Valuation
 PE_TTM
 Price/earnings TTM (needs > 0)
 x

 Valuation
 PB
 Price/book (no PB_TTM)
 x

 Valuation
 PS_TTM
 Price/sales TTM
 x

 Valuation
 TotalMV
 Total market value
 CNY

 Valuation
 DividendRatioTTM
 Dividend yield TTM
 %

 Profitability
 ROETTM
 Return on equity TTM
 percent

 Profitability
 ROECut
 Ex-non-recurring ROE (health check)
 percent

 Profitability
 GrossIncomeRatioTTM
 Gross margin TTM
 percent

 Growth
 NPParentCompanyYOY
 Net profit YoY
 %

 Growth
 OperatingRevenueGrowRate
 Revenue growth
 %

 Leverage
 DebtAssetsRatio
 Debt-to-assets
 %

 Leverage
 DebtEquityRatio
 Debt-to-equity
 %

 Cash flow
 NetOperateCashFlowTTM
 Operating cash flow TTM
 CNY

 All 85 factors (6 valuation / 2 market / 38 profitability / 32 balance sheet / 14 cash flow) and 14 templates — see "Expression syntax and factor dictionary".

## FAQ
 Can I buy directly from screening results?
 No. Screening only filters the market by objective conditions; being selected means "meets the rule", not "worth buying". It replaces the first step of manual statement reading. This guide only covers data retrieval and verification, not investment advice.

 Why do I get extremely low PE and extremely high ROE?
 Extremes often come from basis issues. Cross-check with ROECut (ex-non-recurring), other ROE bases, and DebtEquityRatio (leverage) from the same statement. When bases contradict, the factor value is not usable. Sections 4-5 give the full method and a real case.

 Is screening available on the free tier?
 No, /v1/screen is a paid endpoint. The 5 free endpoints are quote / kline / hot / market-overview / changedist — use those to verify connectivity first.

 Why are numeric fields strings?
 To avoid losing precision. Call float() before comparing or calculating; direct addition concatenates strings.

 Last updated: 2026-09-29
 Field list and strategies taken from live responses of ashareapi /v1/screen and /v1/finance (verified 2026-09-29); factor semantics and the health-check method come from measured verification (85 factors, 2026-08-31).

 Related

-
[Expression syntax & factor dictionary](/en/docs/guides/screen-expressions)

-
[22 ready-made screening strategies](/en/docs/guides/stock-screening-strategies)

-
[Value investing screening & outlier checks](/en/docs/guides/value-stock-screening)

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

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