38 lines
1.4 KiB
Python
38 lines
1.4 KiB
Python
"""05 | 多因子选股(横截面)
|
|
目标:体验"因子"最朴素的样子——按指标排序选股。
|
|
数据:akshare 全A快照(含市盈率/市净率等)。
|
|
"""
|
|
import time
|
|
import akshare as ak, pandas as pd
|
|
|
|
def fetch_spot(retries=6):
|
|
last = None
|
|
for i in range(retries):
|
|
try:
|
|
return ak.stock_zh_a_spot_em()
|
|
except Exception as e:
|
|
last = e; time.sleep(3 + i * 3)
|
|
raise last
|
|
|
|
try:
|
|
spot = fetch_spot()
|
|
print("全A快照:", spot.shape)
|
|
df = spot.copy()
|
|
pe = pd.to_numeric(df.get("市盈率-动态"), errors="coerce")
|
|
df = df[pe.notna()].copy()
|
|
df["EP"] = 1 / pe[pe.notna()] # 盈利收益率(1/PE)
|
|
df["EP_rank"] = df["EP"].rank(pct=True)
|
|
top = df.sort_values("EP_rank", ascending=False).head(20)[
|
|
["代码", "名称", "最新价", "市盈率-动态", "EP_rank"]]
|
|
print("\n== 按盈利收益率(EP)选出的前20(低估值)==")
|
|
print(top.to_string(index=False))
|
|
top.to_csv("../data/05_top20_EP.csv", index=False, encoding="utf-8-sig")
|
|
print("已存 data/05_top20_EP.csv")
|
|
except Exception as e:
|
|
print("取数失败(网络/接口变动):", repr(e)[:200])
|
|
print("可稍后重跑;或先跑 01-04(已缓存,离线可跑)")
|
|
|
|
# 思考题:
|
|
# 1) 单因子排序选股有什么坑?(行业偏差/市值偏差/未来函数)
|
|
# 2) 怎么把2个因子合成打分?(标准化后加权,试试 z-score)
|