Community研究与数据分析github.com

TrueHOOHA/shanxi-securities-tushare-skill

山西证券Tushare Skill

shanxi-securities-tushare-skill 是什么?

shanxi-securities-tushare-skill is a Claude Code agent skill that 山西证券Tushare Skill.

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add TrueHOOHA/shanxi-securities-tushare-skill

Installed? Explore more 研究与数据分析 skills: affaan-m/uspto-database, affaan-m/scholar-evaluation, affaan-m/literature-review · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

Shanxi Securities Tushare Comprehensive Analysis Skill

This skill works in conjunction with the shanxi-securities-tushare data skill. It adds a multi-dimensional cross-analysis layer on top of the data interfaces provided by the latter, integrating dispersed indicators into structured analytical reports.

How It Works

Transforms "analyze XX" into an executable process: Target Identification → Dimension Loading → Data Retrieval → Calculation → Interpretation → Report.

Important: This skill does not encapsulate data retrieval logic. When fetching data, follow the workflow specifications in shanxi-securities-tushare/SKILL.md:

  1. First run python shanxi-securities-tushare/scripts/check_env.py to verify the environment. Stop if the token is missing and prompt the user to configure it.
  2. Before calling any API, you must consult shanxi-securities-tushare/references/API接口对应表.md. Never write API calls from memory.
  3. Refer to the demo templates under shanxi-securities-tushare/scripts/ for data retrieval. Choose the SDK or HTTP method based on the environment check result.

Quick Entry Points (Default Calls)

This skill encapsulates a unified Runner. Once the Agent identifies the target type, it directly calls the corresponding entry point, eliminating the need to fetch data from raw interfaces one by one:

Target TypeModuleDefault Entry PointExample
Stockanalysis_runner.pystock_report(ts_code, end_date=None, dimensions=None)stock_report("600519.SH")
Fund (OTC .OF / Listed ETF .SH/.SZ)fund_analysis_runner.pyfund_report(ts_code, end_date=None, dimensions=None)fund_report("110011.OF")
Indexindex_analysis_runner.pyindex_report(ts_code, end_date=None, dimensions=None)index_report("000300.SH")
Futures (Main Continuous Contract)fut_analysis_runner.pyfut_report(ts_code, end_date=None, dimensions=None)fut_report("SR.ZCE")
  • dimensions is an optional whitelist. By default, it uses the Runner's built-in dimensions. Only pass in a pruned list when the user explicitly requests specific aspects (e.g., "only look at valuation/technicals").
  • *_report() returns an HTML string (with ECharts charts inlined in the corresponding dimension sections). The Agent should write this string to a <ts_code>_report.html file for persistence; open it directly in a browser.
  • The old entry point stock_analyzer.py is retained as a compatibility wrapper. New code should preferentially use analysis_runner.stock_report.
  • Each Runner internally implements dimension-level parallel data fetching, so the Agent does not need to manage concurrency manually.

Core Workflow

Each analysis follows this order:

  1. Environment Check — Run python shanxi-securities-tushare/scripts/check_env.py to confirm token availability and determine the mode (sdk/http).
  2. Target Identification — Parse the user's description to determine the target type and ts_code. Identify by code format or name-based search.
  3. Dimension Loading — Load the default summary dimensions for the target type. If the user explicitly specifies (e.g., "only look at technicals"), load only those dimensions to avoid exceeding permissions/quotas and generating excessively long output. "Full default set" is the upper limit, which can be trimmed.
  4. Call Runner for Analysis — Directly call the corresponding Runner's *_report() / *_analyze() entry point. The Runner internally fetches data in parallel for the default dimensions, calculates, and generates a structured result. For custom dimensions, pass them via the dimensions parameter.
  5. Comprehensive Report — Output an HTML report following the structured template (time series charts are inlined within each dimension section).

Report must be persisted (Mandatory): Each analysis report must be saved as an HTML file in the current project directory with the filename <ts_code>_report.html (e.g., 600519.SH_report.html). The CLI already saves to the current working directory by default and prints the save path. If calling *_report() via the Python interface, the Agent must write the returned HTML string to the <ts_code>_report.html file in the project directory. It is forbidden to only print to the terminal without saving. The report is a standalone HTML file (renders ECharts via CDN, requires internet to open). Time series dimensions automatically generate charts inlined in the corresponding dimension section (e.g., K-line in "Market Trends", PE/PB in "Valuation Analysis"), while other dimensions show as tables.

Target Identification Rules

User ExpressionTarget TypeDescription
600519.SH / 000001.SZ / 920575.BJStockStandard format, directly identifiable. .BJ is for the Beijing Stock Exchange
600519 / 000001StockComplete to .SH/.SZ/.BJ (Shanghai: 600/601/603/605/688, Shenzhen: 000/001/002/003/300/301, Beijing: starts with 8)
"Moutai" / "Guizhou Moutai" / "Ping An"StockCall stock_basic for fuzzy name matching, fetch stocks with listing status 'L'
000300.SH / 399001.SZIndexStandard index code with suffix .SH/.SZ/.SI
"CSI 300" / "SSE 50"IndexCall index_basic for name matching
000001.OF / 110011.OFFundStandard fund code, suffix .OF for OTC / .SZ for listed
"E Fund Blue Chip" / "China Merchants Baijiu"FundCall fund_basic for name matching
RB2501.SHF / CU2403.SHFFuturesStandard futures contract code
"Rebar" / "Shanghai Copper" / "Crude Oil"FuturesCall fut_basic for name matching, get the main contract

Disambiguation: When name matching returns multiple results (e.g., "Ping An" = Ping An Bank 000001.SZ / Ping An Insurance 601318.SH), prioritize the one with the largest market cap, but must note in the report: "Found N matches. Analyzing the largest by market cap, XX, by default. Please specify the code for other targets."

Broad Matching Pitfall for Fund Names (fund_basic does fuzzy substring matching): A name query can hit all funds containing that substring. When analyzing a single target, the scope must be narrowed down, otherwise it will mistakenly pull a group of similar funds:

User ExpressionPitfallCorrect Handling
"ChiNext ETF""ChiNext" can hit 87 thematic ETFs/hybrid fundsUse exact code or filter by name containing "ChiNext ETF", and only take listed ETFs (exclude LOF/feeder funds)
"STAR 50"Tushare full name is "SSE STAR 50 Component ETF". Other products may also have "STAR 50" in their nameUse name containing "STAR 50" or identify directly by code
"Gold ETF"May incorrectly match thematic products like "Gold Industry Stock ETF"Exact name match for "Gold ETF"
"CSI 300"Dozens of funds contain this in their name (listed ETFs + OTC feeders + multiple tracking funds)First determine the target type (listed/OTC/feeder), then narrow down by fund type field

When name matching returns > 1 result: First narrow down by fund type (listed/OTC/feeder) and listing status. If still not unique, follow the "Disambiguation" rule above, and report the match count and final scope.

Analysis Dimensions (Full default set, trimmed as needed)

I. Stocks (11 dimensions by default)

Each dimension outputs: Description sentence → Data table → Analysis & Evaluation

#DimensionData InterfaceKey Analysis Metrics
1Overviewstock_basic, stock_companyCompany full name, industry (Shenwan), listing date, registered address, employee count, main business description
2Market Trendsdaily, weekly, monthly, daily_basic, adj_factor, index_daily (CSI 300 + industry index)Recent 20/60/250-day return (based on adjusted price), MA5/MA20/MA60, MACD/RSI/KDJ/Bollinger Bands, turnover rate, amplitude, volatility, period high/low; Benchmark comparison: Calculate same-metric returns, annualized volatility, max drawdown, and Sharpe ratio for CSI 300 and the relevant industry index, comparing side-by-side with the target (to judge excess returns and relative risk)
3Valuation Analysisdaily_basic, index_dailybasic (industry), index_member (industry constituent stocks)PE(TTM), PB, PS(TTM), dividend yield, total market cap, float market cap; Comparison with industry average (Get industry index code via index_classify → get constituent stocks via index_member → get PE/PB from daily_basic, apply winsorize_cross_section to remove extreme values, then calculate mean/median to avoid bias from single outlier); Dual-sourced PE/PB percentiles (valuation_percentiles: 5-year historical percentile + same-day cross-sectional industry percentile. If the two diverge, find the reason)
4Financial Qualityfina_indicator, income, balancesheet, cashflow, forecastROE, gross margin, net profit margin, revenue/profit growth (YoY), asset-liability ratio, operating cash flow; Earnings forecast type and change range; Piotroski F-Score (9-point quantitative score, ≥7 strong/≤2 weak)
5Capital Flowmoneyflow, moneyflow_hsgt, block_tradeRecent 5-20 day net institutional inflow (Note: net_mf_amount is the total net inflow; buy_elg_amount - sell_elg_amount is the super-large order net inflow. Their directions may differ. Choose the appropriate definition based on the analysis goal), Northbound share changes, block trade premium/discount and institutional buy/sell direction
6Shareholders/Chipstop10_holders, top10_floatholders, stk_holdernumber, stk_holdertradeTop 10 shareholder/float shareholder concentration, Time series analysis of shareholder count (chip concentration indicator), direction and proportion of major shareholder increases/decreases

Chip Concentration Analysis (Shareholder Count Time Series)

Time series changes in shareholder count are a core indicator for judging chip concentration/distribution, more meaningful than a single point value:

  • Decrease in Shareholder Count (aligned with chip concentration direction): Average shares held per person increases. This is typically a signal of chips becoming more concentrated, but the count change is only a correlation, cannot directly assert institutional accumulation; needs cross-validation with trading volume, price trends, and shareholder structure.
  • Increase in Shareholder Count (aligned with chip distribution direction): Average shares held per person decreases. This typically aligns with chips becoming more dispersed, but similarly cannot directly assert institutional distribution; needs volume-price verification.
  • Key Analysis Points:
    • Compare the change rate of shareholder count over the last 4 quarters to determine trend direction.
    • Cross-validate with price trends (all are correlational observations, not causal): Continuously decreasing count + rising price = possible chip lock-up (one characteristic of healthy uptrend); Continuously decreasing count + falling price = possible institutional trapped (one signal of potential bottom); Continuously increasing count + rising price = possible retail buying (be cautious of a top).
    • Use the stk_holdernumber interface to get historical data, sort by end_date, and calculate the quarter-over-quarter change rate. | 7 | Margin/Leverage Sentiment | margin_detail | Margin balance and change rate, short selling balance, recent 5-day margin balance change | | 8 | Market Anomalies | limit_list_d, top_list, top_inst | Recent daily limit up/down records, number of appearances on the dragon and tiger board, net institutional buy/sell | | 9 | Lock-up Expiration Pressure | share_float | Number and proportion of shares to be unlocked in the next 3 months | | 10 | Macro/Market Environment | index_daily (CSI 300), cn_cpi, cn_ppi, shibor_lpr, cn_gdp | Recent market index performance, CPI/PPI trend and direction, LPR interest rate level, GDP YoY | | 11 | Risk Warnings | Summary of above dimensions | Comprehensive risk rating: High/Medium/Low, list specific risk signals |

II. Indices (8 dimensions by default)

#DimensionData InterfaceKey Analysis Metrics
1Overviewindex_basicPublisher, base period, base point, category, listing date
2Market Trendsindex_dailyRecent 20/60/250-day return, MA arrangement, annualized volatility, max drawdown, Sharpe ratio; Benchmark comparison: Calculate same metrics for CSI 300 and compare side-by-side
3Valuationindex_dailybasicPE(TTM), PB historical percentile. Note: index_dailybasic does not cover STAR Market indices (e.g., STAR 50 000688.SH). For these, degrade to aggregate estimates using constituent stock daily_basic data (cross-sectional median + historical percentile) and mark the data source
4Constituent Weightindex_weightTop 10 constituent stocks and their weight percentages, supplement with stock names (batch query via stock_basic)
5Industry DistributionGet constituent stocks via index_weight + query industry via stock_basicGroup constituent stocks by Shenwan industry, count the number and proportion of each industry (top 3 industry proportions)
6Margin/Market Leveragemargin (total market margin summary)Total margin balance for both exchanges, direction of change over the past year (250 trading days), leverage sentiment judgment
7Comparisonindex_globalCompare recent performance with similar/international indices. index_global's ts_code has no dot prefix (e.g., DJI/SPX/IXIC/N225/HSI, not .DJI). The code format must be checked in the references/国际指数.md document. Note: index_global returns data in descending order (latest first). You must .sort_values('trade_date') before calculation, otherwise iloc indexing will retrieve dates in the wrong order, leading to incorrect return direction
8Risk WarningsSummary of above dimensionsRisk signals such as high volatility, deep drawdown, high valuation

III. Public Funds (9 dimensions by default)

#DimensionData InterfaceKey Analysis Metrics
1Overviewfund_basicFund type, establishment date, listing date, fund short name
2Net Value Trendfund_nav, fund_adj, fund_daily (listed ETFs)1/3/6 month, 1/3 year return (based on adjusted net value); Listed ETFs must use fund_daily + apply_etf_adj for adjustment (the daily interface returns empty for ETFs, and unadjusted prices can be severely distorted during share splits)
3Performance MetricsCalculated from fund_nav/fund_dailyAnnualized volatility, Sharpe ratio, maximum drawdown
4Peer Comparisonfund_basic (filter by type), fund_daily/fund_nav (per fund)Peer ranking (20/60/120/250-day percentile); For ETFs, prioritize funds within the same suffix, and prioritize those with earlier listing dates based on establishment date sorting
5Fund Managerfund_managerStart date of tenure, years of service
6Holdings Analysisfund_portfolioTop 10 heavy holdings and their proportions (stk_mkv_ratio), supplement with stock names; Fields are symbol/mkv/stk_mkv_ratio (not name/ratio/market_val)
7Scale Changesfund_shareSample by quarter (groupby quarter-end), share change trend over the last 4 quarters
8Dividendsfund_divCumulative dividend count, dividend amount; Fields are ex_date/div_cash (not div_date)
9Risk WarningsSummary of above dimensionsRisk signals such as deep drawdown, high volatility, shrinking share size

Share Size Statement (must write in the evaluation sentence for Scale Changes/Peer Comparison dimensions): fund_share.fd_share is the share size of a single fund. The same index often has multiple coexisting fund products (listed ETFs + OTC feeders + multiple tracking funds, e.g., dozens of funds named "CSI 300"). The share/size data is for a single fund and should not be described as "total of all funds for this index". The evaluation sentence must clearly state whether it is "the single fund's share" or "total of listed and OTC", to avoid misleading the user into thinking it's the index's total size.

IV. Futures (7 dimensions by default)

#DimensionData InterfaceKey Analysis Metrics
1Overviewfut_basicContract underlying, exchange, contract multiplier, minimum tick size, trading unit, margin rate
2Market Trendsfut_daily (main continuous contract like JM.DCE/RB.SHF, not a specific contract)Recent 20/60-day return, settlement price trend, intraday amplitude, volatility
3Position Analysisfut_holdingPosition change, volume/position ratio, top 20 member long/short ratio
4Main Contractfut_mappingMain contract code, rollover date, basis (spot vs futures)
5Warehouse Receipts/Inventoryfut_wsrRegistered warrant quantity change, inventory/consumption ratio
6Settlement Parametersfut_settleDaily settlement price, delivery settlement price, margin adjustments
7Risk WarningsSummary of above dimensionsRisk signals such as high volatility, rollover gaps, anomalous positions

Report Structure

Each analysis report is output as a standalone HTML file (open directly in a browser; time series charts are inlined within each dimension section). The content structure is as follows, with each dimension following the Description sentence → Data table → Analysis & Evaluation format, ending with an overall analysis & evaluation:

# Target Name Panoramic Research Report

> Data Date: YYYY-MM-DD (Tushare data is T-1 day)

## 1. Overview
Description sentence (e.g., Bank ETF, issued by Hwabao Fund, tracking the CSI Bank Index, scale ranks among the top in its peer group)
- Key metrics summary table

## 2. Market Trends
Description sentence (summary of key metrics like recent 20-day return, volatility, drawdown)
- Return comparison table (Target vs CSI 300 side-by-side)
- Risk control metrics comparison table (Volatility/Drawdown/Sharpe vs Benchmark)
- Technical indicator table (MACD/RSI/KDJ/Bollinger Bands combined into one table)
- Advanced quantitative metrics (Beta/Alpha/Sortino/Rolling Beta/RS/VaR, etc.)
- **Analysis & Evaluation**: Interpretation of the data in this dimension, including clear implications for investment reference

## 3. Valuation Analysis
Description sentence (summary of PE/PB/historical percentile, etc.)
- Valuation metrics table
- Industry cross-sectional valuation comparison table (if applicable)
- **Analysis & Evaluation**: (e.g., "PE historical percentile at 23.7% is low, PB is below the industry median, valuation needs to be judged in conjunction with earnings growth")

## N. Risk Warnings
- Risk signal 1
- Risk signal 2
- Data missing notes (if any dimension failed)

## N+1. Overall Analysis & Evaluation
**Comprehensive Judgment**: A one-sentence summary of the target's characteristics (e.g., "Low valuation, defensive, high dividend")
- Key points per dimension list (Trend/Valuation/Financial/Capital/Chips/Leverage/Macro, one line each)
**Style Positioning**: What style of asset the target belongs to
**Conclusion**: Comprehensive investment reference implications and suitable scenarios based on all dimensions

---
*This report is automatically generated by AI based on data from the Shanxi Securities Tushare platform. It is based on T-1 historical data and is for technical exchange and learning reference only. It does not constitute any investment advice or financial guidance.*

The analysis and evaluation for each dimension must include a clear reference implication for investors (e.g., "Valuation is at a historical low, but needs to be assessed in conjunction with industry cyclicality"), rather than just presenting data.

This report is automatically generated by AI based on data from the Shanxi Securities Tushare platform. It is based on T-1 historical data and is for technical exchange and learning reference only. It does not constitute any investment advice or financial guidance.


Example of multi-column data (column count must align; e.g., splitting the share size column into two columns):

| Target | Latest Share Size | Share Size Change |
|--------|-------------------|-------------------|
| CSI 300 ETF | 24.8 billion shares | -0.1% |

The analysis and evaluation for each dimension must include a clear reference implication for investors (e.g., "Valuation is at a historical low, but needs to be assessed in conjunction with industry cyclicality"), rather than just presenting data.

**Report Table Constraints**: The number of columns in the table header row must match the number of columns in the data rows. If a single conceptual column has multiple data items (e.g., "Share size + Change rate"), either split it into two columns or merge them into one column and adjust the header accordingly. Avoid empty columns.
**Table Merging Recommendation**: Data within the same dimension should preferably be merged into a single table (e.g., combine Returns + Risk Control Metrics + Technical Indicators into one table), to avoid visual fragmentation from multiple separate tables. If the number of columns makes the table too wide, it can be grouped, but the groups should be placed adjacent to each other.

## Key Default Values

| Vague Chinese Term | Default Interpretation |
|-------------------|------------------------|
| "Recent"/"Lately" | Last 20 trading days |
| "Last three months" | Last 60 trading days |
| "This year" | From January 1st of the current year to present |
| "Historical" (Stock/Index) | Last 3 years |
| "Historical" (Fund) | Since inception |
| Security Code | Standard format `600519.SH` |
| Fund Code | OTC `.OF`, Listed `.SZ`/`.SH` |
| Futures Code | Standard format `RB2501.SHF` |
| Industry Classification | Shenwan 2021 edition |
| Comparison Benchmark (Stock) | Average of its Shenwan Level 1 industry |
| Comparison Benchmark (Fund) | Peer funds (same type + same investment direction) |
| Comparison Benchmark (Index) | CSI 300 (000300.SH) |

> **Data Sufficiency**: When fetching data, request the maximum period (e.g., "last 250 days") and then an extra 30 trading days before that to ensure enough data for calculations. If a target (e.g., Cambricon) only has 249 trading days between 20250801 and 20260812, that is insufficient to calculate the last 250-day return. In this case, move the start date earlier (e.g., `start_date = '20250601'`) to get more data, or downgrade to "last 120 days" and note "insufficient data".
> **Report Handling for Insufficient Data**: If a target has been listed for less than the requested period (e.g., a specific futures contract only has 197 days, less than 250):
> 1. **Preferentially switch to the main continuous contract** (for futures) or move the start date earlier (for stocks) to supplement data
> 2. If still insufficient, calculate the total return since listing and label it as "Insufficient data (only N days, since listing X%)"
> 3. Never display N/A directly — users cannot tell if it's a data issue or a calculation issue

## Quantitative Analysis Methods

### Longitudinal Comparison (Single Target Time Series)

Historical trend analysis of a single target must eliminate price jumps caused by corporate actions (stock dividends, rights issues, cash dividends, rights offerings). Otherwise, interval returns and technical indicators will be distorted.

- **Stock Adjustment**: `daily` returns **unadjusted** data (with ex-rights/dividend jumps). **Adjust must be applied** before calculating trends/returns/technical indicators, otherwise, ex-rights days will produce false gaps. Use `adj_factor` for self-calculation:
  - Adjusted price (backward) = Raw price × Daily adjustment factor (`apply_adj_factor` adjusts open/high/low/close/pre_close simultaneously. `*_post` columns share the same scale, making them safe for OHLC indices like KDJ/Bollinger Bands.)
  - Adjusted price (forward) = Raw price × Daily adjustment factor / Latest adjustment factor
  - Long-term returns, fixed investment returns, drawdowns, and technical indicators should all be based on adjusted prices; ⚠️ Never use `close_post` with unadjusted `high`/`low` — the inconsistent scale will distort indicators like KDJ.
- **Fund Adjustment**: `fund_nav` returns unit NAV and cumulative NAV. When calculating interval returns, use the `fund_adj` adjustment factor to build an adjusted NAV series, eliminating the impact of dividend ex-rights:
  - Adjusted NAV = Unit NAV × Daily adjustment factor / Latest adjustment factor
  - Sharpe, max drawdown, Calmar, etc., are all calculated based on the adjusted NAV series.
- **ETF Adjustment**: `fund_daily` returns unadjusted prices. `apply_etf_adj` (`fund_adj` factor) produces `close_post`. **The `fund_adj` factor for ETFs differs in definition from the stock `adj_factor` (measured direction/magnitude is inconsistent, e.g., 510500 ~0.34, 512100 ~0.373, 510300 ~1.27). `close_post`'s absolute value is not a backward-adjusted price. It should only be used for scale-invariant calculations like returns/Sharpe/drawdowns (based on the series' pct_change, which is independent of the factor's absolute value). Display prices using unadjusted `close`.** The stock `adj_factor` is a standard backward adjustment factor (monotonically increasing, `adjusted price = raw price × adj_factor`, can be displayed). `apply_*_adj` returns a DataFrame indexed by `trade_date`/`nav_date`, which can be directly fed to `rebase_series`/`compare_returns` (both check for datetime index; passing an integer index will raise a TypeError).
  - **Function Selection**: `apply_etf_adj` **only adjusts close** (produces close_post, for returns/Sharpe/drawdown). For OHLC-like indicators (KDJ, Bollinger Bands) that require high/low/close to be on the same scale, **use `apply_adj_factor` instead** (it adjusts all open/high/low/close/pre_close, and `*_post` columns share the same scale. It also works for fund_daily). Misusing `apply_etf_adj` for KDJ will result in a KeyError because high_post/low_post do not exist.
- **Fund Size Data Retrieval**: `fund_nav.total_netasset` is quarterly-based (sparse, mostly NaN). It should only be used as a quarterly snapshot. For continuous daily size, use `fund_share.fd_share` (in 10k shares) × `fund_nav.unit_nav`: `Size (100 million yuan) = fd_share × unit_nav / 1e4` (align by trade_date first). `fund_nav` may have duplicate rows for the same nav_date; de-duplicate by nav_date before use.
- **Futures Continuous Contracts**: Futures have rollover gaps. For longitudinal analysis, use `fut_mapping` to identify main contract periods. Continuous trends across main contracts need to be spliced or analyzed per contract using `fut_daily`. Do not simply concatenate them.

### Horizontal Comparison (Multi-Target Normalization)

When comparing multiple targets horizontally, their price scales differ (e.g., Moutai at 1500 vs. Agricultural Bank at 4). Directly comparing price series is meaningless; they must be normalized.

- **Series Normalization (Rebase)**: Scale each target's adjusted price series so that the base date equals 100. Formula: `Normalized NAV = Daily Adjusted Price / Base Date Adjusted Price × 100`. The base date is the start of the comparison period, so all targets start from the same point.
- **Return Comparison**: Calculate contemporaneous returns for each target (1-month/3-month/6-month/1-year/YTD), place them in a single table sorted horizontally.
- **Valuation Percentile Comparison**: PE/PB absolute values cannot be directly compared across targets (industry attributes differ). Convert them to their respective 5-year historical percentiles first, then rank them horizontally. Before calculating cross-sectional mean/percentile across targets, apply `winsize_cross_section` (MAD 3σ) or directly use the cross-sectional median to avoid bias from single outlier stocks. Give priority to the "historical percentile + cross-sectional industry percentile" dual measure (`valuation_percentiles`).
- **Financial Metrics Comparison**: ROE, gross margin, etc., are already ratio metrics and can be ranked directly. Absolute value metrics like revenue/profit should be converted to growth rates (YoY/QoQ) or per-capita values before comparison.
- **Volatility/Drawdown Comparison**: Annualized volatility and max drawdown have unified units and can be ranked directly. However, for Sharpe ratio, ensure the risk-free rate is defined consistently.

### Advanced Quantitative Metrics

Beyond basic metrics, the following methods enhance the depth and scientific rigor of the analysis:

- **Technical Indicators**: MACD (trend momentum/golden cross/death cross), RSI (overbought > 70/oversold < 30), KDJ (stochastic indicator), Bollinger Bands (volatility range/touching upper or lower bands). MA alone is insufficient for judging buy/sell timing; a combination of technical indicators provides richer signals.
- **Historical Percentile**: The percentile rank of a current valuation metric like PE/PB within its 5-year historical series (`percentile_rank`). 85th percentile = current valuation is higher than 85% of historical times → overvalued.
- **Sortino Ratio**: An improvement over Sharpe, the denominator uses only downside volatility (volatility on losing days). It is more appropriate for asymmetric return distributions and suitable for evaluating a fund's downside risk control.
- **Information Ratio (IR)**: Annualized excess return / Annualized tracking error. Measures a fund manager's stock-picking skill. IR > 0.5 is good.
- **Piotroski F-Score**: A 9-point financial health score — Profitability (ROA > 0, Operating Cash Flow > 0, ΔROA > 0, OCF > Net Income), Leverage/Liquidity/Financing (ΔAsset-Liability Ratio ≤ 0, ΔCurrent Ratio > 0, No new equity issued), Operating Efficiency (ΔGross Margin > 0, ΔAsset Turnover > 0). Total score 0-9; ≥7 is strong, ≤2 is weak. De-duplicate by annual report (end_date 1231), use the last 2 periods for YoY comparison. Data comes from `fina_indicator`/`income`/`cashflow`/`balancesheet` (optional).
- **Volume-Price Analysis**: OBV (On-Balance Volume, price up + volume up = healthy trend), Volume Ratio (today's volume / 5-day average volume, > 2 for high volume / < 0.5 for low volume), Volume-Price Divergence (price up + volume down = top signal / price down + volume down = bottom signal).
- **Beta/Alpha Attribution**: CAPM regression decomposition. Beta = stock's sensitivity to the market (> 1.2 high elasticity / < 0.8 defensive). Alpha = annualized excess return after deducting market return. Needs aligned daily returns of the stock and CSI 300 for regression.

### Risk Modeling and Distribution Analysis

- **VaR/CVaR (Value at Risk/Conditional VaR)**: Calculate the maximum daily loss at a 95%/99% confidence level using the historical method. VaR = loss quantile, CVaR = average loss exceeding VaR (more conservative). These are internationally standard risk management metrics.
- **Tail Risk (Skewness/Kurtosis)**: Skewness < 0 = left-skewed (longer loss tail, higher crash risk); Kurtosis > 0 (excess) = fat tails (higher probability of extreme events than normal distribution). Combining the two helps determine if return distribution deviates from normal.
- **Drawdown Depth Analysis**: Beyond max drawdown, include drawdown duration (underwater days) and pain index (average drawdown depth) to measure the actual experience of being "trapped".
- **Amihud Illiquidity**: |Daily Return| / Daily Turnover. Measures the price change caused by a unit of capital. High value = poor liquidity, high cost for large capital entry/exit.

### Rolling Analysis and Dynamic Monitoring

- **Rolling Beta**: Calculate Beta over a 60-day rolling window to show how market sensitivity evolves over time (increase = rising volatility or weakening defense).
- **Rolling Sharpe**: Risk-adjusted return trend over a 60-day rolling window. Better reflects stability than a single-point Sharpe.
- **Relative Strength (RS)**: Target cumulative return / Benchmark cumulative return. RS > 1 means outperforming, RS < 1 means underperforming. A strengthening trend indicates expanding relative advantage.

### Statistical Testing Methods

- **Z-Score Standardization**: Convert a metric to the number of standard deviations from the group mean. |Z| > 1.96 = significantly different at the 5% significance level. Used for cross-target valuation/financial metric comparisons.
- **Event Study Method**: Estimate normal returns using a market model regression over an estimation window (30 days before the event). Calculate Abnormal Returns (AR) and Cumulative Abnormal Returns (CAR) over an event window (10 days after). CAR > 2% = significant positive impact of the event. Applicable to earnings releases, lock-up expirations, insider trading events, etc.
- **CAGR (Compound Annual Growth Rate)**: Exact annualization based on holding days. More suitable for cross-period comparisons than simple interval returns.

## Analysis Principles

1.  **Conclusion First**: Write the conclusion sentence for each dimension first, then present the data. Do not just list data and let the user decide.
2.  **Cross-Validation**: When a signal from a single dimension is insufficient, combine multiple dimensions for cross-validation (e.g., "Capital inflow, but valuation is already high").
3.  **Data Timeliness**: Tushare data is T-1 day. The report header should note the data date.

相关技能