1. 这节究竟解决什么实际问题?¶
4.9 多空股票市场中性策略 (Long-Short Equity) 的具体任务是:建立多空组合并拆解行业、Beta、杠杆和借券假设。 本节将明确输入数据、计算过程、输出及其在后续研究中的用途。
2. 前置知识¶
理解收益率、仓位、交易成本与基本技术指标。 对公式的理解应包括变量定义、单位、时间索引和适用条件。
3. 数据说明¶
默认固定历史样本。历史数据只能说明过去在既定假设下发生了什么,不能承诺未来收益。 运行前先检查 shape、日期范围、列名与缺失值。数据看起来能画图,不代表它适合回答研究问题。
4. 学习目标与完成标准¶
完成本节后,你应能用自己的话解释 4.9 多空股票市场中性策略 (Long-Short Equity) 的输入、计算步骤、输出和局限;尤其能说明:建立多空组合并拆解行业、Beta、杠杆和借券假设。 你还应能独立改动一个参数并解释结果为什么变化,指出至少一个会让结论失真的假设。
5. 核心概念与公式¶
回测按照明确的成交和成本假设重放历史数据。它不能完整复现未来流动性、订单竞争和系统故障。
策略收益 = 滞后仓位 × 资产收益 − 换手 × 成本;每一项都要有明确单位。 看到公式时依次确认:每个符号的单位是什么?它属于哪个时点?分母会不会为零?它是描述性统计量、预测量,还是交易规则?
6. 从零实现¶
原始代码按照“准备输入 → 计算中间量 → 得到结果 → 解释输出”的顺序组织。每个单元应检查变量类型、索引、维度和代表性数值。中间变量用于核对公式实现和定位计算错误。
7. 成熟库实现¶
回测框架替你管理订单和记录,不会自动判断数据、成本或策略假设是否合理。 使用库函数前先阅读参数含义、默认值和返回对象;库输出一个数字,并不说明这个数字适合你的交易假设。
8. 两种实现的差异¶
从零实现便于核对公式、调试和识别隐含假设;成熟库适合在计算逻辑已验证后复用。两种实现依赖相同的数据口径与时点假设,使用库函数不会改变输入数据的质量。
9. 预期结果与检查范围¶
你应看到维度正确的 Series/DataFrame、日期单调递增的索引,以及能支持“建立多空组合并拆解行业、Beta、杠杆和借券假设。”这一任务的表格或图形。金融日收益率均值通常接近 0;若出现极大的连续收益、空表、全 NaN 或索引错位,应先排查数据和对齐逻辑,而不是立即相信结果。
10. 常见错误与诊断¶
信号未滞后、把手续费只扣一次、忽略空仓收益、年化频率错配、将净值曲线当显著性证明。
诊断顺序:先打印类型与 shape,再看 head()/tail(),接着检查日期和 NaN,最后才比较数值。这样能避免在错误的对象上反复改参数。
11. 研究偏差检查¶
检查未来函数、幸存者偏差、重复测试集调参、成交可得性和失败区间;必须报告基线。 结果至少应与一个简单基线比较,并明确哪些部分只是教学演示。
12. 三层练习与答案¶
- 基础练习:验证一个中间变量、补全一段小计算,并用一句话解释输出。
- 研究练习:改变窗口、样本区间、约束或标的,记录哪些结论仍成立。
- 开放项目:把本节方法嵌入模块项目,报告基线、失败结果和限制。
题目在 ../exercises/04_backtesting/09_long_short_equity_exercises.ipynb;完整推导、可运行参考实现与结果检查在 ../solutions/04_backtesting/09_long_short_equity_solutions.ipynb。请先独立作答,再打开答案。
13. 延伸阅读¶
延伸材料:Advances in Financial Machine Learning(Lopez de Prado)。阅读记录应包括研究假设、数据频率、样本范围和结论适用条件。
14. 下一节¶
下一节是 10_performance_attribution。本节的概念会成为理解它的输入,而不是孤立的名词。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
np.random.seed(42)
n_stocks = 100
factor_scores = np.random.normal(0, 1, n_stocks)
fwd_returns = 0.05 * factor_scores + np.random.normal(0, 2, n_stocks)
df = pd.DataFrame({'factor_score': factor_scores, 'fwd_return': fwd_returns})
print(f'模拟股票池:{n_stocks} 只,IC={np.corrcoef(factor_scores, fwd_returns)[0,1]:.4f}')
模拟股票池:100 只,IC=-0.1130
import matplotlib.pyplot as plt
# 1. 设置系统自带的中文字体(这里使用黑体 SimHei)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 如果你想用微软雅黑,可以改成 ['Microsoft YaHei']
# 2. 解决更换字体后,负号(-)显示为方块的问题
plt.rcParams['axes.unicode_minus'] = False
1. 分位数赋权与多空两端收益¶
df['quintile'] = pd.qcut(df['factor_score'], q=5, labels=['Q1','Q2','Q3','Q4','Q5'])
df['weight'] = 0.0
df.loc[df['quintile']=='Q5', 'weight'] = 1.0/20
df.loc[df['quintile']=='Q1', 'weight'] = -1.0/20
long_ret = df[df['weight'] > 0]['fwd_return'].mean()
short_ret = df[df['weight'] < 0]['fwd_return'].mean()
strat_ret = (df['weight'] * df['fwd_return']).sum()
print(f'多头 Q5 平均收益: {long_ret:.4f}')
print(f'空头 Q1 平均收益: {short_ret:.4f}')
print(f'多空策略总收益 (Q5-Q1): {long_ret - short_ret:.4f}')
print(f'权重加权策略实际收益: {strat_ret:.4f}')
# 可视化
colors = ['green' if w>0 else ('red' if w<0 else 'lightgray') for w in df.sort_values('factor_score')['weight']]
plt.figure(figsize=(12, 4))
plt.bar(range(n_stocks), df.sort_values('factor_score')['weight'], color=colors)
plt.axhline(0, color='black', linewidth=0.8)
plt.title('多空股票策略持仓权重(按因子得分升序)')
plt.xlabel('股票(按因子得分升序排列)')
plt.ylabel('权重')
plt.tight_layout()
plt.show()
多头 Q5 平均收益: 0.4805 空头 Q1 平均收益: 0.9463 多空策略总收益 (Q5-Q1): -0.4658 权重加权策略实际收益: -0.4658
2. 美元中性 vs Beta 中性¶
| 类型 | 目标 | 优点 | 缺点 |
|---|---|---|---|
| 美元中性 | 多头金额 = 空头金额 | 简单 | 可能有 Beta 暴露 |
| Beta 中性 | 组合 Beta = 0 | 完全对冲市场 | 需动态调整 |
dollar_long = df[df['weight']>0]['weight'].sum()
dollar_short = df[df['weight']<0]['weight'].sum()
print(f'多头权重合计: {dollar_long:+.4f}')
print(f'空头权重合计: {dollar_short:+.4f}')
print(f'净权重(应趋近0): {dollar_long+dollar_short:+.6f}')
beta_long = 1.2 # 假设多头平均 Beta
beta_short = 0.7 # 假设空头平均 Beta
portfolio_beta = dollar_long * beta_long + dollar_short * beta_short
print(f'\n组合 Beta(非 Beta 中性): {portfolio_beta:.4f}')
print('处理方法:额外做空股指期货以中和剩余 Beta')
多头权重合计: +1.0000 空头权重合计: -1.0000 净权重(应趋近0): +0.000000 组合 Beta(非 Beta 中性): 0.5000 处理方法:额外做空股指期货以中和剩余 Beta
练习¶
- 将因子得分层数改为 3 分位(T3 vs B3)和 10 分位(D10 vs D1),对比哪种分位方式的 IC 和策略夏普更高。
- 实现一个动态 Beta 识别继续训练,如果当前组合 Beta > 0.1,自动调整空头权重使 Beta 放回 0。
- 在同样的因子得分下,分别计算价格加权和市值加权两种权重方式对策略 Sharpe 比率的影响。
下一节 → 07_kalman_filter_applications.ipynb