格雷厄姆这个名字这几年在量化圈被提及的次数远不如那些高频策略和机器学习模型但每次市场出现极端行情我总会把《聪明的投资者》翻出来重读一遍。特别是其中关于分散投资的原则——原文其实很朴素“将资金分散到多种证券上而非集中于一只或几只股票”但真正在代码世界里把这条原则完整落地我踩了不少坑也绕了不少弯路。这篇文章就从我自己的实践出发完整拆解AI如何实现格雷厄姆的分散投资原则。这篇文章解决的是一个具体问题当你的股票选择从“人工看财报”变成“算法批量筛选”时分散投资不再是一个操作习惯而必须被转译成一套可量化、可执行、可回测的系统规则。如果你正在写自己的量化选股框架或者准备把价值投资理念自动化这篇文章会帮你避开我在数据、信号构建和再平衡环节踩过的大量深坑。全文以Python为主要实现语言涉及财务因子计算、机器学习排序、组合权重约束和风险监控都是可以直接参考的实践方案。1. 先拆清楚格雷厄姆的分散投资原则到底包含什么很多人对“分散投资”的理解停留在“别把鸡蛋放在一个篮子里”但这个表述其实掩盖了大量细节。格雷厄姆的分散原则有三层明确的内容不拆清楚就直接上模型最后结果一定与原则初衷相悖。1.1 分散不是“多买几只股票”这么简单《聪明的投资者》里给出过一个具体数量参考分散到至少10只、至多30只股票。但这句话搁在A股、港股和美股市场执行方式差异很大。格雷厄姆强调的核心是“每只股票都不应成为决定你整体收益格局的关键变量”换句话讲单一标的的最大亏损对组合的冲击要被限制在一个可接受范围内。用数学语言描述就是单个持仓权重的上限约束。我第一次写这个逻辑时直接把30只股票平均分配权重各约3.33%看起来确实“分散”了。可随后一位做风控的朋友提醒我30只股票全部来自同一个行业涨跌联动极高名义上是分散实际集中度爆表。格雷厄姆本人在书中也明确说过“分散化是抵御无知与错误的保护措施”但当你对行业的风险暴露一无所知时分散只是表象。所以第一条纪律是分散的第一个维度永远是个股数量与单一持仓上限的双重约束而不仅是“数量多”。1.2 格雷厄姆的三个约束条件AI怎么理解格雷厄姆在实际操作中把分散原则细化为三个约束条件第一持有至少10只股票且单只股票仓位不超过总资金的5%。对应到AI系统这就是组合优化模块里的上界约束——max_weight 0.05。第二行业仓位不超过总资金的15%。这一点现在的多因子框架几乎不会自动考虑需要额外接入行业分类数据。A股可以参考申万一级行业美股可以用标普行业分类。我第一次实现时想的特别天真觉得加个行业标签再设个约束就行直到发现同一只股票在不同数据源下的行业归属差异极大——有的分类把它归为信息技术有的归为可选消费单这一项就足以让组合构建结果不稳定。第三分散不是一次性的而是周期性的再平衡操作。格雷厄姆的做法是每年检查一次组合卖掉涨幅过大导致权重溢出的标的买入跌幅过大但基本面未坏的标的。这套逻辑翻译成AI指令就是设定固定的再平衡周期月频或季频触发约束偏离度阈值后执行调仓。把这三个约束翻译成机器可执行的规则是AI落地格雷厄姆原则的第一道门槛。我在代码里的实现思路是这样的# 单一标的上限约束 MAX_STOCK_WEIGHT 0.05 # 行业上限约束 MAX_INDUSTRY_WEIGHT 0.15 # 最小持仓数量 MIN_STOCK_NUM 10 # 再平衡周期单位自然日 REBALANCE_PERIOD 90是不是很简单但后面所有复杂逻辑都是从这三行参数衍生开的。你慢慢会发现所谓“AI实现价值投资”本质上不是让模型去找什么神秘圣杯而是把大师写在书里的模糊原则变成一套精确到参数级的规则系统。2. AI的用武之地以及它的边界在哪里格雷厄姆原则技术化的难点从来不是“分散”本身而是“什么值得分散”。换句话讲你必须先有能力筛出一组符合低估标准的标的才有资格谈分散。AI在这套体系里承担的角色也因此分层非常清楚。2.1 哪些环节适合交给AI哪些不适合以我的经验看AI在格雷厄姆体系里的介入程度可以分为三层第一层数据清洗与财务指标计算完全可以自动化。PE、PB、股息率、资产负债率这些指标人工看财报一来慢二来口径容易混交给程序批量处理是性价比最高的环节。第二层低估标的初筛AI能做到“辅助判断”。这里需要的学习模型或打分规则本质上是把你对“低估”的定义从主观感受转成可枚举的条件。格雷厄姆的选股标准非常具体比如PE低于历史均值一定比例、PB低于1.5、股息率大于3%、债务结构健康等。这些条件看起来像硬编码规则但实际上可以做成一个动态阈值调整器让模型根据市场整体水位自动调整筛选强度。第三层组合构建与再平衡的执行应该完全交给规则系统。这层讲究纪律感和可解释性黑箱模型反而不合适。格雷厄姆原则里有一句很重要的话——“投资者应该像企业家一样思考”它强调的是逻辑一致性和长期性不是高频的预测能力。我见过不少失败的AI价值投资项目问题几乎都出在同一件事试图让模型在第三层发挥“预测”功能比如用LSTM预测下季度哪只价值股会涨。这种思路偏离了格雷厄姆原则实盘效果也很不稳因为价值回归的时间窗口实在太难预测了。2.2 数据准备AI吃什么比怎么吃更重要如果数据有问题后面所有模型都是白搭。我构建这套系统时数据的完整性和一致性花的时间比写模型的时间多得多。核心数据清单包括历史行情数据至少5年日线、财务报告数据含资产负债表、利润表、现金流量表、行业分类数据、退市及ST状态标记。很多人还会加入舆情数据或分析师预期数据但格雷厄姆原则本身不依赖这类“市场情绪类数据”我建议第一阶段先不加保持系统的纯净度。这里有一个实操细节财务数据的“时点对齐”。比如你想计算某只股票在2023年6月1日的PE应该用哪一个财报数据答案是最近一期已披露的财报而不是最新发布的财报。很多量化框架默认使用最新财报这会带来严重的前视偏差look-ahead bias。如果不想自己写对齐逻辑可以直接用现成的因子库比如某财经数据商的A股因子接口它的财报数据默认就是按披露日期对齐的。我用过两类数据源一类是“点我”式简单拉数的接口一类是需要自己维护数据库的传统数据商分别适用于小规模验证和大规模生产。数据清洗时有一个我后来补上的细节处理停牌股。长期停牌的股票在回测期间看起来收益率平稳实际上根本无法成交。如果策略选入了这类标的实盘时会直接卡死。我的做法是在初筛阶段直接剔除连续停牌超过10个交易日的股票。这个参数是试出来的起初设的是5天结果把一些有价值的重组标的也剔了后来放宽到10天逻辑基本合理。3. 构建低估标的池从规则筛选到机器学习排序格雷厄姆的选股逻辑本质上是一套多条件的综合打分体系。我最初的实现方式是纯规则型也就是硬编码条件3.1 规则初筛让AI先读懂格雷厄姆的“硬杠杠”对于全市场股票先做一次严格的条件过滤直接砍掉大部分不合格标的。我按格雷厄姆经典标准做了一个基础版def graham_filter(df): 格雷厄姆基础筛选条件 df: 包含财务指标的DataFrame cond_pe (df[pe_ttm] 0) (df[pe_ttm] 15) # 盈利且PE不过高 cond_pb (df[pb] 0) (df[pb] 1.5) # 市净率低于1.5 cond_div df[dividend_yield] 3.0 # 股息率大于3% cond_debt df[debt_ratio] 0.5 # 资产负债率低于50% cond_roe df[roe] 0.1 # ROE大于10% return df[cond_pe cond_pb cond_div cond_debt cond_roe]这个初筛版本非常严格有时候全市场筛完只剩下几十只。刚开始我会觉得太少了觉得这不是给自己找麻烦吗后来我想通了格雷厄姆本来就是极度谨慎的人宁可错过也不做错。标的少并不是坏事反而让后面的分散构建变得更直接。但问题也来了条件太刚性当年有效的阈值放到几年的不同市场行情下可能从“保守”变成“僵化”。比如2021年成长风格极端占优时PE小于15的标的基本都是传统行业筛完的结果严重偏向银行地产。这不是说筛选逻辑错了而是条件需要加上“市场适配”的动态调整。3.2 机器学习打分把“低估程度”变成连续变量在初筛的基础上我加入了排序模型。具体做法是用PE、PB、股息率、资产负债率、ROE、营收增速这六个因子作为特征构建一个综合低估打分。这里不需要太复杂的模型我试过XGBoost和LightGBM也试过简单的加权打分最终发现对于这类低维财务数据逻辑清晰的加权打分和复杂模型的效果差不多但前者解释成本低太多。量化打分并不一定要盲目上机器学习模型如果你有行业内经验完全可以直接给因子配权重。以下是我用过的打分函数def score_stock(row): 对股票进行低估打分分数越高越低估 # 各因子分位数转换取值区间在0-1之间 pe_score 1 - row[pe_rank] # PE越低得分越高 pb_score 1 - row[pb_rank] # PB越低得分越高 div_score row[div_rank] # 股息率越高得分越高 roe_score row[roe_rank] # ROE越高得分越高 debt_score 1 - row[debt_rank] # 负债越低得分越高 growth_score row[growth_rank] # 营收增速越高得分越高 # 综合打分权重可以按经验调整 return 0.25*pe_score 0.25*pb_score 0.2*div_score 0.15*roe_score 0.1*debt_score 0.05*growth_score这套权重是我多次测试后固定的一个相对均衡配置核心逻辑是估值因子为主、质量因子为辅。分母使用同行业内分位数而非全市场分位数避免银行股和科技股基本面指标之间不可比的问题。打分完成后取前5%作为候选池接着进入分散构建模块。这里有个小细节候选池里大概率会集中在少数几个行业比如金融、能源、公用事业。如果候选池只有金融行业你再怎么分散个股行业集中度过高的问题还是没法解决。4. 分散逻辑的量化实现把“原则”变成“约束条件”这是整篇文章我认为最核心的部分。因为从“选出好股票”到“构建好组合”之间还有一段距离。分散原则的落地本质上是一个带约束的优化问题。4.1 用凸优化硬约束实现行业与个股权重双上限组合优化模块我一开始尝试用scipy的minimize手写约束后来发现问题太多。一个关键难点是分散还要求“尽量让权重均匀”并不是只满足上限就行。比如你设了单只股票不超过5%但最终权重是0.5%、4.9%、0.8%这种极端分布实际操作层面并没有达到均衡分散。后来我换成了cvxpy来建模用凸优化框架把分散目标拆成了两部分一是最大化组合的分散度二是尽量逼近最大分散组合——也就是设计一个目标函数让组合权重与等权组合的距离最小。具体实现如下import cvxpy as cp def build_diversified_portfolio(candidates, industry_map, max_weight0.05, max_industry_weight0.15): 构建分散组合 candidates: 候选股票的预期打分 industry_map: 股票到行业的映射字典 stocks list(candidates.keys()) n len(stocks) # 权重变量 w cp.Variable(n) # 等权目标 w_target cp.Parameter(n, value[1/n]*n) # 目标函数权重与等权组合的差异最小化 objective cp.Minimize(cp.sum_squares(w - w_target)) constraints [ cp.sum(w) 1, # 权重之和为1 w 0, # 不允许做空 w max_weight # 单只股票上限 ] # 行业权重约束 industries set(industry_map.values()) for industry in industries: indices [i for i, stock in enumerate(stocks) if industry_map[stock] industry] if indices: constraints.append(cp.sum(w[indices]) max_industry_weight) # 加入打分排序约束不要求强制选中高分股但剔除得分过低者 low_score_indices [i for i, stock in enumerate(stocks) if candidates[stock] 0.2] if low_score_indices: constraints.append(cp.sum(w[low_score_indices]) 0.1) problem cp.Problem(objective, constraints) problem.solve() return {stock: round(w[i].value, 4) for i, stock in enumerate(stocks)}这段代码的核心思想说来也简单在满足分散上限约束的前提下让组合尽可能靠近等权配置。为什么要追求等权因为格雷厄姆本身就倾向于平均分配不预测谁会跑得更好。但这里有一个实践层面的问题当候选池刚好只有11只股票且8只都集中在金融行业时行业权重15%的约束是卡死的最终结果可能只有8只金融股各占5%、3只其他行业股票瓜分剩下的60%。这种情况至少比无约束强但组合还是偏了。我的解法是回到上一层对候选池做行业均衡再采样保证进入构建模块的股票行业分布本身就不过度集中。4.2 再平衡算法让组合始终守规矩再平衡就是定期检查组合偏离程度然后调仓回到约束内。这里的关键不是“机械地卖掉超出上限的股票”而是要区分“超配是因为股价上涨还是因为基本面变化”。原理是如果某只股票从4%涨到6%触发上限这属于顺其自然的成长卖掉一半即可如果一只股票的基本面恶化导致ROE跌破阈值、负债率飙升那就不只是调权重的问题而是直接剔除。这两类动作在代码里是完全不同的逻辑分支。def rebalance(portfolio, market_data, fund_data, rebalance_date): 定期再平衡组合 new_portfolio {} # 第一步剔除基本面恶化的标的 for stock, weight in portfolio.items(): if fund_data.loc[rebalance_date, stock][roe] 0.05: continue # ROE显著下滑直接剔除 if fund_data.loc[rebalance_date, stock][debt_ratio] 0.7: continue # 负债率过高直接剔除 new_portfolio[stock] weight # 第二步基于最新权重重新做分散优化 return build_diversified_portfolio(new_portfolio, industry_map)很多人做再平衡时容易忘记交易成本的存在。A股市场的双边手续费和冲击成本对于小市值策略的影响可能达到年化2%到5%。如果调仓频率太密光摩擦成本就能吞掉很大一部分超额收益。我最终把再平衡周期设成了季度调仓并叠加一个“偏离度触发机制”单个持仓权重超过目标上限的1.2倍或低于下限的0.5倍时才触发调仓这样能有效控制无效交易的出现。5. 回测与风控策略是“看起来有效”还是“真正有效”一个看起来逻辑完美的分散策略在真实市场里能不能跑出稳定收益完全是另一个问题。我在这部分投入的时间比写策略本身多一倍。5.1 回测框架要小心的几个坑首先是前视偏差。我前面提到的财报时点对齐在回测中尤为致命。假设你用一只股票2023年全年财报的ROE去回测2023年上半年的持仓这个信号当时根本无法获取回测结果自然漂亮实盘却不可能复现。其次是幸存者偏差。很多现成的回测数据默认剔除了已退市的股票导致回测空间里全部是“活下来”的标的。如果你不主动加入退市股票的历史数据策略回测收益率会虚高。真正的做法是使用含退市股的全市场数据让策略在历史时点面对的是当年真实存在的全部选项。最后是手续费和滑点。我在回测初期设的单边手续费是万2.5滑点设了0.1%对比我后续实盘真实成交情况这个假设在大多数流动性较好的标的上基本够用但一旦策略涉及小盘股滑点会显著高于设定值。我的处理方式是回测时对市值最小的那部分候选股额外加了一个惩罚项把滑点假设上调到0.3%。5.2 风控监控别等组合爆了才想起看指标风控这个环节表面上看是设几个“红线指标”实际上最难的是提前判断组合是否正在悄悄偏离初衷。我在自己的项目里做了三类监控。第一类是系统性风险监控。分散投个10到30只股票只能对冲掉部分非系统性风险系统性风险还是要靠仓位管理。我会监控组合整体的Beta值如果组合Beta超过1.1即使个股层面再分散市场大跌时也无法有效避险。第二类是流动性监控。价值投资经常买到“便宜但没成交量”的股票这类标的买入时问题不大卖出时冲击成本极高。我设了一个监控条件单只股票过去20个交易日的日均成交金额低于某阈值时系统会在下一次再平衡时优先剔除。第三类是风格漂移监控。这一点我这两年体会特别深。价值策略最怕的不是跌而是策略不知道自己在干什么了。比如某段时间组合里的股票平均市值越来越小或者持仓标的的平均市盈率从12倍慢慢涨到20倍说明系统可能正在偏离初衷。我的做法是定期计算组合持仓的风格因子暴露度——市值因子和估值因子的暴露度如果超出历史均值的1个标准差就触发告警让我重新审视筛选条件是否被市场行情带偏了。6. 常见问题与排查技巧实录这部分是我在实际开发过程中整理了半年的踩坑笔记。做这套系统的时候有四个问题出现的频率最高值得单独拿出来说。6.1 数据错位导致的“假低估”某次我的策略选出了一只市盈率特别低的标代码打分很高但人工复查后发现它的最新财报实际是两年前的——因为该公司延迟披露数据商把旧财报当作“最近一期”给推送了。这类问题在年报季尤其高发。排查方法很朴素每期调仓前随机抽5只持仓抄底标的人工核对一下财报日期和披露时间能过滤掉90%以上的数据错位问题。6.2 分散组合跑输等权基准组合构建完成后我的系统把基准设置为沪深300。有段时间组合收益率连续跑输基准查了原因发现是约束条件加得太多导致组合能买的标的都是市值偏大的传统行业弹性不足。解决办法在候选池生成环节把全市场按市值划分成几个梯队分散构建时保证每个梯队都有配额避免约束条件把组合“锁死”在某一类风格里。6.3 再平衡反而拉低收益刚开始我把再平衡周期设得比较短结果频繁在低波动区间做无意义换仓收益被手续费吃掉不少。这个问题花了我很长时间才定位清楚。后来我把再平衡模块做了一个“冷静期”机制如果两次调仓之间的净值最大回撤低于1.5%系统自动跳过本次再平衡等到偏离度真正变大时再动。调整之后策略年化收益没有明显提升但最大回撤降了约两个百分点持有体验好了很多。6.4 打分模型在极端行情下失效2024年初有一段小盘股集中回调的行情我的打分模型筛出来的股票大面积下跌。复盘后发现模型使用的财务因子全是滞后数据在极端流动性收缩的行情里根本没有防御作用。后来我在打分模型里增加了一个刹车因子用近20个交易日的动量与换手率变化作为流动性预警信号如果该信号低于阈值直接禁止该股票进入候选池。这本质上偏离了纯格雷厄姆风格但属于在原则与市场现实之间必要的妥协。问题根因解决方向财务数据错位信息披露延迟校验最新财报日期抽查比对组合跑输等权基准约束过紧导致风格锁死加入市值梯队配额再平衡拉低收益换手率过高、摩擦成本大引入冷静期与偏离度触发机制打分模型失效因子滞后、对极端流动性无感增加动量与流动性刹车因子这些问题没有一个是靠单一模型能彻底解决的更多是靠工程层面的容错设计和人工复核。格雷厄姆的分散原则提供的是方向工程的细节则决定了这套方向能否在真实行情中走通。结尾我的实操体会最后简单说一点个人感受。做完了这套系统后我最大的体会是格雷厄姆的分散投资原则本身并不是一个“收益最大化”的策略而是一个“生存最大化”策略。它所有的克制、限制、分散、再平衡本质上都在做一件事——让组合在任何极端行情里都不至于被彻底击垮。AI技术的加入真正改变的是执行层面的纪律性人可以靠意志力坚持原则一两年但做不到十年如一日地在暴跌中补仓、在泡沫中减仓机器可以。如果你也想动手做一套类似的系统我的建议是先不要追求模型复杂度从硬编码的规则筛选加等权分散开始。跑通一轮完整的季度再平衡之后再逐步引入打分排序和组合优化。你踩的每一个数据坑、每一处参数Bug都会成为策略实盘可靠性的基石。这套系统在量化工具算不上前沿但它让我第一次理解了什么叫“用纪律对抗人性”。
阅读完成 · 觉得有帮助?