Alpha对冲

ZaynPei Lv6

这是一个在机构投资者和对冲基金中广泛使用的市场中性策略,其目标是剥离市场的系统性风险(Beta),从而获取纯粹的、由选股能力带来的超额收益(Alpha)。

策略原理

Alpha (α) 与 Beta (β):解构投资收益的来源

在金融学中,投资收益通常可以分解为两部分:

  • Beta (β):代表市场收益和风险,反映了投资组合相对于市场整体的波动性。高 Beta 值意味着投资组合对市场变动的敏感度较高,可能带来更高的收益,但也伴随更大的风险。

  • Alpha (α):代表超额收益,反映了投资组合在剔除市场风险后所获得的额外回报。正 Alpha 值意味着投资经理的选股能力强,带来了独立于市场涨跌的超额收益。

通过对 Alpha 和 Beta 的分析,投资者可以更好地理解其投资组合的表现,并制定相应的对冲策略。

如何实现Alpha对冲? 策略的核心思想是通过同时持有多头和空头头寸,来剥离市场的系统性风险(Beta),从而专注于获取选股带来的超额收益(Alpha)。

  • 构建Alpha组合:首先,通过你的选股模型(在这个策略里是低EV/EBITDA因子),精心挑选出一篮子你认为会跑赢市场的股票,并买入它们(做多)。这个组合同时包含了你期望的Alpha和你不想要的Beta

  • 对冲Beta风险:同时,在股指期货市场上,做空与你股票组合市值相当股指期货合约。股指期货的涨跌与整个市场高度相关。

此时, 当市场上涨时,你的股票组合(大概率)会上涨,获得Beta收益;但你做空的股指期货会亏损, 两者相互抵消。

当市场下跌时,你的股票组合(大概率)会下跌,产生Beta亏损;但你做空的股指期货会盈利。

最终结果是, 通过期货的做空头寸,市场涨跌带来的Beta收益和亏损被相互抵消了。最后剩下的,就是你的选股组合跑赢市场基准的那一部分——纯粹的Alpha收益。

策略实现

本策略将上述原理转化为了一个清晰、可执行的月度调仓计划。

第一步:Alpha因子选择与组合构建

  • 选股池: 沪深300指数的成份股。

  • Alpha因子: EV/EBITDA (企业价值/息税折旧摊销前利润)。

    • 这是一个常用的价值因子,类似于市盈率(P/E)。它衡量的是一家公司的企业价值(市值+净负债)是其核心盈利能力的多少倍。EV/EBITDA值越低,通常意味着该公司可能被市场低估。
  • 策略假设: 选取EV/EBITDA值最低的一批股票,可以构建一个跑赢沪深300指数的Alpha组合。

  • 组合构建: 每月选取30只EV/EBITDA值最低且大于零的股票,并对它们进行等权重资金分配。

第二步:Beta对冲工具选择

  • 对冲工具: 沪深300股指期货 (CFFEX.IF)。因为股票池来自沪深300,所以用对应的股指期货来对冲,相关性最高,对冲效果最好。

第三步:调仓与执行

  • 每月调仓一次,卖出不再符合条件的旧股票,买入新选出的股票,并同时调整股指期货的空头头寸,使其名义价值与股票组合的总市值保持大致相等

策略代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# coding=utf-8
from __future__ import print_function, absolute_import, unicode_literals
from gm.api import *
'''
本策略每隔1个月定时触发计算SHSE.000300成份股的过去一天EV/EBITDA值并选取30只EV/EBITDA值最小且大于零的股票
对不在股票池的股票平仓并等权配置股票池的标的
并用相应的CFFEX.IF对应的真实合约等额对冲
回测数据为:SHSE.000300和他们的成份股和CFFEX.IF对应的真实合约
回测时间为:2017-07-01 08:00:00到2017-10-01 16:00:00
注意:本策略仅供参考,实际使用中要考虑到期货和股票处于两个不同的账户,需要人为的保证两个账户的资金相同。
'''
def init(context):
# 每月第一个交易日09:40:00的定时执行algo任务(仿真和实盘时不支持该频率)
schedule(schedule_func=algo, date_rule='1m', time_rule='09:40:00')
# 设置开仓在股票和期货的资金百分比(期货在后面自动进行杠杆相关的调整)
context.percentage_stock = 0.4
context.percentage_futures = 0.4
def algo(context):
# 获取当前时刻
now = context.now
# 获取上一个交易日
last_day = get_previous_trading_date(exchange='SHSE', date=now)
# 获取沪深300成份股的股票代码
stock300 = get_history_constituents(index='SHSE.000300', start_date=last_day,
end_date=last_day)[0]['constituents'].keys()
# 获取上一个工作日的CFFEX.IF对应的合约
index_futures = get_continuous_contracts(csymbol='CFFEX.IF', start_date=last_day, end_date=last_day)[-1]['symbol']
# 获取当天有交易的股票
not_suspended_info = get_history_instruments(symbols=stock300, start_date=now, end_date=now)
not_suspended_symbols = [item['symbol'] for item in not_suspended_info if not item['is_suspended']]
# 获取成份股EV/EBITDA大于0并为最小的30个
fin = get_fundamentals(table='trading_derivative_indicator', symbols=not_suspended_symbols,
start_date=now, end_date=now, fields='EVEBITDA',
filter='EVEBITDA>0', order_by='EVEBITDA', limit=30, df=True)
fin.index = fin.symbol
# 获取当前仓位
positions = context.account().positions()
# 平不在标的池或不为当前股指期货主力合约对应真实合约的标的
for position in positions:
symbol = position['symbol']
sec_type = get_instrumentinfos(symbols=symbol)[0]['sec_type']
# 若类型为期货且不在标的池则平仓
if sec_type == SEC_TYPE_FUTURE and symbol != index_futures:
order_target_percent(symbol=symbol, percent=0, order_type=OrderType_Market,
position_side=PositionSide_Short)
print('市价单平不在标的池的', symbol)
elif symbol not in fin.index:
order_target_percent(symbol=symbol, percent=0, order_type=OrderType_Market,
position_side=PositionSide_Long)
print('市价单平不在标的池的', symbol)
# 获取股票的权重
percent = context.percentage_stock / len(fin.index)
# 买在标的池中的股票
for symbol in fin.index:
order_target_percent(symbol=symbol, percent=percent, order_type=OrderType_Market,
position_side=PositionSide_Long)
print(symbol, '以市价单调多仓到仓位', percent)
# 获取股指期货的保证金比率
ratio = get_history_instruments(symbols=index_futures, start_date=last_day, end_date=last_day)[0]['margin_ratio']
# 更新股指期货的权重
percent = context.percentage_futures * ratio
# 买入股指期货对冲
# 注意:股指期货的percent参数是按照期货的保证金来算比例,不是按照合约价值, 比如说0.1就是用0.1的仓位的资金全部买入期货。
order_target_percent(symbol=index_futures, percent=percent, order_type=OrderType_Market,
position_side=PositionSide_Short)
print(index_futures, '以市价单调空仓到仓位', percent)
if __name__ == '__main__':
'''
strategy_id策略ID,由系统生成
filename文件名,请与本文件名保持一致
mode实时模式:MODE_LIVE回测模式:MODE_BACKTEST
token绑定计算机的ID,可在系统设置-密钥管理中生成
backtest_start_time回测开始时间
backtest_end_time回测结束时间
backtest_adjust股票复权方式不复权:ADJUST_NONE前复权:ADJUST_PREV后复权:ADJUST_POST
backtest_initial_cash回测初始资金
backtest_commission_ratio回测佣金比例
backtest_slippage_ratio回测滑点比例
'''
run(strategy_id='strategy_id',
filename='main.py',
mode=MODE_BACKTEST,
token='token_id',
backtest_start_time='2017-07-01 08:00:00',
backtest_end_time='2017-10-01 16:00:00',
backtest_adjust=ADJUST_PREV,
backtest_initial_cash=10000000,
backtest_commission_ratio=0.0001,
backtest_slippage_ratio=0.0001)