Fundamental factor screening — filter stocks by PE/PB/ROE and other financial metrics for value or growth selection. Supports A-shares (via tushare extra_fields) and HK/US stocks (via yfinance Ticker info).
69
85%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Filter stocks using fundamental financial data (PE/PB/ROE, etc.) to build value or growth screen signals for backtesting. Supports multiple markets with different data sources.
| Market | Data Source | Method | Supported Metrics |
|---|---|---|---|
| A-shares | tushare daily_basic | extra_fields in config.json | pe, pb, pe_ttm, ps_ttm, dv_ttm, total_mv, circ_mv, roe |
| US stocks | yfinance Ticker.info | Direct API call | trailingPE, forwardPE, priceToBook, returnOnEquity, marketCap, dividendYield |
| HK stocks | yfinance Ticker.info | Direct API call | trailingPE, priceToBook, returnOnEquity, marketCap |
{
"source": "tushare",
"codes": ["000001.SZ", "600036.SH", "000858.SZ"],
"start_date": "2023-01-01",
"end_date": "2024-12-31",
"extra_fields": ["pe", "pb", "pe_ttm", "roe", "total_mv"],
"initial_cash": 1000000,
"commission": 0.001
}The extra_fields columns are automatically merged into the daily DataFrame by the DataLoader.
For HK/US stocks, fundamental data is not available as daily time-series via the backtest loader. Instead, use yfinance Ticker info for point-in-time screening:
import yfinance as yf
def screen_us_stocks(tickers, criteria):
"""Screen US/HK stocks by fundamental criteria."""
passed = []
for symbol in tickers:
info = yf.Ticker(symbol).info
pe = info.get("trailingPE")
pb = info.get("priceToBook")
roe = info.get("returnOnEquity") # Decimal (e.g., 0.25 = 25%)
mcap = info.get("marketCap")
if pe is None or pb is None or roe is None:
continue # Skip stocks with missing data
if (0 < pe < criteria["pe_max"]
and pb < criteria["pb_max"]
and roe > criteria["roe_min"]
and (mcap or 0) > criteria.get("mcap_min", 0)):
passed.append({
"symbol": symbol,
"pe": pe,
"pb": pb,
"roe": round(roe * 100, 1), # Convert to percentage
"mcap": mcap,
})
return passed
# Example: screen S&P 500 components
criteria = {"pe_max": 20, "pb_max": 3.0, "roe_min": 0.08, "mcap_min": 10_000_000_000}
results = screen_us_stocks(["AAPL", "MSFT", "JNJ", "JPM", "XOM"], criteria)# HK stocks use the same yfinance interface
hk_tickers = ["0700.HK", "9988.HK", "1810.HK", "2318.HK", "0005.HK"]
results = screen_us_stocks(hk_tickers, criteria) # Same function works| Parameter | Default | Description |
|---|---|---|
| pe_max | 20.0 | PE ceiling (exclude overvalued) |
| pb_max | 3.0 | PB ceiling |
| roe_min | 8.0 | ROE floor (%), exclude low-profitability |
| pe_min | 0.0 | PE floor (exclude loss-making stocks) |
| mcap_min | 0 | Market cap floor (for US/HK, in USD) |
extra_fields columns may contain NaN (new listings, ST stocks) — must fillna or dropnape > 0Ticker.info is a point-in-time snapshot, not historical time-series — cannot directly use for daily rebalancing backtests on US/HK stockspip install pandas numpy yfinance1/N = selected for long (N = number of stocks passing the screen), 0 = not selected3dba332
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.