SuperAPI AI Directory

ashare-pre-st-filter

General & other

View repository

Updated 10-15 22:13

About this skill

Dependencies: This skill must be used in conjunction with tushare skill , and when data is missing, fall back to akshare skill。

A-share ST/*ST risk prediction

Scope of application

  • A-shares onlyMain Board / ChiNext / STAR Market. Hong Kong stocks, US stocks, crypto, commodities,Beijing Stock Exchange(8xxxxx.BJ whose regulatory rules are inconsistent with this skill's thresholds) are all not applicable, and this skill directly refuses.
  • Only makes forward-looking predictions of "whether it will be ST/*ST in the next fiscal year," and does not predict financial fraud.
  • Outputs a dual-axis result:Threshold-triggering risk level + Prediction credibility。

Trigger conditions

User questions in the form of:

  • "Analyze the ST risk of 000729.SZ"
  • "Will 600xxx be ST at the next annual report"
  • "Help me check whether 300xxx has delisting risk"

When receiving such requests, execute according to the "Analysis Process" below; do not proactively enable this skill in other scenarios.

Data acquisition specification (tushare priority → akshare fallback)

Iron rule:

  1. All financial/fundamental/dividend/audit/ST status data must first call tushare skill, using the interface names specified in the table below,ts_code、period to fetch.
  2. When the tushare interface returns empty due to insufficient points, missing token, orfall back to akshare skill the corresponding function.
  3. akshare fallback data must be explicitly noted in the "Remarks" of the final output:数据源:akshare(非官方聚合,不保证完整性,建议核对原始公告)。It is not allowed to give a "high credibility" prediction using only akshare— the credibility of red-line items sourced from akshare fallback is mandatorily lowered by one level (high→medium-high, medium-high→medium, medium→low).
  4. Regulatory penalties (E2) use this skill's built-in scripts/fetch_sina_penalties.py, and do not go through tushare/akshare.

Data requirement mapping table

Data requirement tushare interface (preferred) Fetch parameters / time window akshare fallback akshare notes
Current ST status stock_st Most recent trading day stock_zh_a_st_em() Only returns the current ST/delisting consolidation board list; history is not queryable
Historical name changes namechange ts_code full history stock_zh_a_new_em()(new stocks only, no name changes) akshare has no complete name-change interface; skip if necessary
Stock basic information (board determination) stock_basic list_status='L' stock_individual_info_em(symbol) Field names differ, mapping must be done manually
Earnings forecast forecast ts_code + the most recent 2 periods ({Y}0630/{Y}0930/{Y}1231) stock_yjyg_em(date='YYYYMMDD') Look up by report period date; must first pull the whole market by period and then filter by ts_code
Earnings flash report express Same as above, the most recent 2 periods stock_yjbb_em(date='YYYYMMDD') Same as above, whole-market snapshot needs filtering
Income statement income ts_code + the most recent 5 periods (annual reports for the past 4 years {Y}1231 + the latest interim/third-quarter report) stock_financial_report_sina(stock='sh600000', symbol='利润表') Units are inconsistent (ten thousand yuan vs yuan), normalization is required; missing quarterly reports are common
Balance Sheet balancesheet Same as above stock_financial_report_sina(stock='sh600000', symbol='资产负债表') Same as above
Cash Flow Statement cashflow Same as above stock_financial_report_sina(stock='sh600000', symbol='现金流量表') Same as above
Financial Indicators (Net profit excluding non-recurring items, etc.) fina_indicator ts_code + most recent 5 periods stock_financial_analysis_indicator(symbol='600000') Field names in Chinese; the non-recurring-excluded field is named "Net profit after deducting non-recurring gains and losses"
Audit Opinion fina_audit ts_code + most recent 2 annual report periods akshare has no corresponding interface When missing, annotate "Audit opinion data missing" in the output,must not skip——must prompt the user to check the official website
Dividends dividend ts_code + most recent 5 years div_proc='实施' stock_history_dividend_detail(symbol='600000', indicator='分红') Field names in Chinese; need to multiply the "dividend" amount × total share capital to get the total cash dividend
Daily quotes (1 yuan delisting warning) daily ts_code + most recent 30 trading days stock_zh_a_hist(symbol='600000', period='daily', adjust='') Must useunadjustedprice to judge the 1 yuan delisting line
Daily indicators (market value) daily_basic ts_code + most recent trading day stock_zh_a_spot_em() Full-market snapshot filter 代码=600000 Field name is "Total market value" (Unit: yuan, Eastmoney push2 original specification, akshare does not rescale); to convert to 100 million yuan, need /1e8. ⚠️ Do not confuse with tushare daily_basic.total_mv(10 thousand yuan)——this column is the akshare fallback specification
Financial report disclosure date disclosure_date ts_code + current year akshare has no corresponding interface When missing, estimate based on experience (4/30 annual report, 8/31 interim report, 10/31 third-quarter report)
Regulatory penalties — — Use this skill's built-in sina script See section E2

Unified time window specifications

Handle separately by data type,do not use a single 60-day empirical value to uniformly align:

  • Financial statements (income / balancesheet / cashflow / fina_indicator): based on disclosure_date actual announcement date; when this interface is unavailable, use the statutory deadlines (annual report 4/30, interim report 8/31, third-quarter report 10/31, first-quarter report 4/30) as fallback. Only from announcement date +1 day can this period be regarded as "latest available".
  • "Past N years' annual reports": always period = {Y}1231, do not use calendar year start and end.
  • Earnings forecast forecast / earnings express express: only take ann_date ≥ 当前年度 1 月 1 日 records; sort by ann_date in descending order and take the latest one; forecasts from old periods are invalid for prediction.
  • dividend: by (end_date, ann_date, cash_div_tax) tripleforced deduplication——the same dividend in tushare will appear in 3-4 rows (proposal/shareholders' meeting approval/implementation); directly summing will cause triple miscalculation.

Step 1: Current status check (M0)

Determine whether the company is currently under risk warning, and adjust the analysis direction accordingly (do not end with a one-size-fits-all approach):

Call order:

  1. Prioritize calling stock_st(tushare skill, 3000 points), query by the current most recent trading day; record type / type_name。
  2. If points are insufficient, fall back to namechange(free): fetch ts_code all historical name change records, take by start_date the latest sorted item; determine name prefix.
  3. Use stock_basic.name as a fallback to confirm the name.

Branch handling:

Current status Analysis direction Whether to continue
Normal stock Predict whether it will be ST/*ST in the next fiscal year Yes(default process)
Already ST (ordinary) Change to predicting: whether it will further become *ST or be delisted; the R1-R4 thresholds need to be stricter (the loss chain threshold is lowered by one year) Yes
Already *ST Change to predicting: whether it will be forcibly delisted; focus on R1 revenue + R2 net assets + E1 audit opinion Yes
Already in delisting consolidation period / already delisted End directly No

Step 2: Board threshold table (determines the red line)

First use the ts_code prefix to determine the board, then apply the corresponding thresholds. Do not mix them.

Board Code identification Revenue red line Market cap delisting line Three-year cumulative dividend threshold
Main Board 60xxxx.SH / 00xxxx.SZ(except those starting with 30 / 688) Net profit is negative and revenue < 300 million Market cap < 500 million Cumulative < 50 million and < 30% of average annual net profit
ChiNext 30xxxx.SZ Net profit is negative and revenue < 100 million Market cap < 300 million Cumulative < 30 million and < 30% of average annual net profit (R&D exemption: R&D investment accounts for ≥ 5% of revenue or cumulative over the past three years ≥ 60 million)
STAR Market 688xxx.SH Net profit is negative and revenue < 100 million Market cap < 300 million Cumulative < 30 million and < 30% of average annual net profit (R&D exemption: R&D investment accounts for ≥ 5% of revenue or cumulative over the past three years ≥ 60 million)

Step 3: Forecast point-in-time selection

Determine the baseline point in time according to the "latest available evidence" principle, selecting the best from bottom to top:

Baseline point in time Data interface Credibility baseline Applicable season
Earnings forecast forecast forecast High Late January / mid-July / late October peak period
Earnings express express express High January-April, before the annual report
Third-quarter report income/balancesheet/cashflow (period=YYYYMMDD, end of September) Medium-high After disclosure in late October until the next year's annual report
Interim report Same as above, end of June period Medium After disclosure in late August until the third-quarter report
Last year's annual report Same as above, end of December period Low Only used as a baseline reference

Evidence priority(when there are multiple sources for the same indicator, the higher one overrides the lower one):

forecast / express > 三季报 > 中报 > 去年年报 > 经验外推

When outputtingyou must explicitly state for each forecast item which level of evidence was used. If there is a full-year net profit range given by forecast,it is prohibited to mechanically annualize and override it using the third-quarter report。

Step 4: Four Predictable Red Lines

R1 Revenue + Net Profit Red Line

Objective: Predict full-year revenue, net profit attributable to the parent, andnet profit excluding non-recurring items, and judge using the regulatory standard of "the lower of the two, before and after excluding non-recurring items."

Key to the standard: The original regulatory text is min(n_income, profit_dedt) < 0 and revenue < 板块阈值 —— must also predict net profit excluding non-recurring items, and cannot use only the parent-attributable figure. Looking only at the parent-attributable figure would miss shell companies where "the parent-attributable figure is positive but the ex-non-recurring figure is negative."

Forecasting Methods (choose according to the base time point, at least one):

  • forecast direct extraction method: If forecast provides net_profit_min / net_profit_max, directly take the range as the full-year parent-attributable forecast; for the ex-non-recurring figure, convert using the ex-non-recurring rate from the past two years (the median ofprofit_dedt / n_income ); credibility = high. The revenue red line still needs to be extrapolated in combination with the latest financial statements.
  • express direct extraction method: If express has already been disclosed,revenue / n_income is the full-year express report value; the ex-non-recurring figure is likewise converted using the rate from the past two years (express reports generally have no ex-non-recurring field); credibility = high.
  • Q4 single-quarter recovery method(Q3 report base):
    • Q1Q3_revenue = operating revenue in the Q3 report
    • Q4_revenue_est = median of Q4 revenue as a proportion of full-year revenue in the past two years × current annualized estimate
    • revenue_full_year_est = Q1Q3_revenue + Q4_revenue_est
    • n_income / profit_dedt handled the same way
    • credibility = medium-high
  • H2 scenario extrapolation method(interim report base, mandatory for strongly seasonal companies):
    • Take the average of H2 revenue as a proportion of full-year revenue in the past two years, and give pessimistic/base/optimistic scenarios
    • revenue_full_year_est = H1_revenue / H1_share_avg
    • credibility = medium
  • Year-on-year continuation method(interim report base, usable for weakly seasonal companies):
    • revenue_full_year_est = H1_revenue × (last_year_full_revenue / last_year_H1_revenue)
    • credibility = medium

Prohibited: Directly multiplying H1 by 2, directly multiplying Q1-Q3 by 4/3. Any mechanical annualizationmust be downgraded to "low" credibilityand noted in the output.

Threshold breach determination(standard:worst_profit = min(n_income_est, profit_dedt_est)):

  • High risk:worst_profit < 0 and revenue_est < 板块阈值
  • Medium risk:worst_profit < 0 but revenue meets the standard; or revenue is close to the threshold (< threshold × 1.2)
  • Low risk: none of the above are met

Explanation of coefficients: In R1, the 1.2 for medium risk is a warning buffer for the forecast item (the forecast itself has error and requires a narrow buffer); in R4, the 1.5 for high risk is a buffer for the two-year linkage determination (only when both years are losses and revenue is close to the threshold is it a true delisting signal, requiring a wide buffer). The two coefficients are intentionally different,do not incorrectly unify them。

R2 Year-end Net Assets Red Line

Objective: Determine whether year-end parent-attributable shareholders' equity may turn negative.

Method:

  1. Take the latest period balancesheet.total_hldr_eqy_exc_min_int(latest interim report or Q3 report), denoted as current_eq。
  2. Calculate eq_year_end_est = current_eq + 剩余季度净利润预测 − 当前年度已实施现金分红总额。
    • remaining-quarter net profit: for the interim report base, use R1's H2 forecast; for the Q3 report base, use R1's Q4 forecast.
    • Total dividends already implemented: see R3's deduplication + dimensional formula cash_div_tax / 10 × total_share。

Threshold breach determination(unified relative threshold, unit: yuan):

  • High risk:current_eq < 0 or eq_year_end_est < 0
  • Medium risk:0 ≤ eq_year_end_est < 1e8(100 million yuan)
  • Low risk:eq_year_end_est ≥ 1e8

Note: Goodwill impairment and long-term equity investment impairment are recognized in a concentrated manner in Q3/Q4, and a note should indicate "if a large impairment is recognized, net assets may decline further", butimpairment must not be recognized without the basis of an announcement。

R3 Dividend Compliance Outlook

Objective: Determine whether "cumulative cash dividends over the past three years < 30% of average annual net profit and < the cumulative threshold for the board" will both be met at the next annual assessment (regulatory text: the two conditionssimultaneouslytrigger a warning only if met).

Single Dividend Amount Dimensional Formula(This formula must be used, do not use cash_div_tax × base_share):

cash_dividend_total = cash_div_tax / 10 × total_share

where cash_div_tax comes from dividend(cash amount per 10 shares, tax included),total_share comes from daily_basic.total_share(latest total share capital, in ten thousand shares → needs ×1e4 to convert to shares) or stock_basic。tushare dividend.base_share field is None for many companies,direct use is prohibited。

Method:

  1. Use dividend to pull the ts_code records for the past five years, by the (end_date, ann_date, cash_div_tax) triplemandatory deduplication—tushare returns 3-4 rows for the same dividend: "proposal/shareholders' meeting approved/implemented".
  2. Conversion coefficient (by div_proc status):实施=1.0 / 股东大会通过=0.7 / 预案=0.5; for the same end_date take the row with the highest coefficient.
  3. Use income to pull the full-year net profit attributable to the parent for the past three years (period=YYYY1231).
  4. Calculation assessment window = [当前年-2, 当前年], i.e. "dividends already implemented in the past two years + estimated dividends for the current year".
  5. Estimated dividends for the current year:
    • If dividend a current-year record has been found: include it according to the conversion coefficient above.
    • Otherwise use "average dividend payout ratio over the past two years" × R1 forecast full-year net profit (base scenario) for estimation, and lower the confidence by one level.
  6. Compare with average annual net profit:
    • Condition A:cumulative_div_3y < 30% × avg_n_income_3y
    • Condition B:cumulative_div_3y < 板块累计阈值
  7. For ChiNext / STAR Market, if the R&D investment ratio meets the exemption conditions, note "meeting R&D requirements may exempt".

Threshold Breach Determination:

  • High risk: A and B are met simultaneously and net profit was positive in at least one of the past three years (i.e. "failed to meet the standard in a profitable year"—regulation uses profitable years as the benchmark).
  • Medium risk: only one condition is met; or dividends for the current year have not yet been announced.
  • Low risk: cumulative dividends have steadily met the standard; or cumulative net profit over the past three years ≤ 0 (no basis for dividends, linked per R1).

Prohibited: when dividends for the current year have not yet been announced, do not assert "certainly will not meet the standard"; only give a probability.

R4 Consecutive Losses / Non-Recurring Loss Chain

Objective: Determine whether it will trigger "the lower of net profit before and after non-recurring items is negative for two consecutive years" → *ST.

Key Scope: the regulatory text istwo consecutive years(not three years), and the statutory condition for *ST financial mandatory delisting is "loss + revenue < board threshold" must be met simultaneously—looking only at the loss chain will systematically overestimate risk (empirical example: Wingtech Technology lost money in 2024 but had revenue of over one hundred billion, so it will not be *ST).

Method:

  1. Take the n_income、fina_indicator.profit_dedtfrom the last full annual report, record worst_last = min(n_income, profit_dedt)、revenue_last。
  2. Using the worst_profit_est and revenue_full_year_estalready predicted by R1 (baseline scenario), corresponding to the current year.
  3. Check the two-year worst < 0 combination,and overlay the revenue linkage condition。

Threshold-line determination(dual condition, loss chain + revenue linkage):

  • High risk:worst_last < 0 and worst_profit_est < 0,and(R1 current year hits high risk or revenue_full_year_est < 板块阈值 × 1.5) — i.e., losses in both years + revenue in the delisting risk range.
  • Medium risk: (a) losses in two consecutive years but revenue far above the threshold (≥ threshold × 1.5) — the loss chain holds but financial-category *ST would not be triggered, though ST may still result from deteriorating operations; (b) only worst_profit_est < 0(current year forecast loss, profitable last year, no consecutive losses formed); (c) only worst_last < 0 but the current year is forecast positive and close to 0 (< board threshold × 0.5).
  • Low risk:worst_last ≥ 0 and worst_profit_est ≥ 0。

Why overlay revenue: The statutory condition for A-share *ST financial-category mandatory delisting is "net profit before and after non-recurring items, whichever is lower < 0 and revenue < board threshold", both of which must be satisfied simultaneously. A company with only losses that does not reach the revenue threshold (such as a large cyclical stock with short-term losses) would be regarded by the market and regulators as a "cyclical loss" rather than "going-concern doubt".

Step 5: Three factual/critical evidence surfaces (not involved in forecast credibility)

E1 Audit opinion (fact)

Call fina_audit, take the most recent 2 complete annual reports:

  • High risk: the latest annual report audit_result contains a "disclaimer of opinion" or "adverse opinion";or a single occurrence of a "qualified opinion"(empirically supported: recent SSE regulatory-category *ST cases mostly triggered by a single qualified opinion).
  • Medium risk: the same negative conclusion for two consecutive years but corrected in the current period; or an unqualified opinion with an emphasis of matter paragraph involving going concern.
  • Low risk: standard unqualified opinion.

Predicting the next audit opinion is prohibited— auditing is an ex-post act.

Manual verification path when akshare fallback is missing(fina_audit has no akshare substitute interface, a clickable URL must be given):

Source URL template Query method
CNINFO (original announcements, authoritative) http://www.cninfo.com.cn/new/disclosure/stock?orgId=&stockCode={code6} After entering the page, filter "Periodic Reports → Annual Reports", download the PDF and check 审计意见类型
CNINFO advanced search (by keyword) http://www.cninfo.com.cn/new/fulltextSearch/full?searchkey={code6}+审计报告&sdate=&edate=&isfulltext=false&sortName=time&sortType=desc Directly hits announcements with "audit report" in the title
SSE information disclosure http://www.sse.com.cn/disclosure/listedinfo/regular/?stockCode={code6} Limited to 60xxxx / 688xxx
SZSE information disclosure http://www.szse.cn/disclosure/listed/notice/index.html?stock={code6} Limited to 00xxxx / 30xxxx

Where {code6} is the 6-digit stock code (remove the .SH / .SZ suffix).Mandatory requirement: when fina_audit returns empty, the "Remarks" of the output report must list one of the two CNINFO URLs above, to facilitate the user's manual verification; it must not merely write "audit opinion data missing".

E2 Regulatory penalties (fact, dual window: previous fiscal year + past 12 months)

This is the key evidence surface of this skill.

Window rules (dual-window strategy, single fetch sliced in memory):

  • Window A — [当前年-1 的 1 月 1 日, 当前年-1 的 12 月 31 日](the last complete fiscal year): used for reason_normalized single-record rating.
  • Window B — [分析日 - 365 天, 分析日](trailing 12 months): used forfrequency enhancement rule。
  • If the analysis point in time is already after May and the latest annual report has been fully disclosed, Window A may be changed to [最新年报 end_date - 365 天, 最新年报 end_date]。

Call method (recommended: single full fetch + in-memory slicing):

python agent/src/skills/ashare-pre-st-filter/scripts/fetch_sina_penalties.py \
  --ts-code 000729.SZ --stock-name 燕京啤酒 --no-filter

After the full page records are returned, the LLM slices two copies in memory by Window A and Window B. You can also use --start-date / --end-date to fetch separately, but within the same analysisavoid issuing two HTTP requests。

Output a JSON list, fields:ann_date / event_type / title / reason / reason_normalized / content / issuer / issuer_normalized / subject_normalized / target_relevance / e2_countable / source_url。

Ironclad relevance rule: when calling the script, you must pass --stock-name {股票简称}(from stock_basic.name), and if necessary use --alias to supplement former names/abbreviations. Sina pages may include records of "the target stock appearing in some person's securities account trading list"; such records only indicate that the target stock was traded,not a penalty on the listed company/shareholder/director, supervisor, or senior manager. The script will mark them as target_relevance=security_mention_only and e2_countable=false, and E2 frequency statistics must exclude them.

subject_normalized field(used for frequency weight conversion):

  • company — the penalized subject is the company itself (default; classified here when no personal-identity keyword is present)
  • shareholder — controlling shareholder / actual controller / shareholder holding 5% or more
  • officer — director / supervisor / senior manager (chairman, general manager, board secretary, CFO, etc.)

Risk level determination:

Hit reason_normalized Level contribution
Financial fraud / false statements / information disclosure violations High (strong warning)
Illegal guarantees / misappropriation of funds High (directly touches the ST red line)
Insider trading / market manipulation / illegal share reduction Medium
Other/unknown Low (background only)

Frequency enhancement rule (governance quality warning, Window B):

Regulatory letters themselves reflect corporate governance and internal control quality, and dense occurrences are a strong leading indicator of "compliance-category ST" (qualified opinion, non-standard internal control, major information disclosure defects). However,different penalized subjects have different governance implications: shareholder share-reduction violations and short-swing trading by directors, supervisors, and senior managers reflect personal compliance issues and should not be equated with "corporate governance disorder".

Subject-weighted count(after conversion by subject_normalized , then look up the table):

加权条数 = Σ 单条权重
  其中:subject_normalized == "company"     → 权重 1.0
        subject_normalized == "officer"     → 权重 0.5
        subject_normalized == "shareholder" → 权重 0.5
Regulatory letters/inquiries/warning letters in the past 12 monthsWeighted count Frequency level
≥ 5.0 Extremely high
3.0 - 4.5 High
2.0 - 2.5 Medium
< 2.0 Low

Determination source: only when e2_countable=true , the event_type ∈ {警示, 问讯, 监管关注, 监管函} or issuer_normalized ∈ {上交所, 深交所, 北交所, 证监会, 地方证监局} output by the script is counted toward the count; the count is converted by subject_normalized before looking up the table.target_relevance=security_mention_only records must be excluded.

Output requirement: both the "raw count" and the "weighted count" must be given, so the user can review the conversion logic. For example:窗口 B 命中 6 条(公司 2 条 + 股东 3 条 + 高管 1 条 → 加权 4.0 条),频次等级:高。

E2 composite level synthesis rule(Resolving the issue of a single rating overlapping with frequency):

E2_单条等级 = 窗口 A 内所有 reason_normalized 单条等级的最大值
E2_频次等级 = 窗口 B 频次表查得
E2_综合等级 = max(E2_单条等级, E2_频次等级)

Overlay bonus: if both E2_频次等级 ≥ 高 and E2_单条等级 ≥ 高are satisfied (including financial fraud/false statements/illegal guarantees/misappropriation of funds) → directly elevated to extremely high。

Why this rule is needed: purely quantitative red lines can only capture "financial ST" and cannot provide early warning of "regulatory ST". The frequency rule incorporates "governance disorder" as a forward-looking signal.

Note: penalty evidenceonly raises the risk level and does not affect forecast credibility—this is factual evidence, not a forecast item.

E3 Trading-Related Critical Early Warning (Fact)

Call daily(last 30 trading days,must adjust='' be unadjusted) and daily_basic(latest day, unit: ten thousand yuan):

1 yuan delisting warning(using daily.close,unadjusted):

  • High risk: in the last 20 trading days, the number of days with a closing price < 1 yuan is ≥ 10
  • Medium risk: ≥ 1 but < 10
  • Low risk: 0 days

Market value delisting warning(using daily_basic.total_mv, unit ten thousand yuan → ×1e4 converted to yuan → /1e8 converted to hundred million yuan):

Board High-risk threshold Medium-risk threshold
Main board < 500 million < 5 × 1.5 = 750 million
ChiNext / STAR Market < 300 million < 3 × 1.5 = 450 million

Step 6: Dual-Axis Output Template

Each analysis must be output according to the template below.Both dimensions must be given: risk level + credibility。

## ST 风险预测:{name}({ts_code})

### 当前状态
- 是否已 ST/*ST:{是 / 否}
- 板块:{主板 / 创业板 / 科创板}
- 基准预测时点:{forecast / express / 三季报(period) / 中报(period)}

### 量化红线预测(双轴)

| 红线 | 基准情景结论 | 风险等级 | 可信度 | 主要证据 |
|------|-------------|---------|-------|---------|
| R1 营收+净利润 | 全年营收预测 X 亿,净利润 Y 亿 | 高/中/低 | 高/中高/中/低 | forecast/三季报/... |
| R2 年末净资产 | 当前 X 亿,年末预计 Y 亿 | 高/中/低 | 高/中高/中/低 | balancesheet + R1 |
| R3 分红达标 | 三年累计预计 X,对应阈值 Y | 高/中/低 | 中/低 | dividend + income |
| R4 连续亏损链 | 过去两年 + 当前年是否均亏 | 高/中/低 | 同 R1 | income + fina_indicator |

### 事实证据面(不参与预测可信度)

| 证据 | 结论 | 影响 |
|------|------|------|
| E1 审计意见 | 最新结论 | 抬升/无影响 |
| E2 监管处罚(窗口 A 上一财年 / 窗口 B 过去 12 个月) | A 命中 Na 条(最高单条等级:…),B 原始 Nb_raw 条 / 加权 Nb_w 条(公司 a + 股东 b + 高管 c → a×1.0+b×0.5+c×0.5),频次等级:…,E2_综合等级:… | 抬升/无影响 |
| E3 交易类临界 | 收盘价/市值情况 | 抬升/无影响 |

### 综合结论
- **下一财年被 ST/*ST 风险等级**:{极高 / 高 / 中 / 低}
- **预测综合可信度**:{高 / 中高 / 中 / 低}
- **关键风险点**(最多 3 条):...
- **缓解信号**(如有):...

### 备注
- 数据时点:{所用最新报告期}
- 已忽略的不可预测项:财务造假、未来审计意见
- 季节性提醒(如适用):...

Prohibitions

  1. Do not predict financial fraud (unknowable in advance).
  2. Do not predict the next audit opinion (it is issued only after the fact).
  3. Do not arbitrarily recognize impairment without announcement-based grounds.
  4. Do not mix board thresholds (the revenue/market value/dividend thresholds differ between the main board and ChiNext/STAR Market).
  5. Do not disguise mechanical annualization (H1×2, Q1Q3×4/3) as "high credibility".
  6. Do not enable this skill on Hong Kong stocks / U.S. stocks / crypto / Beijing Stock Exchange(8xxxxx.BJ, where regulatory rules are inconsistent with this skill's thresholds).
  7. Do not count "violation penalty records" toward forecast credibility (they only raise the risk level).
  8. Do not use cash_div_tax × base_sharein the R3 dividend calculation (base_share is often None, which would yield 0); you must use cash_div_tax / 10 × total_share, and deduplicate by the (end_date, ann_date, cash_div_tax) triple.
  9. Do not use only n_incomein R1 threshold determination; you must use min(n_income, profit_dedt), otherwise shell companies will be missed.
  10. Do not write R4 as "three consecutive years"; the regulatory text says "two consecutive years".And R4 high risk must be overlaid with the revenue linkage condition—"two consecutive years of losses" alone does not constitute *ST financial mandatory delisting; it must also satisfy "revenue < board threshold × 1.5" or R1 has already hit high risk, otherwise only medium risk can be given.
  11. Do not count E2 regulatory penalties "by entity in a one-size-fits-all way"—you must use subject_normalized weighting (company ×1.0 / shareholder ×0.5 / directors, supervisors, and senior management ×0.5), otherwise companies with shareholder turmoil will be systematically overestimated.

List of dependent tushare interfaces

Purpose Interface Remarks
Current ST status stock_st 3000 points; fallback when unavailable namechange
Historical name changes namechange Free
Board/sector determination stock_basic Free
Income statement income 2000 points, fetched for multiple periods
Balance sheet balancesheet 2000 points
Financial indicators (non-recurring, etc.) fina_indicator 2000 points
Earnings forecast forecast 2000 points
Earnings flash report express 2000 points
Audit opinion fina_audit 500 points
Dividends dividend 2000 points
Daily bars daily Free
Daily indicators (market cap) daily_basic Free
Financial report disclosure date disclosure_date 500 points

Bundled script

  • scripts/fetch_sina_penalties.py — Scrapes the Sina Finance vGP_GetOutOfLine penalty page, implemented with stdlib, no external dependencies; reason / issuer are standardized.

Usage:

# 单次拉全量(推荐:本 skill 双窗口策略由 LLM 在内存中切片)
python agent/src/skills/ashare-pre-st-filter/scripts/fetch_sina_penalties.py \
  --ts-code 000729.SZ --stock-name 燕京啤酒 --no-filter

# 或指定单一窗口
python agent/src/skills/ashare-pre-st-filter/scripts/fetch_sina_penalties.py \
  --ts-code 000729.SZ --stock-name 燕京啤酒 --start-date 2025-01-01 --end-date 2025-12-31

Under normal conditions, outputs JSON to stdout; on network/parsing failure or invalid parameters, returns {"source": "unavailable", "error": "..."} to stdout and exits with a non-zero exit code (without throwing a traceback), making it easy for the LLM to handle as a fallback.

End-to-end call pseudocode

Used to reduce LLM call order drift, organized according to the following skeleton:

import os, json, subprocess
import tushare as ts

ts_code = '000729.SZ'
pro = ts.pro_api(os.environ['TUSHARE_TOKEN'])

# === Step 0: M0 当前状态 ===
basic = pro.stock_basic(ts_code=ts_code, fields='ts_code,name,market').to_dict('records')[0]
st_hit = pro.stock_st()  # 失败则回退 namechange
name_chg = pro.namechange(ts_code=ts_code).sort_values('start_date', ascending=False)

# === Step 1: 板块判断 ===
board = '科创板' if ts_code.startswith('688') else '创业板' if ts_code.startswith('30') else '主板'
threshold_revenue = 1e8 if board != '主板' else 3e8
threshold_mv = 3e8 if board != '主板' else 5e8

# === Step 2: 拉财务(最新 5 期 + 过去 4 年年报) ===
income = pro.income(ts_code=ts_code).sort_values('end_date', ascending=False).drop_duplicates('end_date')
balance = pro.balancesheet(ts_code=ts_code).sort_values('end_date', ascending=False).drop_duplicates('end_date')
fina_ind = pro.fina_indicator(ts_code=ts_code).sort_values('end_date', ascending=False).drop_duplicates('end_date')
forecast = pro.forecast(ts_code=ts_code).sort_values('ann_date', ascending=False)
express = pro.express(ts_code=ts_code).sort_values('ann_date', ascending=False)

# === Step 3: R1-R4 计算(按各章节口径,注意 min(n_income, profit_dedt)) ===
# ... 略

# === Step 4: E1 审计 ===
audit = pro.fina_audit(ts_code=ts_code).sort_values('end_date', ascending=False).head(2)

# === Step 5: E2 监管处罚(双窗口 + 主体加权)===
from datetime import date, timedelta
result = subprocess.run([
    'python', 'agent/src/skills/ashare-pre-st-filter/scripts/fetch_sina_penalties.py',
    '--ts-code', ts_code, '--stock-name', basic['name'], '--no-filter',
], capture_output=True, text=True)
penalties = json.loads(result.stdout).get('records', [])

# 在内存中切双窗口(避免两次 HTTP)
this_year = date.today().year
win_a_start, win_a_end = f'{this_year-1}-01-01', f'{this_year-1}-12-31'
win_b_start = (date.today() - timedelta(days=365)).isoformat()
win_b_end   = date.today().isoformat()

def _in(rec, s, e):
    d = rec.get('ann_date') or ''
    return bool(d) and s <= d <= e

win_a = [r for r in penalties if _in(r, win_a_start, win_a_end)]
win_b = [r for r in penalties if _in(r, win_b_start, win_b_end)]

# 窗口 A:单条等级取最高
REASON_LEVEL = {
    '财务造假': 3, '虚假陈述': 3, '信息披露违规': 3,
    '违规担保': 3, '占用资金': 3,
    '内幕交易': 2, '市场操纵': 2, '违规减持': 2,
}
levels_a = [REASON_LEVEL.get(r['reason_normalized'], 1) for r in win_a]
e2_single = max(levels_a) if levels_a else 0

# 窗口 B:原始条数 + 主体加权条数
FREQ_EVENT_TYPES = {'警示', '问讯', '监管关注', '监管函', '警示函'}
FREQ_ISSUERS = {'上交所', '深交所', '北交所', '证监会', '地方证监局'}
SUBJECT_WEIGHT = {'company': 1.0, 'shareholder': 0.5, 'officer': 0.5}

freq_pool = [r for r in win_b
             if r.get('e2_countable', True)
             and (r['event_type'] in FREQ_EVENT_TYPES
                  or r['issuer_normalized'] in FREQ_ISSUERS)]
nb_raw = len(freq_pool)
nb_weighted = round(sum(SUBJECT_WEIGHT.get(r['subject_normalized'], 1.0)
                        for r in freq_pool), 1)

# 频次等级(基于加权条数)
if nb_weighted >= 5.0:    e2_freq = 4   # 极高
elif nb_weighted >= 3.0:  e2_freq = 3   # 高
elif nb_weighted >= 2.0:  e2_freq = 2   # 中
else:                     e2_freq = 1   # 低

e2_overall = max(e2_single, e2_freq)
# 叠加加成:频次高 + 单条高同时命中 → 直升极高
if e2_freq >= 3 and e2_single >= 3:
    e2_overall = 4

# === Step 6: E3 交易临界 ===
daily = pro.daily(ts_code=ts_code).sort_values('trade_date', ascending=False).head(30)
daily_basic = pro.daily_basic(ts_code=ts_code).sort_values('trade_date', ascending=False).head(1).iloc[0]
total_mv_yi = daily_basic['total_mv'] * 1e4 / 1e8  # 万元 → 亿元

# === Step 7: 双轴合成输出 ===
# 风险等级 = max(R1, R2, R3, R4, E1, E2_综合, E3)
# 可信度 = 加权平均(R1, R2, R3, R4 各项可信度),akshare 兜底项降一档