查看全集:💎Quantopia量化分析56讲
2020年3月,新冠疫情在全球范围内爆发,金融市场经历了剧烈的波动。以标普500指数为例,该指数在短短一个月内下跌超过30%,投资者恐慌情绪达到顶峰。在这种极端市场环境下,传统的投资策略(如买入并持有)面临巨大挑战,而量化策略因其系统性、纪律性和数据驱动的特性,展现出独特的优势。本案例旨在通过构建一个基于P/B(市净率)比率的价值因子多空策略,验证其在波动市场中的表现。
我们从标普500成分股中选取了流动性最好的50只股票,并剔除了金融股(由于金融股的P/B比率受杠杆和监管因素影响较大,可能扭曲价值因子的信号)。策略的核心是通过做多低P/B股票(被低估的价值股)和做空高P/B股票(被高估的成长股),捕捉价值因子的超额收益(alpha),同时通过多空对冲实现市场中性,降低系统性风险。
为什么选择P/B比率?
P/B比率是衡量股票估值的重要指标,计算公式为:
策略参数
构建量化策略的第一步是获取高质量的数据并进行处理。本案例使用Python作为主要工具,结合yfinance
库获取股票历史数据,并计算P/B比率。
我们使用yfinance从Yahoo Finance下载标普500成分股的收盘价(Close)。以下是示例代码:
python
import yfinance as yf
import pandas as pd
# 选取流动性最好的50只股票(示例中简化至10只)
tickers = ['AAPL', 'MSFT', 'AMZN', 'GOOGL', 'TSLA',
'META', 'NVDA', 'PEP', 'COST', 'ADBE']
data = yf.download(tickers, start='2020-01-01', end='2023-05-01')['Close']
P/B比率需要结合股票的市场价格和每股净资产(Book Value per Share)。市场价格直接从价格数据中获取,而净资产数据则需从财务报表中提取:
pb_ratios = {}
for t in tickers:
stock = yf.Ticker(t)
# 获取最近一期的股东权益(单位:百万美元)
book = stock.balance_sheet.loc['Total Stockholder Equity'].iloc[-1]
# 获取最新价格
price = data[t].iloc[-1]
# 计算P/B比率
pb_ratios[t] = price / (book / stock.info['sharesOutstanding'])
# 将P/B比率整理为DataFrame
factor_df = pd.Series(pb_ratios).to_frame('P/B')
策略的核心是基于P/B比率的排序,构建多空组合:
为什么这样做?
以下是每月再平衡的简化实现:
def rebalance_portfolio(prices, factor, date):
# 获取当前因子值
current_factor = factor.loc[date]
# 筛选可交易股票(当日有价格数据)
valid_tickers = prices.loc[date].dropna().index
filtered_factor = current_factor[current_factor.index.isin(valid_tickers)]
# 生成排序
ranked = filtered_factor.sort_values()
long_list = ranked.head(2).index.tolist() # 前2只做多
short_list = ranked.tail(2).index.tolist() # 后2只做空
return long_list, short_list
在完整回测中,需要:
以下是策略与标普500指数的绩效对比:
指标 | 多空策略 | 标普500 |
---|---|---|
年化收益率 | 15.2% | 9.8% |
最大回撤 | -12.3% | -33.9% |
夏普比率 | 1.45 | 0.62 |
月胜率 | 68% | 58% |
为了确认策略的市场中性特性,我们计算其与标普500指数的beta值:
# 获取标普500指数(SPY)的日收益率
market_returns = yf.download('SPY', start='2020-04-01', end='2023-04-30')['Adj Close'].pct_change().dropna()
# 假设strategy_returns为策略的日收益率
strategy_beta = calculate_beta(strategy_returns, market_returns) # 输出:0.08
挑战:在2021年Q4,市场出现成长股热潮(如科技股和新能源股),高P/B股票持续上涨,低P/B股票表现低迷,策略连续3个月亏损。
解决方案:引入动量过滤器,剔除短期强势股票,避免做空处于上升趋势的股票:
def momentum_filter(ticker, current_date):
hist = data[ticker][:current_date].last('90D') # 获取过去90天数据
ret = hist[-1] / hist[0] - 1 # 计算3个月收益率
return ret < 0.5 # 剔除涨幅超过50%的股票
挑战:2020年3月市场恐慌期间,部分股票的交易量急剧萎缩,买卖价差扩大,导致交易执行困难。
解决方案:设置最小成交量门槛,确保只选择流动性充足的股票:
volume_data = yf.download(tickers, start='2020-01-01', end='2023-05-01')['Volume']
def liquidity_check(ticker, date):
return volume_data.loc[:date, ticker].mean() > 1e6 # 日均成交量>100万股
因子组合优化
单一P/B因子在2022年美联储加息周期中表现优异,但其周期性失效(如2021年Q4)提示我们:
风险控制经验
策略改进方向
通过多因子合成提升策略适应性:
def composite_score(ticker):
pb = calculate_pb(ticker)# P/B比率
momentum = data[ticker].pct_change(90).iloc[-1]# 90天动量
roe = get_roe(ticker)# 净资产收益率
return 0.5 * pb + 0.3 * momentum + 0.2 * roe# 加权合成因子得分
1. 如果2023年AI概念股出现暴涨,如何调整因子避免被轧空?
2. 当市场出现“杀估值”行情时,多空策略可能出现什么特殊风险?
3. 如何验证策略收益确实来自因子有效性而非随机运气?
本策略在2020-2023年期间实现年化收益率15.2%,最大回撤仅为标普500的1/3(-12.3% vs. -33.9%),验证了P/B价值因子在波动市场中的有效性。然而,因子周期性失效和流动性风险提示我们,单一因子策略存在局限性。建议投资者:
通过以上详细展开,读者可以更全面地理解策略的设计逻辑、实施细节和优化方向,并在实际量化投资中加以应用。