ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

【Python量化实战 #12】选股还在拍脑袋?用 Python 搭多因子打分模型(5 因子实战)

【Python量化实战 #12】选股还在拍脑袋?用 Python 搭多因子打分模型(5 因子实战) 连载系列「Python量化实战」第 12 篇模块六 · 量化策略实战。上一篇《Python双均线金叉策略完整实现》做的是择时本篇转向量化的另一半“选股”。Python多因子选股是机构量化的主流框架思路并不神秘给每只股票的估值、质量、成长、动量等维度分别打分加权合成总分后排序取前 N 只。难点在工程侧——PE、ROE、营收增速、动量分散在行情快照和财务报表两类接口里字段格式不统一、缺失值处理麻烦。本文用 mairui SDK 一站式取齐 5 个核心因子的原始数据完成z-score 标准化 → 方向调整 → 等权合成 → 排序输出的完整多因子选股模型全部代码可直接运行。本文你将得到什么一套可直接运行的多因子框架5 因子取数 →to_num清洗 → z-score 标准化 方向调整 → 等权合成排序真实打分输出15 只样本 Top10及综合均衡才能排前的逻辑解读负 PE 陷阱、缺失值处理、行业偏斜等 6 个真实避坑点一、环境准备本文代码使用 mairui SDK 获取股票数据安装方法如下pipinstallmairui运行环境Python 3.9mairui SDK 1.0.0pandas 2.2 / numpyimportosimportmairui# 证书从环境变量读取注册后可在官网获取apimairui.Client(LICENCE-66D8-9F96-0C7F0FBCD073)# 演示证书演示证书读者复制即用无需替换本文数据截至 2026-07-27行情为实时快照财务为 2026 年一季报读者复现时数值会随行情与财报更新而变化。二、5 个核心因子与数据来源因子维度字段来源方向市盈率 PE估值stock_ssjy→pe越低越好市净率 PB估值stock_ssjy→sjl越低越好净资产收益率 ROE质量stock_pershareindex→jzcsyl越高越好营收同比增速成长stock_pershareindex→zyyrsrzz越高越好60日涨跌幅动量stock_ssjy→zdf60越高越好两个接口分工明确stock_ssjy一次返回估值与动量pe市盈率、sjl市净率、zdf6060日涨跌幅动量因子不用自己拉K线计算stock_pershareindex返回历季财务主要指标取最后一条即最新报告期。importnumpyasnpimportpandasaspddefto_num(value):接口里缺失值以 - 返回统一转成 NaN。try:returnfloat(value)except(TypeError,ValueError):returnnp.nandeffetch_factors(api,code,name):取单只股票的 5 个因子原始值。snapapi.stock_ssjy(code)# 实时快照pe / sjl / zdf60snapsnap[0]ifisinstance(snap,list)elsesnap fin_rowsapi.stock_pershareindex(code)# 历季财务指标[-1] 为最新一期finfin_rows[-1]iffin_rowselse{}return{code:code,name:name,pe:to_num(snap.get(pe)),pb:to_num(snap.get(sjl)),roe:to_num(fin.get(jzcsyl)),rev_growth:to_num(fin.get(zyyrsrzz)),momentum_60d:to_num(snap.get(zdf60)),}关键解释财务接口的缺失值是字符串-而非 null直接float()会抛异常to_num统一兜底最新报告期若是一季报ROE 为单季未年化值——横截面比较时所有股票同期可比性不受影响但不要拿去和年度 ROE 混着看。三、z-score 标准化与方向调整不同因子量纲差异巨大PE 几十、增速可能上百直接相加会被大数值因子主导。标准做法是z-score减均值除以标准差把所有因子拉到同一尺度。估值因子取负号越便宜分越高defzscore(series):z-score 标准化NaN 记 0 分中性不奖不罚。z(series-series.mean(skipnaTrue))/series.std(skipnaTrue)returnz.fillna(0.0)defbuild_score(factor_df):5 因子打分估值负向其余正向等权合成。# 亏损股 PE0 不具可比性记 NaN 中性处理factor_df.loc[factor_df[pe]0,pe]np.nan factor_df[score_value_pe]-zscore(factor_df[pe])factor_df[score_value_pb]-zscore(factor_df[pb])factor_df[score_quality]zscore(factor_df[roe])factor_df[score_growth]zscore(factor_df[rev_growth])factor_df[score_momentum]zscore(factor_df[momentum_60d])score_cols[score_value_pe,score_value_pb,score_quality,score_growth,score_momentum]factor_df[total_score]factor_df[score_cols].mean(axis1)returnfactor_df.sort_values(total_score,ascendingFalse).reset_index(dropTrue)关键解释亏损股 PE 为负数值上最低但含义完全相反必须剔除后中性化这是多因子模型最常见的数据陷阱NaN 填 0 分表示该因子不奖不罚比直接丢弃股票更稳健等权是最朴素的加权方式进阶做法IC 加权、行业中性化在文末讨论。四、完整实战示例与真实运行结果示例用一个跨行业的 15 只大盘股固定池便于复现实际使用可替换为指数成分股成分股列表可通过官网指数接口获取importtime STOCK_POOL{600519:贵州茅台,000858:五粮液,601318:中国平安,600036:招商银行,601166:兴业银行,000333:美的集团,600900:长江电力,601088:中国神华,600030:中信证券,000651:格力电器,600276:恒瑞医药,300750:宁德时代,601899:紫金矿业,600887:伊利股份,601668:中国建筑,}defmain():apimairui.Client(LICENCE-66D8-9F96-0C7F0FBCD073)# 演示证书演示证书读者复制即用无需替换records[]forcode,nameinSTOCK_POOL.items():records.append(fetch_factors(api,code,name))time.sleep(0.2)# 控制请求频率ranked_dfbuild_score(pd.DataFrame(records))cols[code,name,pe,pb,roe,rev_growth,momentum_60d,total_score]print(ranked_df[cols].head(10).round(2).to_string(indexFalse))ranked_df.to_csv(factor_scores.csv,indexFalse,encodingutf-8-sig)main()真实运行输出2026-07-27 盘中快照因子采集: 成功 15 只, 失败 0 只 多因子打分排序Top 10 code name pe pb roe rev_growth momentum_60d total_score 600030 中信证券 10.15 1.45 3.12 40.91 4.05 0.52 600887 伊利股份 7.73 3.09 9.44 5.47 7.20 0.50 601899 紫金矿业 10.37 4.39 10.40 24.79 -3.87 0.34 601166 兴业银行 4.05 0.47 2.63 -1.06 3.51 0.22 000651 格力电器 9.26 1.48 4.08 3.46 4.68 0.19 601668 中国建筑 3.48 0.40 2.79 -7.85 2.41 0.15 000333 美的集团 12.59 3.09 5.56 2.45 9.12 0.15 600036 招商银行 6.47 0.89 2.96 3.81 0.67 0.14 300750 宁德时代 21.17 4.83 5.97 52.45 -7.36 0.00 000858 五粮液 8.87 2.42 6.50 33.67 -24.51 -0.07读一下这个排序的逻辑是否自洽中信证券靠低估值 40.91% 的高营收增速登顶宁德时代增速最高52.45%但估值最贵、动量为负各因子互相抵消后总分归零——这正是多因子模型不偏科的特点单一亮点不足以上榜综合均衡才能排前。打分结果是数据的横截面快照不是买入名单。五、避坑与进阶缺失值财务字段的-必须统一转 NaN且 zscore 后填 0 中性化不要直接dropna丢股票负 PE 陷阱亏损股 PE 为负会被低估值因子误判为最优务必先剔除报告期对齐横截面所有股票用同一最新报告期不要混用年报和季报小样本失真15 只股票的 z-score 仅作演示实际应在全市场或指数成分内计算全市场列表可用stock_list共 5000 只行业偏斜银行天然低 PB、科技天然高 PE直接全市场打分会重仓金融——进阶做法是行业内分别 z-score行业中性化行业归属可通过官网板块接口获取频率限制批量采集加time.sleep控频全市场级别的并发拉取方案见本系列第 16 篇。六、总结与延伸本文搭出了多因子选股的最小可用框架两个接口取齐 5 因子 →to_num清洗 → z-score 标准化 方向调整 → 等权合成排序并讨论了负 PE、行业偏斜等真实陷阱。下一篇《从零搭建Python量化选股系统多条件筛选与历史回测》将把因子打分升级成可配置的选股系统并与第 11 篇的回测框架打通。本文为技术演示打分结果为特定时点的数据快照不构成投资建议亦不代表任何个股推荐。
返回列表