What does Shanxi Securities Tushare Comprehensive Analysis Skill do?
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:
- First run
python shanxi-securities-tushare/scripts/check_env.pyto verify the environment. Stop if the token is missing and prompt the user to configure it. - Before calling any API, you must consult
shanxi-securities-tushare/references/API接口对应表.md. Never write API calls from memory. - 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 Type | Module | Default Entry Point | Example |
|---|---|---|---|
| Stock | analysis_runner.py | stock_report(ts_code, end_date=None, dimensions=None) | stock_report("600519.SH") |
| Fund (OTC .OF / Listed ETF .SH/.SZ) | fund_analysis_runner.py | fund_report(ts_code, end_date=None, dimensions=None) | fund_report("110011.OF") |
| Index | index_analysis_runner.py | index_report(ts_code, end_date=None, dimensions=None) | index_report("000300.SH") |
| Futures (Main Continuous Contract) | fut_analysis_runner.py | fut_report(ts_code, end_date=None, dimensions=None) | fut_report("SR.ZCE") |
dimensionsis 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.htmlfile for persistence; open it directly in a browser.- The old entry point
stock_analyzer.pyis retained as a compatibility wrapper. New code should preferentially useanalysis_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:
- Environment Check — Run
python shanxi-securities-tushare/scripts/check_env.pyto confirm token availability and determine the mode (sdk/http). - Target Identification — Parse the user's description to determine the target type and
ts_code. Identify by code format or name-based search. - 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.
- 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 thedimensionsparameter. - 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.htmlfile 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 Expression | Target Type | Description |
|---|---|---|
600519.SH / 000001.SZ / 920575.BJ | Stock | Standard format, directly identifiable. .BJ is for the Beijing Stock Exchange |
600519 / 000001 | Stock | Complete 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" | Stock | Call stock_basic for fuzzy name matching, fetch stocks with listing status 'L' |
000300.SH / 399001.SZ | Index | Standard index code with suffix .SH/.SZ/.SI |
| "CSI 300" / "SSE 50" | Index | Call index_basic for name matching |
000001.OF / 110011.OF | Fund | Standard fund code, suffix .OF for OTC / .SZ for listed |
| "E Fund Blue Chip" / "China Merchants Baijiu" | Fund | Call fund_basic for name matching |
RB2501.SHF / CU2403.SHF | Futures | Standard futures contract code |
| "Rebar" / "Shanghai Copper" / "Crude Oil" | Futures | Call 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_basicdoes 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 Expression Pitfall Correct Handling "ChiNext ETF" "ChiNext" can hit 87 thematic ETFs/hybrid funds Use 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 name Use 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
| # | Dimension | Data Interface | Key Analysis Metrics |
|---|---|---|---|
| 1 | Overview | stock_basic, stock_company | Company full name, industry (Shenwan), listing date, registered address, employee count, main business description |
| 2 | Market Trends | daily, 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) |
| 3 | Valuation Analysis | daily_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) |
| 4 | Financial Quality | fina_indicator, income, balancesheet, cashflow, forecast | ROE, 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) |
| 5 | Capital Flow | moneyflow, moneyflow_hsgt, block_trade | Recent 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 |
| 6 | Shareholders/Chips | top10_holders, top10_floatholders, stk_holdernumber, stk_holdertrade | Top 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_holdernumberinterface to get historical data, sort byend_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)
| # | Dimension | Data Interface | Key Analysis Metrics |
|---|---|---|---|
| 1 | Overview | index_basic | Publisher, base period, base point, category, listing date |
| 2 | Market Trends | index_daily | Recent 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 |
| 3 | Valuation | index_dailybasic | PE(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 |
| 4 | Constituent Weight | index_weight | Top 10 constituent stocks and their weight percentages, supplement with stock names (batch query via stock_basic) |
| 5 | Industry Distribution | Get constituent stocks via index_weight + query industry via stock_basic | Group constituent stocks by Shenwan industry, count the number and proportion of each industry (top 3 industry proportions) |
| 6 | Margin/Market Leverage | margin (total market margin summary) | Total margin balance for both exchanges, direction of change over the past year (250 trading days), leverage sentiment judgment |
| 7 | Comparison | index_global | Compare 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 |
| 8 | Risk Warnings | Summary of above dimensions | Risk signals such as high volatility, deep drawdown, high valuation |
III. Public Funds (9 dimensions by default)
| # | Dimension | Data Interface | Key Analysis Metrics |
|---|---|---|---|
| 1 | Overview | fund_basic | Fund type, establishment date, listing date, fund short name |
| 2 | Net Value Trend | fund_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) |
| 3 | Performance Metrics | Calculated from fund_nav/fund_daily | Annualized volatility, Sharpe ratio, maximum drawdown |
| 4 | Peer Comparison | fund_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 |
| 5 | Fund Manager | fund_manager | Start date of tenure, years of service |
| 6 | Holdings Analysis | fund_portfolio | Top 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) |
| 7 | Scale Changes | fund_share | Sample by quarter (groupby quarter-end), share change trend over the last 4 quarters |
| 8 | Dividends | fund_div | Cumulative dividend count, dividend amount; Fields are ex_date/div_cash (not div_date) |
| 9 | Risk Warnings | Summary of above dimensions | Risk 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_shareis 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)
| # | Dimension | Data Interface | Key Analysis Metrics |
|---|---|---|---|
| 1 | Overview | fut_basic | Contract underlying, exchange, contract multiplier, minimum tick size, trading unit, margin rate |
| 2 | Market Trends | fut_daily (main continuous contract like JM.DCE/RB.SHF, not a specific contract) | Recent 20/60-day return, settlement price trend, intraday amplitude, volatility |
| 3 | Position Analysis | fut_holding | Position change, volume/position ratio, top 20 member long/short ratio |
| 4 | Main Contract | fut_mapping | Main contract code, rollover date, basis (spot vs futures) |
| 5 | Warehouse Receipts/Inventory | fut_wsr | Registered warrant quantity change, inventory/consumption ratio |
| 6 | Settlement Parameters | fut_settle | Daily settlement price, delivery settlement price, margin adjustments |
| 7 | Risk Warnings | Summary of above dimensions | Risk 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.