解锁量化价值投资,实现投资组合优化目标

从菜市场到华尔街:用量化思维解锁价值投资的密码

关键词

量化价值投资 | 投资组合优化 | 因子模型 | Markowitz均值-方差 | 回测系统 | 风险控制 | 夏普比率

摘要

你有没有过这样的经历:在菜市场挑菜时,会反复比较“新鲜度”和“价格”——想选最新鲜的,又不想花太多钱?其实,这和价值投资的核心逻辑惊人地相似:买“质地好”且“估值低”的资产。只不过,华尔街的投资者把“新鲜度”换成了“ROE(净资产收益率)”,把“价格”换成了“P/E(市盈率)”,并用数学模型代替了直觉判断。

本文将带你从“菜市场逻辑”出发,一步步拆解量化价值投资的底层框架:如何用数据筛选“便宜的好公司”?如何通过数学模型优化投资组合,平衡“收益”与“风险”?如何用代码实现策略并验证效果?最终,你将掌握一套可复制的量化投资方法,把“拍脑袋”的投资变成“可计算”的科学。

一、背景介绍:为什么需要量化价值投资?

1.1 价值投资的“老问题”

价值投资的理念源于本杰明·格雷厄姆的《证券分析》(1934年),核心思想是“买低于内在价值的资产”。比如,一家公司的内在价值是10元,而当前股价是8元,就值得买入——这像极了菜市场里“捡漏”新鲜又便宜的蔬菜。

但传统价值投资有个致命缺陷:依赖主观判断。比如,“内在价值”的计算需要预测未来现金流,而不同分析师的预测结果可能相差巨大;“估值低”的标准也很模糊——有人认为P/E<10是低估值,有人觉得P/E<15才合理。这种主观性导致很多投资者“买了看似便宜的垃圾股”(比如绩差股的P/E很低,但根本没有盈利),或者“错过真正的好公司”(比如成长股的P/E很高,但未来盈利增长能覆盖估值)。

1.2 量化价值投资的“新解法”

量化价值投资的出现,就是为了用数据驱动模型决策解决传统价值投资的主观问题。它的核心逻辑可以总结为:

  • 用“因子”替代“主观判断”:把“质地好”转化为可量化的指标(比如ROE>15%、净利润增速>10%),把“估值低”转化为P/E<行业均值、P/B<2等指标;
  • 用“组合优化”替代“单一选股”:通过数学模型计算各股票的权重,平衡“分散风险”和“集中收益”;
  • 用“回测”替代“事后诸葛亮”:用历史数据验证策略的有效性,避免“纸上谈兵”。

1.3 谁需要读这篇文章?

  • 程序员:想把编程技能应用到投资领域,实现“代码赚钱”;
  • 金融从业者:想提升投资决策的科学性,减少人为误差;
  • 普通投资者:想告别“听消息炒股”,掌握一套可复制的投资方法。

1.4 核心挑战

本文要解决的核心问题是:如何将价值投资的逻辑转化为可量化、可验证的策略,并通过组合优化实现“风险可控的收益最大化”。具体来说,你将学会:

  • 如何用因子筛选“便宜的好公司”?
  • 如何用Markowitz模型计算最优投资组合?
  • 如何用代码回测策略,避免“过拟合”?

二、核心概念解析:用菜市场比喻搞懂量化价值投资

为了让复杂概念更易理解,我们用“菜市场买菜”的场景类比量化价值投资的核心环节:

菜市场场景量化价值投资对应环节关键指标/工具
选“新鲜的菜”(质地好)选“质地好的公司”ROE(净资产收益率)、净利润增速
选“便宜的菜”(估值低)选“估值低的公司”P/E(市盈率)、P/B(市净率)
搭配“蔬菜+肉类+主食”(分散)构建“分散化投资组合”协方差矩阵、Markowitz模型
用“秤”称重量(验证)用“回测”验证策略有效性夏普比率、最大回撤

2.1 因子:量化价值投资的“秤”

在菜市场,你用“眼睛看新鲜度”“手摸硬度”判断菜的质地;在量化投资中,你用“因子”(Factor)判断公司的质地和估值。

(1)什么是因子?

因子是能解释股票收益差异的可量化指标。比如:

  • 价值因子:衡量估值高低,如P/E(股价/每股收益)、P/B(股价/每股净资产)、股息率(股息/股价);
  • 质量因子:衡量公司质地,如ROE(净利润/净资产)、净利润增速(同比增长)、资产负债率(负债/资产);
  • 动量因子:衡量价格趋势,如过去6个月的涨幅;
  • 流动性因子:衡量交易活跃度,如日均成交量。
(2)因子的“有效性”:为什么低P/E股票能赚钱?

根据有效市场假说,超额收益来自“承担未被定价的风险”。比如,低P/E股票通常是市场忽略的“冷门股”,投资者需要承担“流动性风险”或“业绩修复风险”,因此能获得超额收益。

举个例子:假设市场上有两家公司,A公司P/E=10(每股收益1元,股价10元),B公司P/E=20(每股收益1元,股价20元)。如果两家公司的盈利增速相同,那么A公司的“性价比”更高——就像菜市场里“10元一斤的新鲜菜”比“20元一斤的同品质菜”更值得买。

(3)因子筛选流程:从“全市场”到“候选池”

量化价值投资的第一步,是用因子从全市场股票中筛选出“便宜的好公司”。流程如下(用Mermaid画流程图):

graph TD
    A[全市场股票] --> B[筛选条件1:质量因子(ROE>15%、净利润增速>10%)]
    B --> C[筛选条件2:价值因子(P/E<行业均值、P/B<2)]
    C --> D[筛选条件3:流动性因子(日均成交量>1亿)]
    D --> E[候选股票池(约50-100只)]

说明

  • 质量因子确保公司“质地好”(能持续盈利);
  • 价值因子确保公司“估值低”(价格低于内在价值);
  • 流动性因子确保股票“能买能卖”(避免买了卖不出去)。

2.2 投资组合优化:像搭配早餐一样平衡“营养”与“热量”

选好了“候选股票池”,接下来要解决的问题是:每只股票买多少? 比如,候选池里有10只股票,是平均分配资金(每只10%),还是集中买几只?

这就像搭配早餐:你需要平衡“营养”(收益)和“热量”(风险)——只吃蛋糕(高收益高风险)会胖,只吃蔬菜(低风险低收益)会饿,最好的选择是“蛋糕+蔬菜+牛奶”的组合(收益适中,风险适中)。

(1)投资组合的“营养”与“热量”
  • 预期收益(E®):组合的平均收益,等于各股票预期收益的加权和:
    E(rp)=∑i=1nwiE(ri) E(r_p) = \sum_{i=1}^n w_i E(r_i) E(rp)=i=1nwiE(ri)
    其中,wiw_iwi是第iii只股票的权重(∑wi=1\sum w_i=1wi=1),E(ri)E(r_i)E(ri)是第iii只股票的预期收益。
  • 风险(σ_p):组合的波动,用方差衡量,等于各股票协方差的加权和:
    σp2=∑i=1n∑j=1nwiwjCov(ri,rj) \sigma_p^2 = \sum_{i=1}^n \sum_{j=1}^n w_i w_j \text{Cov}(r_i, r_j) σp2=i=1nj=1nwiwjCov(ri,rj)
    其中,Cov(ri,rj)\text{Cov}(r_i, r_j)Cov(ri,rj)是股票iiijjj的协方差(衡量两者收益的相关性)。
(2)Markowitz均值-方差模型:找到“最优早餐组合”

1952年,哈里·马科维茨(Harry Markowitz)提出了均值-方差模型,核心思想是:在给定风险水平下,最大化预期收益;或在给定预期收益水平下,最小化风险

用早餐比喻,就是:

  • 如果你能接受“中等热量”(风险),那么选“营养最高”(收益)的组合;
  • 如果你想“营养最低”(收益)不低于某个值,那么选“热量最低”(风险)的组合。
(3)有效前沿:所有“最优组合”的集合

通过均值-方差模型计算,我们可以得到有效前沿(Efficient Frontier)——这是一条曲线,曲线上的每个点都是“给定风险下收益最高”或“给定收益下风险最低”的组合。

比如,假设候选池中有3只股票:

  • 股票A:预期收益10%,风险(σ)20%;
  • 股票B:预期收益8%,风险15%;
  • 股票C:预期收益6%,风险10%。

通过调整权重,我们可以得到不同的组合:

  • 组合1(全A):收益10%,风险20%;
  • 组合2(A+B=50%+50%):收益9%,风险17%(假设协方差为0.5);
  • 组合3(B+C=50%+50%):收益7%,风险12%;
  • 组合4(全C):收益6%,风险10%。

这些组合的有效前沿是一条从组合4到组合1的曲线,曲线上的每个点都是“最优”的。

三、技术原理与实现:用Python构建量化价值投资策略

3.1 工具准备

  • 数据获取:用yfinance获取股票历史数据(免费);
  • 因子计算:用pandas处理财务数据;
  • 组合优化:用cvxpy(凸优化库)求解Markowitz模型;
  • 回测:用backtrader验证策略有效性。

3.2 步骤1:获取数据与计算因子

(1)获取股票列表

首先,我们需要从全市场中筛选出符合条件的股票。比如,选沪深300成分股(代表大盘蓝筹股),或者中证500成分股(代表中盘成长股)。

yfinance获取沪深300成分股列表(以美股为例,A股可以用tusharebaostock):

import yfinance as yf
import pandas as pd

# 获取沪深300成分股(示例用美股SP500代替)
sp500 = yf.Ticker("^GSPC")
sp500_components = sp500.components
tickers = sp500_components.index.tolist()[:100]  # 取前100只股票
(2)计算因子

接下来,计算每只股票的质量因子(ROE、净利润增速)和价值因子(P/E、P/B)。

以ROE为例,ROE=净利润/净资产,我们可以用yfinance获取财务数据:

def calculate_roe(ticker):
    try:
        stock = yf.Ticker(ticker)
        financials = stock.financials
        balance_sheet = stock.balance_sheet
        
        # 净利润(最近12个月)
        net_income = financials.loc["Net Income"].iloc[0]
        # 净资产(最近季度)
        equity = balance_sheet.loc["Total Stockholder Equity"].iloc[0]
        
        roe = net_income / equity
        return roe
    except:
        return None

# 计算所有股票的ROE
roe_data = pd.Series({ticker: calculate_roe(ticker) for ticker in tickers})
roe_data = roe_data.dropna()  # 剔除数据缺失的股票

同理,计算P/E(股价/每股收益):

def calculate_pe(ticker):
    try:
        stock = yf.Ticker(ticker)
        pe = stock.info["trailingPE"]  #  trailing P/E( trailing 12 months)
        return pe
    except:
        return None

pe_data = pd.Series({ticker: calculate_pe(ticker) for ticker in tickers})
pe_data = pe_data.dropna()
(3)筛选候选股票池

根据因子筛选条件,比如:

  • ROE>15%(质量好);
  • P/E<行业均值(估值低);
  • 日均成交量>1亿(流动性好)。
# 计算行业均值(假设用GICS行业分类)
sp500_components["industry"] = sp500_components["GICS Sector"]
industry_pe = sp500_components.merge(pe_data, left_index=True, right_index=True)
industry_pe_mean = industry_pe.groupby("industry")["PE"].mean()

# 筛选条件
selected_stocks = roe_data[roe_data > 0.15].index  # ROE>15%
selected_stocks = pe_data[pe_data < industry_pe_mean[pe_data.index.map(sp500_components["industry"])]]  # P/E<行业均值
selected_stocks = selected_stocks[selected_stocks.index.isin(selected_stocks)]  # 交集

# 筛选流动性(示例用最近30天日均成交量>1亿)
def calculate_volume(ticker):
    try:
        stock = yf.Ticker(ticker)
        volume = stock.history(period="1mo")["Volume"].mean()
        return volume
    except:
        return None

volume_data = pd.Series({ticker: calculate_volume(ticker) for ticker in selected_stocks.index})
selected_stocks = volume_data[volume_data > 1e8].index  # 日均成交量>1亿

print(f"候选股票池数量:{len(selected_stocks)}")

3.3 步骤2:用Markowitz模型优化组合权重

(1)计算预期收益与协方差矩阵

预期收益通常用历史平均收益代替(假设未来收益与历史一致),协方差矩阵用历史收益的协方差计算。

import numpy as np

# 获取历史收益数据(最近5年,月频)
def get_monthly_returns(ticker):
    try:
        stock = yf.Ticker(ticker)
        returns = stock.history(period="5y", interval="1mo")["Close"].pct_change().dropna()
        return returns
    except:
        return None

# 收集所有候选股票的月收益
returns_data = pd.DataFrame({ticker: get_monthly_returns(ticker) for ticker in selected_stocks})
returns_data = returns_data.dropna(axis=1)  # 剔除数据缺失的股票

# 计算预期收益(月均收益)
expected_returns = returns_data.mean()

# 计算协方差矩阵
cov_matrix = returns_data.cov()
(2)构建优化问题

我们的目标是最大化夏普比率(Sharpe Ratio),即“每承担1单位风险获得的超额收益”:
Sharpe Ratio=E(rp)−rfσp \text{Sharpe Ratio} = \frac{E(r_p) - r_f}{\sigma_p} Sharpe Ratio=σpE(rp)rf
其中,rfr_frf是无风险利率(比如10年期国债收益率,约3%/年,即0.25%/月)。

cvxpy构建优化问题:

import cvxpy as cp

# 变量:各股票的权重(w)
w = cp.Variable(len(expected_returns))

# 约束条件:
# 1. 权重和为1(满仓)
constraints = [cp.sum(w) == 1]
# 2. 权重非负(不允许卖空)
constraints.append(w >= 0)

# 目标函数:最大化夏普比率(等价于最大化(预期收益-无风险利率)/ 风险)
risk_free_rate = 0.03 / 12  # 月无风险利率
expected_excess_returns = expected_returns - risk_free_rate
portfolio_return = expected_excess_returns @ w
portfolio_risk = cp.quad_form(w, cov_matrix)  # 方差
sharpe_ratio = portfolio_return / cp.sqrt(portfolio_risk)

# 优化问题:最大化夏普比率
problem = cp.Problem(cp.Maximize(sharpe_ratio), constraints)
problem.solve()

# 输出最优权重
optimal_weights = pd.Series(w.value, index=expected_returns.index)
optimal_weights = optimal_weights[optimal_weights > 1e-4]  # 剔除权重极小的股票
optimal_weights = optimal_weights / optimal_weights.sum()  # 重新归一化

print("最优投资组合权重:")
print(optimal_weights.round(4))
(3)结果解释

假设候选池中有10只股票,优化后的权重可能是:

股票代码权重(%)
AAPL15.2
MSFT12.8
JPM10.5

这些权重的组合,能在“承担一定风险”的前提下,获得最高的夏普比率——就像“早餐组合”中,蛋糕占15%、蔬菜占12%、牛奶占10%,这样既能吃饱,又不会太胖。

3.4 步骤3:回测策略有效性

回测是量化投资的“试金石”——用历史数据验证策略是否能赚钱。我们用backtrader库进行回测。

(1)构建策略类
import backtrader as bt

class QuantitativeValueStrategy(bt.Strategy):
    params = (
        ("rebalance_month", 6),  # 每6个月再平衡一次
        ("roe_threshold", 0.15),  # ROE>15%
        ("pe_threshold", 15),     # P/E<15(示例用固定阈值,实际用行业均值)
    )

    def __init__(self):
        self.month_counter = 0  # 月份计数器
        self.stocks = selected_stocks  # 候选股票池(从步骤2获取)

    def next(self):
        # 每6个月再平衡一次
        self.month_counter += 1
        if self.month_counter % self.params.rebalance_month != 0:
            return

        # 计算当前因子(ROE、P/E)
        roe_data = pd.Series({ticker: calculate_roe(ticker) for ticker in self.stocks})
        pe_data = pd.Series({ticker: calculate_pe(ticker) for ticker in self.stocks})

        # 筛选符合条件的股票
        selected = roe_data[roe_data > self.params.roe_threshold].index
        selected = pe_data[pe_data < self.params.pe_threshold].index
        selected = selected.intersection(self.stocks)

        # 如果没有符合条件的股票,持有现金
        if not selected.empty:
            # 计算最优权重(用Markowitz模型,省略重复代码)
            optimal_weights = self.calculate_optimal_weights(selected)
            # 调整仓位:卖出不在选中列表的股票,买入选中的股票
            for d in self.getdatanames():
                if d not in selected:
                    self.order_target_percent(d, 0)
                else:
                    self.order_target_percent(d, optimal_weights[d])
        else:
            # 卖出所有股票,持有现金
            for d in self.getdatanames():
                self.order_target_percent(d, 0)

    def calculate_optimal_weights(self, selected):
        # 省略与步骤3.3相同的代码,返回最优权重
        pass
(2)运行回测
# 初始化回测引擎
cerebro = bt.Cerebro()

# 添加策略
cerebro.addstrategy(QuantitativeValueStrategy)

# 添加数据(示例用美股数据)
for ticker in selected_stocks:
    data = bt.feeds.YahooFinanceData(
        dataname=ticker,
        fromdate=pd.Timestamp("2018-01-01"),
        todate=pd.Timestamp("2023-12-31"),
        interval="1mo"
    )
    cerebro.adddata(data)

# 设置初始资金
cerebro.broker.setcash(100000.0)

# 设置佣金(0.1%)
cerebro.broker.setcommission(commission=0.001)

# 运行回测
print(f"初始资金:{cerebro.broker.getvalue():.2f}")
cerebro.run()
print(f"最终资金:{cerebro.broker.getvalue():.2f}")

# 绘制收益曲线
cerebro.plot(style="candlestick")
(3)回测结果分析

假设回测结果如下:

  • 初始资金:100,000元;
  • 最终资金:180,000元;
  • 年化收益:12%;
  • 夏普比率:1.5;
  • 最大回撤:15%(即历史上最大亏损幅度)。

对比基准(比如沪深300指数)的年化收益8%、夏普比率1.0,说明量化价值策略在风险可控的前提下,获得了更高的收益

四、实际应用:常见问题与解决方案

4.1 问题1:因子失效怎么办?

现象:某因子(比如低P/E)在过去10年有效,但最近1年失效(低P/E股票反而下跌)。
原因

  • 市场风格变化(比如从“价值股”转向“成长股”);
  • 因子拥挤(太多投资者使用同样的因子,导致超额收益消失)。
    解决方案
  • 因子轮换:定期更新因子(比如每季度重新筛选有效因子);
  • 因子组合:使用多个因子(比如低P/E+高ROE+高股息率),降低单一因子的风险;
  • 机器学习:用随机森林、XGBoost等模型预测因子的有效性(比如预测“下一季度哪些因子能带来超额收益”)。

4.2 问题2:回测过拟合怎么办?

现象:策略在历史数据中表现很好,但实盘运行时亏损。
原因

  • 数据 snooping(过度挖掘历史数据中的噪音);
  • 参数优化过度(比如为了拟合历史数据,调整参数到“完美”,但未来不适用)。
    解决方案
  • 交叉验证:将历史数据分成训练集和测试集(比如70%训练,30%测试),用训练集优化参数,用测试集验证效果;
  • 正则化:在优化模型中加入正则项(比如L1正则,限制权重的分散度),避免过度集中;
  • 样本外测试:用未参与回测的“新鲜数据”验证策略(比如回测用2018-2022年数据,用2023年数据做样本外测试)。

4.3 问题3:流动性风险怎么办?

现象:选中的股票日均成交量很小,买入时导致股价上涨(冲击成本),卖出时导致股价下跌。
原因

  • 股票市值小(比如小盘股);
  • 市场关注度低(比如冷门股)。
    解决方案
  • 筛选流动性因子:在候选池筛选时,加入“日均成交量>1亿”或“流通市值>50亿”的条件;
  • 限制单只股票权重:比如单只股票权重不超过5%,避免大额交易影响股价;
  • 分批次交易:比如将买入订单分成10笔,在一天内逐步执行,降低冲击成本。

五、未来展望:量化价值投资的“进化方向”

5.1 趋势1:结合机器学习,提升因子有效性

传统量化策略依赖“线性因子模型”(比如Fama-French三因子),而机器学习(比如深度学习、强化学习)能捕捉非线性关系动态变化。比如:

  • 用LSTM预测公司净利润增速(替代传统的“历史均值”);
  • 用Transformer分析新闻文本(比如从财报中提取“管理层信心”因子);
  • 用强化学习优化组合权重(根据市场变化动态调整)。

5.2 趋势2:大数据与另类数据的应用

传统量化策略用“财务数据”和“价格数据”,而另类数据(比如卫星图像、信用卡交易数据、社交媒体数据)能提供更及时、更全面的信息。比如:

  • 用卫星图像分析零售公司的停车场车辆数(预测销售额);
  • 用信用卡交易数据分析消费行业的景气度(预测净利润);
  • 用社交媒体 sentiment 分析(比如Twitter上的情绪)预测股价波动。

5.3 趋势3:区块链与智能合约的融合

区块链技术能解决量化投资中的“信任问题”和“执行效率”:

  • 透明化:用区块链记录策略的回测结果和实盘交易,避免“数据造假”;
  • 自动化:用智能合约自动执行交易(比如当股票达到目标价格时,自动卖出);
  • 去中心化:用DeFi(去中心化金融)平台进行量化交易,降低交易成本(比如无需券商佣金)。

5.4 潜在挑战

  • 技术门槛提高:机器学习和大数据需要更专业的知识(比如编程、统计学、深度学习);
  • 监管加强:量化交易的高频率和大额交易可能引发市场波动,监管机构可能出台更严格的规定(比如限制算法交易的频率);
  • 竞争加剧:越来越多的投资者使用量化策略,导致超额收益消失(比如“因子拥挤”问题)。

六、总结与思考

6.1 总结要点

  • 量化价值投资是数据驱动的价值投资:用因子筛选“便宜的好公司”,用模型优化组合权重,用回测验证策略有效性;
  • 核心逻辑是平衡风险与收益:通过Markowitz模型找到“最优组合”,最大化夏普比率;
  • 关键工具是编程与数学:用Python处理数据、计算因子、优化组合,用数学模型解释投资逻辑。

6.2 思考问题

  • 你认为“价值因子”(比如低P/E)在未来10年还会有效吗?为什么?
  • 如果你是一名普通投资者,没有编程基础,如何用量化思维优化自己的投资组合?
  • 量化投资中的“风险”除了市场波动,还有哪些?如何控制?

6.3 参考资源

  • 书籍:《证券分析》(格雷厄姆)、《量化投资策略》(Ernest Chan)、《Python量化投资》(Yves Hilpisch);
  • 论文:《The Cross-Section of Expected Stock Returns》(Fama & French,1992)、《Portfolio Selection》(Markowitz,1952);
  • 工具yfinance(数据获取)、cvxpy(组合优化)、backtrader(回测)、tushare(A股数据)。

结尾:从“菜市场”到“华尔街”的距离

其实,量化价值投资并不神秘——它只是把“菜市场挑菜”的逻辑,用数据和模型翻译成了华尔街的语言。你不需要是金融专家,也不需要是编程大师,只要掌握“因子筛选”“组合优化”“回测验证”这三个核心环节,就能把“拍脑袋”的投资变成“可计算”的科学。

下次你去菜市场挑菜时,不妨想想:“这棵菜的‘ROE’(新鲜度)怎么样?‘P/E’(价格)是不是低于行业均值?”——或许,你已经在无意识地使用量化价值投资的逻辑了。

愿你在投资的道路上,用数据做秤,用模型做菜谱,挑到最“划算”的资产!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值