数据准备
选择如下几只股票,从tushare.org获取其2007-10-31到2017-10-31十年的交易数据,保存为csv文件以备后用:
- 招商证券 600999
- 广发证券 000776
- 万科a 000002
- 保利地产 600048
- 招商银行 600036
- 工商银行 601398
- 恒瑞医药 600276
- 同仁堂 600685
- 大族激光 002008
- 三安光电 600703
- 中国石油 601857
- 中国石化 600028
- ST中富 000659
- ST山水 600234
- 沪深300指数
import tushare as ts
import pandas as pd
codes=[
(u'招商证券','600999'),(u'广发证券','000776'),(u'万科a','000002'),
(u'保利地产','600048'),(u'招商银行','600036'),(u'工商银行','601398'),
(u'恒瑞医药','600276'),(u'同仁堂','600685'),(u'大族激光','002008'),
(u'三安光电','600703'),(u'中国石油','601857'),(u'中国石化','600028'),
(u'ST中富','000659'),(u'ST山水','600234'),(u'沪深300','hs300')
]
for c in codes:
df=ts.get_hist_data(c[1],start='2007-10-31',end='2017-10-31')
df.to_csv('assets/'+c[0]+'.csv')
print 'now '+c[0]+' earliest='+str(df.index[-1])
实际执行结果:
now 招商证券 earliest=2014-11-03
now 广发证券 earliest=2014-11-03
now 万科a earliest=2014-11-03
now 保利地产 earliest=2014-11-03
now 招商银行 earliest=2014-11-03
now 工商银行 earliest=2014-11-03
now 恒瑞医药 earliest=2014-11-03
now 同仁堂 earliest=2014-11-03
now 大族激光 earliest=2014-11-04
now 三安光电 earliest=2014-11-03
now 中国石油 earliest=2014-11-03
now 中国石化 earliest=2014-11-03
now ST中富 earliest=2014-11-03
now ST山水 earliest=2015-01-26
now 沪深300 earliest=2014-11-03
从结果看,只能选择 2014-11-03 之后到 2017-9-26 之前的数据,因为获取到的最早和最近的数据是这样。
%matplotlib inline
import matplotlib as mpl
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
plt.rcParams['font.sans-serif']=['SimHei']
# myfont=FontProperties(fname=u'C:\\Windows\Fonts\\幼圆.TTF')
mpl.rcParams['axes.unicode_minus']=False
# legend_font=FontProperties(fname=u'C:\\Windows\Fonts\\幼圆.TTF',size=10)
dpi = 72.
xinch = 800 / dpi
yinch = 400 / dpi
mpl.rcParams['figure.figsize']=(xinch,yinch)
stocks=[
(u'招商证券','600999'),(u'广发证券','000776'),(u'万科a','000002'),
(u'保利地产','600048'),(u'招商银行','600036'),(u'工商银行','601398'),
(u'恒瑞医药','600276'),(u'同仁堂','600685'),(u'大族激光','002008'),
(u'三安光电','600703'),(u'中国石油','601857'),(u'中国石化','600028'),
(u'ST中富','000659'),(u'ST山水','600234'),(u'沪深300','hs300')
]
codes={}
for s in stocks:
codes[s[0]]=s[1]
symbols=codes.keys()
def col_converter(x):
try:
return float(x)
except:
return None
prices=None
for i,s in enumerate(symbols):
p=pd.read_csv('assets/'+s.upper()+'.csv',usecols=['close','date'],index_col='date',converters={'close':col_converter})
if i==0:
prices=pd.DataFrame(index=p.index)
prices[s]=p['close']
prices.sort_index(ascending=True,inplace=True)
prices.dropna(inplace=True)
两支地产股和两支券商股的比较
股价波动情况
prices[[u'招商证券',u'广发证券',u'万科a',u'保利地产']].plot()
plt.ylabel(u'每日收盘价')
plt.xlabel(u'日期')
plt.legend()
print '----期初股价----'
print prices[[u'招商证券',u'广发证券',u'万科a',u'保利地产']].head(1)
print '----期末股价----'
print prices[[u'招商证券',u'广发证券',u'万科a',u'保利地产']].tail(1)
----期初股价----
招商证券 广发证券 万科a 保利地产
date
2015-02-03 24.9 22.3 12.96 10.15
----期末股价----
招商证券 广发证券 万科a 保利地产
date
2017-09-26 20.59 18.87 26.76 10.65
收益率比较
假定同时在2014-11-03日买入这四只股票和沪深300指数,比较一下到2017-9-26的收益率
prices_norm=prices.copy()
for symbol in symbols:
prices_norm[symbol]=prices[symbol]/prices[symbol][0]
prices_norm[[u'招商证券',u'广发证券',u'万科a',u'保利地产']].plot()
plt.ylabel(u'收益率')
plt.xlabel(u'日期')
plt.legend()
print prices_norm[[u'招商证券',u'广发证券',u'万科a',u'保利地产']].tail(1)
招商证券 广发证券 万科a 保利地产
date
2017-09-26 0.826908 0.846188 2.064815 1.049261
从图表来看,到2017-10-31为止,投资万科a收益率最高(是期初的206.4%),投资招商证券最低(是期初的82.70%,还在站岗中)。
股价波动情况比较
再看看两支券商股和两支地产股的收盘价波动情况,同时与沪深300的收盘价波动情况比较:
prices.pct_change()[[u'招商证券',u'广发证券',u'万科a',u'保利地产',u'沪深300']].plot()
plt.ylabel(u'每日波动率')
plt.xlabel(u'日期')
plt.legend()
print prices.pct_change()[[u'招商证券',u'广发证券',u'万科a',u'保利地产',u'沪深300']].describe()
招商证券 广发证券 万科a 保利地产 沪深300
count 332.000000 332.000000 332.000000 332.000000 332.000000
mean 0.000319 0.000345 0.002647 0.000730 0.000556
std 0.042842 0.042965 0.030688 0.033740 0.021790
min -0.297507 -0.313300 -0.100045 -0.229651 -0.151217
25% -0.009038 -0.007870 -0.011612 -0.011329 -0.004597
50% 0.000000 -0.000584 -0.000400 0.000460 0.000990
75% 0.008002 0.008111 0.010071 0.010879 0.005632
max 0.470405 0.551145 0.113119 0.169173 0.196912
从图像上看广发证券外波动最大,但是从区间收盘价标准差来看,其实招商证券和广发证券都在0.043附近,风险程度相近。保利地产标准差仅0.022,风险最小。
计算股价波动的相关性
co=prices.pct_change().corr()
for symbol in symbols:
v=co[symbol].sort_values()
print symbol,u' | 正相关度最高: ',v.index[-2],u' 相关系数=',v[-2],u' | 负相关度最高: ',v.index[0],u' 相关系数=',v[0]
print ''
恒瑞医药 | 正相关度最高: 招商证券 相关系数= 0.373459451207 | 负相关度最高: ST山水 相关系数= -0.184459943941
中国石化 | 正相关度最高: 中国石油 相关系数= 0.924324466248 | 负相关度最高: 恒瑞医药 相关系数= 0.086023084494
大族激光 | 正相关度最高: 沪深300 相关系数= 0.661414109 | 负相关度最高: 恒瑞医药 相关系数= 0.0872177335242
中国石油 | 正相关度最高: 中国石化 相关系数= 0.924324466248 | 负相关度最高: ST山水 相关系数= 0.117857884825
沪深300 | 正相关度最高: 广发证券 相关系数= 0.860752981977 | 负相关度最高: 恒瑞医药 相关系数= 0.289424888497
三安光电 | 正相关度最高: ST山水 相关系数= 0.621160353597 | 负相关度最高: 恒瑞医药 相关系数= 0.0579186039258
万科a | 正相关度最高: 保利地产 相关系数= 0.575758930125 | 负相关度最高: 恒瑞医药 相关系数= 0.196663064699
工商银行 | 正相关度最高: 中国石油 相关系数= 0.782436477866 | 负相关度最高: ST山水 相关系数= 0.0843699347197
招商证券 | 正相关度最高: 广发证券 相关系数= 0.921710029685 | 负相关度最高: ST山水 相关系数= 0.130198313722
招商银行 | 正相关度最高: 工商银行 相关系数= 0.686388691468 | 负相关度最高: 恒瑞医药 相关系数= 0.0239442789959
ST山水 | 正相关度最高: 三安光电 相关系数= 0.621160353597 | 负相关度最高: 恒瑞医药 相关系数= -0.184459943941
广发证券 | 正相关度最高: 招商证券 相关系数= 0.921710029685 | 负相关度最高: ST山水 相关系数= 0.250817065922
同仁堂 | 正相关度最高: 沪深300 相关系数= 0.675505803837 | 负相关度最高: 恒瑞医药 相关系数= 0.11457913001
ST中富 | 正相关度最高: 广发证券 相关系数= 0.563662524852 | 负相关度最高: 招商银行 相关系数= 0.0833174028769
保利地产 | 正相关度最高: 沪深300 相关系数= 0.746992561689 | 负相关度最高: ST山水 相关系数= 0.176521765306
结论有点意思:
- 同属一个版块,中石油、中石化关联度很高;券商关联度也很高
- 正相关中,沪深300 和 广发证券 出现频率最高,莫非广发证券也能作为大势研判的一个指标了,连ST的都与它正相关最高?
- 恒瑞医药出现在负相关中的频率最高,属于独立行情,适合在资产配置加入,降低风险
聚类分析
看看基于股价波动性聚类,会是什么结果?
from sklearn.cluster import affinity_propagation
_,labels=affinity_propagation(co)
df_c=pd.DataFrame({'label':labels,'name':symbols})
g=df_c.groupby('label')
for item in g:
print item[0],','.join(item[1]['name'].values)
print '============='
0 恒瑞医药
=============
1 中国石化,中国石油,工商银行,招商银行
=============
2 大族激光,沪深300,三安光电,万科a,招商证券,ST山水,广发证券,同仁堂,ST中富,保利地产
=============
果然和前面的数值分析有很大的相关性! 恒瑞医疗就是独行侠,第一个归类里就只有它。石油、石化、银行混在一起,嗯,也符合它们的身份吧。
验证一下每日股价波动是否符合正态分布
prices.pct_change().hist(column=[u'恒瑞医药',u'招商银行',u'保利地产',u'三安光电'],sharex=True,sharey=True,bins=30)
array([[<matplotlib.axes._subplots.AxesSubplot object at 0x000000000CEDA320>,
<matplotlib.axes._subplots.AxesSubplot object at 0x000000000CEF4588>],
[<matplotlib.axes._subplots.AxesSubplot object at 0x000000000D210B00>,
<matplotlib.axes._subplots.AxesSubplot object at 0x000000000D31CAC8>]], dtype=object)
从图表来看,所选样本波动率集中度都很高,也符合正太分布。
从投资组合的角度分析
仅选两支股票的投资组合
既然前面谈到了,恒瑞医药走出独立行情,那么就设定一种投资组合,都是恒瑞医药加上另一只票。如果投资风格是追求收益风险比值是最高,那么计算一下不同的组合中,如何配比可以达到最佳值。
恒瑞医药+万科a
group_dots=np.linspace(0,1,100,endpoint=False)
hryy_wka=pd.DataFrame({
u'回报':pd.Series([(r*prices_norm[u'恒瑞医药']+(1-r)*prices_norm[u'万科a']).pct_change().mean() for r in group_dots],index=group_dots),
u'风险':pd.Series([(r*prices_norm[u'恒瑞医药']+(1-r)*prices_norm[u'万科a']).pct_change().std() for r in group_dots],index=group_dots)
})
ax=hryy_wka.plot(secondary_y=u'风险')
ax.set_xlabel(u'恒瑞医药占比')
ax.set_ylabel(u'单日股价波动均值')
ax.right_ax.set_ylabel(u'单日股价波动标准差')
plt.title(u'恒瑞医药+万科a 不同配比的收益风险变化图')
<matplotlib.text.Text at 0x20e0b668>
绘制这个组合的风险回报比变化曲线
reward_over_risk=hryy_wka[u'回报']/hryy_wka[u'风险']
reward_over_risk.plot()
plt.xlabel(u'恒瑞医药占比')
plt.ylabel(u'回报/风险')
print u'恒瑞医药最佳占比:', reward_over_risk.argmax()
恒瑞医药最佳占比: 0.14
分析表明:这个组合中 15%恒瑞医药+85%万科a 时,回报和风险比最高。
恒瑞医药+招商证券
group_dots=np.linspace(0,1,100,endpoint=False)
hryy_wka=pd.DataFrame({
u'回报':pd.Series([(r*prices_norm[u'恒瑞医药']+(1-r)*prices_norm[u'招商证券']).pct_change().mean() for r in group_dots],index=group_dots),
u'风险':pd.Series([(r*prices_norm[u'恒瑞医药']+(1-r)*prices_norm[u'招商证券']).pct_change().std() for r in group_dots],index=group_dots)
})
ax=hryy_wka.plot(secondary_y=u'风险')
ax.set_xlabel(u'恒瑞医药占比')
ax.set_ylabel(u'单日股价波动均值')
ax.right_ax.set_ylabel(u'单日股价波动标准差')
plt.title(u'恒瑞医药+招商证券 不同配比的收益风险变化图')
<matplotlib.text.Text at 0x213725f8>
reward_over_risk=hryy_wka[u'回报']/hryy_wka[u'风险']
reward_over_risk.plot()
plt.xlabel(u'恒瑞医药占比')
plt.ylabel(u'回报/风险')
print u'恒瑞医药最佳占比:', reward_over_risk.argmax()
恒瑞医药最佳占比: 0.99
这个组合中,恒瑞医药几乎占据全部比例时,回报/风险值最佳。
恒瑞医药+三安光电
group_dots=np.linspace(0,1,100,endpoint=False)
hryy_wka=pd.DataFrame({
u'回报':pd.Series([(r*prices_norm[u'恒瑞医药']+(1-r)*prices_norm[u'三安光电']).pct_change().mean() for r in group_dots],index=group_dots),
u'风险':pd.Series([(r*prices_norm[u'恒瑞医药']+(1-r)*prices_norm[u'三安光电']).pct_change().std() for r in group_dots],index=group_dots)
})
ax=hryy_wka.plot(secondary_y=u'风险')
ax.set_xlabel(u'恒瑞医药占比')
ax.set_ylabel(u'单日股价波动均值')
ax.right_ax.set_ylabel(u'单日股价波动标准差')
plt.title(u'恒瑞医药+招商证券 不同配比的收益风险变化图')
<matplotlib.text.Text at 0x2166e0b8>
reward_over_risk=hryy_wka[u'回报']/hryy_wka[u'风险']
reward_over_risk.plot()
plt.xlabel(u'恒瑞医药占比')
plt.ylabel(u'回报/风险')
print u'恒瑞医药最佳占比:', reward_over_risk.argmax()
恒瑞医药最佳占比: 0.89
这个组合中 89%恒瑞医药+11%三安光电 时,回报和风险比最高。
多支票组合的效果对比
如果同时选择恒瑞医药+沪深300+万科a,但是根据配比不同有以下三种方案:
- 重仓恒瑞医药,恒瑞医药、沪深300和万科a三者配比为 50%:30%:20%
- 重仓沪深300,恒瑞医药、沪深300和万科a三者配比为 20%:50%:30%
- 重仓万科a,恒瑞医药、沪深300和万科a三者配比为 20%:30%:50%
portfolios=pd.DataFrame({
u'重仓恒瑞医疗':0.5*prices_norm[u'恒瑞医药']+0.3*prices_norm[u'沪深300']+0.2*prices_norm[u'万科a'],
u'重仓沪深300':0.2*prices_norm[u'恒瑞医药']+0.50*prices_norm[u'沪深300']+0.3*prices_norm[u'万科a'],
u'重仓万科a':0.2*prices_norm[u'恒瑞医药']+0.30*prices_norm[u'沪深300']+0.5*prices_norm[u'万科a']
})
portfolios.plot()
print portfolios.pct_change().describe()
重仓万科a 重仓恒瑞医疗 重仓沪深300
count 332.000000 332.000000 332.000000
mean 0.001767 0.001322 0.001347
std 0.023129 0.020336 0.020824
min -0.123201 -0.148621 -0.133951
25% -0.009271 -0.007207 -0.007543
50% 0.000218 0.001041 0.001170
75% 0.008352 0.008673 0.008061
max 0.136271 0.134773 0.152384
结论:
- 重仓万科a收益率最高,但是风险值也更大,股价波动率标准差为0.023
- 重仓恒瑞医药或沪深300,收益率相近,股价波动率标准差也相近,都在 0.020附近