这是一个根据PE、PB在指数历史低估区间时买入,长期持有,然后在PE、PB处于历史高位时卖出的策略。
这个策略极其简单,适用于大部分宽基指数;
这个策略是跑不赢指数的,但是能让你极其安心的长期持有;
谨记:一切回测有效的策略都是看后视镜开车。回测仅仅是参考,不能预测未来。
谨记:成功概率不能预测,失败风险无法回避,历史周期不断重复,时刻抱有敬畏之心。
指数特点
背靠国运,不死鸟
长期上涨
成本低
不择股
容易量化
大道至简
低估不定期不定额策略
我们的策略制定原则:
可复现、可回测
排除人工干扰,机器拯救人类
落子无悔,买定离手
低估买,高估卖,没有机会不动
资金分为50份分批投入
买入条件
市场出现系统性低估机会可以买入
单一标的PE、PB 处于历史30%以下可以买入
PB处于历史30%以下,且PE<10 或 1/PE<十年期国债利率X2,可以买入
卖出条件
市场出现系统性高估机会可以卖出
单一标的PE、PB 处于历史70%以上可以卖出
1/PE<市场能找到的最小无风险收益率,可以卖出置换
简单持有
不符合买入,也不符合卖出条件,简单持有即可。
若市场利率缓慢下行,可简单买入短债基金持有,其他情况不动。
凯利公式控制仓位
采用银行螺丝钉的方法计算仓位;
策略特点:
这个策略的收益在很多人看来是非常垃圾的,我期望的比较乐观的情况是总资金4%-7%的年化收益
把这个策略看成是一个人的话,他超级胆小,超级吝啬,超级怕死,只有在他的把握非常非常大的时候,才敢抛出仅仅一个筹码。即使是2018年的钻石底,他买入也很少。
这个策略基本上建仓时间在3年以上,什么也不做的时间
基本上5年以上。这段时间内,现金可以买入货基打底。所以这个策略的收益你可以再乐观的 3% ;
我相信一个策略带有其人格化,我相信世界上有许多极度胆小,不求暴富,只希望四平八稳取得微小的幸福的人,理所当然应该有这个极度简单,极度保守的策略来服务他们;
再重复说明一下: 这个策略不是为了高收益,不是为了跑赢指数,甚至在3-5年内,不是为了跑赢银行理财;而是让你长期持有!所谓长期,是5年,10年以上;最重要的是安全边际,是控制风险。 这个策略是我以极度保守思考的思路思考之后的结果,我个人有25%的仓位用这个策略慢慢建仓,如果持有现金换成货基,我期待长期年化6%~10%左右。 它是跑不赢指数的。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import bisect
import warnings
warnings.filterwarnings("ignore")
#指定日期的指数PE(市值加权)
def get_index_pe_date(index_code,date):
stocks = get_index_stocks(index_code, date)
q = query(valuation).filter(valuation.code.in_(stocks))
df = get_fundamentals(q, date)
df = df[df['pe_ratio'] > 0]
if len(df) > 0:
#pe = len(df)/sum([1/p if p>0 else 0 for p in df.pe_ratio])
#pe = df['pe_ratio'].size/(1/df['pe_ratio']).sum()
pe = df['circulating_market_cap'].sum()/(df['circulating_market_cap']/df['pe_ratio']).sum()
return pe
else:
return float('NaN')
#指定日期的指数PB(市值加权)
def get_index_pb_date(index_code,date):
stocks = get_index_stocks(index_code, date)
q = query(valuation).filter(valuation.code.in_(stocks))
df = get_fundamentals(q, date)
df = df[df['pb_ratio']>0]
if len(df)>0:
#pb = len(df)/sum([1/p if p>0 else 0 for p in df.pb_ratio])
#pb = df['pb_ratio'].size/(1/df['pb_ratio']).sum()
pb = df['circulating_market_cap'].sum()/(df['circulating_market_cap']/df['pb_ratio']).sum()
return pb
else:
return float('NaN')
#指数历史PEPB
def get_index_pe_pb(index_code):
start='2011-1-1'
end = pd.datetime.today();
dates=[]
pes=[]
pbs=[]
for d in pd.date_range(start,end,freq='W'): #频率为周
dates.append(d)
pes.append(get_index_pe_date(index_code,d))
pbs.append(get_index_pb_date(index_code,d))
d = {
'PE' : pd.Series(pes, index=dates),
'PB' : pd.Series(pbs, index=dates)
}
PB_PE = pd.DataFrame(d)
return PB_PE
all_index = get_all_securities(['index'])
index_choose =['000016.XSHG',
'000300.XSHG',
'000902.XSHG',
'000905.XSHG',
'399106.XSHE',
'399316.XSHE',
'000036.XSHG',
'000037.XSHG',
'000038.XSHG',
'000039.XSHG',
'000158.XSHG'
]
index_choose = [
'000300.XSHG', # :'沪深300', #000176.OF 嘉实沪深300增强
'000905.XSHG', # :'中证500', #000478.OF 建信中证500增强
'000919.XSHG', #:'300价值', #310398.OF 申万沪深300价值
'000922.XSHG', #:'中证红利', #100032.OF 富国中证红利
'399702.XSHE', #:'深证F120', #070023.OF 嘉实深F120基本面联接
'399978.XSHE', #:'中证医药100',#001550.OF 天弘中证医药100
'399812.XSHE', #:'中证养老' #000968.OF 广发中证养老指数
'000932.XSHG', # 中证消费
]
df_pe_pb = pd.DataFrame()
frames =pd.DataFrame()
today = pd.datetime.today()
for code in index_choose:
index_name = all_index.ix[code].display_name
print('正在处理: ', index_name)
df_pe_pb = get_index_pe_pb(code)
results=[]
pe = get_index_pe_date(code, today)
q_pes = [df_pe_pb['PE'].quantile(i / 10.0) for i in range(11)]
idx = bisect.bisect(q_pes, pe)
quantile = idx - (q_pes[idx] - pe) / (q_pes[idx] - q_pes[idx-1])
#index_name = all_index.ix[code].display_name
results.append([index_name,
format(pe, '.2f'),
format(quantile * 10, '.2f')] +
[format(q, '.2f') for q in q_pes] +
[df_pe_pb['PE'].count()])
pb = get_index_pb_date(code, today)
q_pbs = [df_pe_pb['PB'].quantile(i / 10.0) for i in range(11)]
idx = bisect.bisect(q_pbs, pb)
quantile = idx - (q_pbs[idx] - pb) / (q_pbs[idx] - q_pbs[idx-1])
#index_name = all_index.ix[code].display_name
results.append([index_name,
format(pb, '.2f'),
format(quantile * 10, '.2f')] +
[format(q, '.2f') for q in q_pbs] +
[df_pe_pb['PB'].count()])
df_pe_pb['10% PE']=q_pes[1]
df_pe_pb['50% PE']=q_pes[5]
df_pe_pb['90% PE']=q_pes[9]
df_pe_pb['10% PB']=q_pbs[1]
df_pe_pb['50% PB']=q_pbs[5]
df_pe_pb['90% PB']=q_pbs[9]
plt.rcParams['font.sans-serif']=['SimHei']
df_pe_pb.plot(secondary_y=['PB','10% PB','50% PB','90% PB'],
figsize=(14,8), title = index_name,
style=['k-.', 'k', 'g', 'y', 'r', 'g-.', 'y-.', 'r-.'])
columns=['名称', '当前估值', '分位点%', '最小估值'] + \
[format(i * 10, 'd') + '%%' for i in range(1,10)] + \
['最大估值' , '数据个数']
df= pd.DataFrame(data = results,
index = ['PE','PB'],
columns = columns)
frames = pd.concat([frames, df])
frames