曾经某位伟大的领导人曾说过,中国人,做啥都要一窝蜂。半个世纪过去了,国家的金融市场从无到有,从有到逐渐完善的过程中,这种“一窝蜂”的精神却是常伴相随。本文今天将就这种“一窝蜂”的现象进行研究,首先引入一个比较专业的词汇——羊群效应,来解释这种现象。金融市场的羊群效应主要是指投资者在市场交易过程中的学习与模仿的现象,当市场中存在羊群效应时,投资者在做出自己的决策时更加依赖于他人的行为而忽略自己所获取的信息。怎样,听起来是不是很像股市中各个小散的自画像?本期文章作为羊群效应系列的第一篇,将主要介绍羊群效应的基本理论。
一、背景知识
目前国外对羊群效应的实证研究主要分为两类,一类是以基金为研究对象的LSV模型,一类是以个股投资者为研究对象的CSAD模型(横截面收益率标准差模型),本文主要应用了后者的研究。首先介绍两个基本模型:
1.CSAD模型
CSAD模型中的核心公式为度量市场分散程度的横截面绝对偏离度CSAD:
式中,N代表股票数量,股票i在t时刻的收益率为Ri,t,市场组合在t日内的平均收益率为Rm,t
2.CAPM模型
金工领域有个著名的资产定价模型(CAPM),股票i的收益率E(Ri,t)等于无风险利率加上系统风险溢价,将其转换为差值形式:
式中,E(Rm,t)代表市场组合的预期收益率,rf为无风险利率。
如果对该式涉及的所有股票求和,可得到:
3.CCK模型
两个基本模型介绍完,接着介绍基于两个基本模型的检验羊群效应的CCK模型。如果我们仔细对比模型1和2,是不是发现了比较有什么相似的地方?对了,模型2经过变换后的等式左边等于模型1的等式右边的期望,则综合可得:
对该式分别求一阶导和二阶导,可得:
由上式可知,一阶导大于0而二阶导等于0,因此理性情况下,CSAD与市场收益率Rm应当呈线性递增关系;而如果市场存在羊群效应,那么由于市场参与者的行为一致性,CSAD与Rm之间的线性关系将不复存在,而会表现出非线性的递减增长,因此,定义一个二次项Rm2来描述这种关系,同时使用可测的CSAD和Rm来分别代替不可测的E(CSAD)和E(Rm)。可得到羊群效应的回归方程:
因此,只要判断该回归方程的系数β2是否为负数且系数显著,即可说明市场中是否存在羊群效应。
二、研究/策略步骤
本文根据指数数据对股票市场进行实证研究,市场收益率选用指数数据,个股收益率以动态市盈率计算。出于对比分析,研究中测试不同指数在不同时期的影响。
1.研究简述
研究实证了沪深300指数、上证指数、中证500指数、中小板指数,创业板指数在近一个月的羊群效应值。研究结果概述如下:
可以看到,在过去的一个月中具有显著羊群效应的股指为沪深300、上证指数(p<0.01),创业板指则属于较为显著(p<0.05);上证50的P值未通过检验,中小板指的系数大于0。
2.策略简述
本期仅编写了一个简单的策略来验证羊群效应的影响,策略的主要步骤如下:
(1).对每个指数,每个月(也可以每周)检测一次市场是否存在羊群效应,返回该指数该月的判断标识符;
(2).根据判断标志,如果该指数下存在羊群效应,则避开该指数下的股票;如果不存在羊群效应,则根据自己的策略选股(暂定该策略为基于股票相对强弱RPS指标的选股策略)
(3).考虑到本期策略本质上也是一种追涨策略,因此设立了个对照组:与步骤2正好相反,如果存在羊群效应则启动该策略,否则不做任何操作。目的主要是为了观察羊群效应的作用和影响。
三、回测结果
本次回测选取了中小板指数和创业板指数作为研究对象(感兴趣的用户可研究单独某个指数在羊群效应下的表现)。
四、研究结论
1.按照以往的文献研究,创业板指具有非常显著的羊群效应,本文的实证研究也证明了这一点;当然,对比不同指数的回测效果也发现在其他指数中也存在此类效应的,上证50除外(有兴趣的用户 可以自行修改indexList观察)。而通过回测也发现羊群效应并非一种长期存在的现象,仅仅在某些时间段存在。
2.从回测中可以看到跟随羊群的情况下,在一波震荡慢牛中反倒收获了不错的策略收益,而在震荡期的调整则表现不佳;令人意外的是,中小板指和创业板指在15年的牛市中并未显示出羊群效应(可能与Pvalue的阈值设定较为严格有关,本策略设定为0.01,而统计上一般使用0.05)
3.此外,从回测中也可以看到,羊群效应在不同指数的表现效果也不尽相同,无论在牛市亦或者是熊市(如15年末的震荡慢牛中实际上一个指数有羊群效应一个没有,因此该阶段是两个策略都有操作股票)。当然,仅仅从本次回测来看,最好的策略就是坚持自己的策略啦,跟随羊群跑,可能赚大钱,也可能吃大亏哦(虽然仅从回测来看仅仅震荡还没有大亏的端倪(:з」∠))。
4.羊群效应,说到底是把双刃剑,是选择在存在羊群效应的市场紧随潮流收割利润,还是坚持本我理性炒股获取固定收益,这是个问题。先预告下下期文章,将讨论如何在羊群效应期间重仓持有龙头股获取收益(将涉及龙头股的选择策略),敬请期待。
5.本策略仅作观察羊群效应用,在之后的文章里会更新针对羊群效应的选股策略。
import pandas as pd
import numpy as np
import statsmodels.formula as smFormula
import statsmodels.api as smApi
from operator import methodcaller
#羊群效应
def calHerdSign(eachIndex,pastDay,curDate,preDate):
try:
#获取指数pastDay内的价格
indexPrice = get_price(eachIndex,start_date = preDate, end_date = curDate, frequency = '1d',fields = ['close'])
#获取不同日期的Rmt
#初始化存储数组
stockPeInfo = indexPrice
stockPeInfo['Rmt'] = 0
stockPeInfo['Rmt2'] = 0
dateInfo = (stockPeInfo.T).columns
#计算Rmt
stockPE = 0
peIndex = 0
dateInfo = dateInfo.map(methodcaller('date'))
for days in dateInfo:
#获取指数内的股票
stocks = get_index_stocks(eachIndex,days)
numStocks = len(stocks)
for security in stocks:
peInfo = get_fundamentals(query(valuation.pe_ratio).filter(valuation.code.in_([security])), date = days)
peInfo = float(peInfo['pe_ratio'])
stockPE += peInfo
peIndex += stockPE / numStocks
stockPeInfo.loc[days,'Rmt'] = abs(float(peIndex))
stockPeInfo.loc[days,'Rmt2'] = float(peIndex)**2
#重置参数
stockPE = 0
peIndex = 0
olsResult = smFormula.api.ols(formula='close~Rmt+Rmt2', data=stockPeInfo).fit()
testInfo = smApi.stats.linear_rainbow(olsResult)
#olsResult = pd.stats.api.ols(y = stockPeInfo['close'],x = stockPeInfo[['Rmt','Rmt2']])
return olsResult,testInfo
except:
print('Turn to modify code in function "calHerdSign"')
# 沪深300指数在最近一个月的表现
eachIndex = '000300.XSHG'
pastDay = 30
curDate = datetime.date.today()
preDate = datetime.date.today() + datetime.timedelta(days = -pastDay)
curDate = str(curDate);preDay = str(preDate)
olsResult,testInfo = calHerdSign(eachIndex,pastDay,curDate,preDate)
# 沪深300指数回归结果
olsResult.summary()
Dep. Variable: | close | R-squared: | 0.917 |
---|---|---|---|
Model: | OLS | Adj. R-squared: | 0.908 |
Method: | Least Squares | F-statistic: | 104.3 |
Date: | Wed, 30 Mar 2016 | Prob (F-statistic): | 5.69e-11 |
Time: | 13:12:38 | Log-Likelihood: | -103.25 |
No. Observations: | 22 | AIC: | 212.5 |
Df Residuals: | 19 | BIC: | 215.8 |
Df Model: | 2 | ||
Covariance Type: | nonrobust |
coef | std err | t | P>|t| | [95.0% Conf. Int.] | |
---|---|---|---|---|---|
Intercept | -4269.9426 | 690.189 | -6.187 | 0.000 | -5714.524 -2825.361 |
Rmt | 473.6858 | 46.599 | 10.165 | 0.000 | 376.152 571.219 |
Rmt2 | -7.4786 | 0.782 | -9.564 | 0.000 | -9.115 -5.842 |
Omnibus: | 1.642 | Durbin-Watson: | 1.336 |
---|---|---|---|
Prob(Omnibus): | 0.440 | Jarque-Bera (JB): | 0.981 |
Skew: | 0.093 | Prob(JB): | 0.612 |
Kurtosis: | 1.982 | Cond. No. | 9.28e+04 |
# 上证50指数在最近一个月的表现
eachIndex = '000016.XSHG'
pastDay = 30
curDate = datetime.date.today()
preDate = datetime.date.today() + datetime.timedelta(days = -pastDay)
curDate = str(curDate);preDay = str(preDate)
olsResult,testInfo = calHerdSign(eachIndex,pastDay,curDate,preDate)
# 上证50指数回归结果
olsResult.summary()
Dep. Variable: | close | R-squared: | 0.889 |
---|---|---|---|
Model: | OLS | Adj. R-squared: | 0.877 |
Method: | Least Squares | F-statistic: | 75.85 |
Date: | Wed, 30 Mar 2016 | Prob (F-statistic): | 8.75e-10 |
Time: | 13:12:47 | Log-Likelihood: | -96.887 |
No. Observations: | 22 | AIC: | 199.8 |
Df Residuals: | 19 | BIC: | 203.0 |
Df Model: | 2 | ||
Covariance Type: | nonrobust |
coef | std err | t | P>|t| | [95.0% Conf. Int.] | |
---|---|---|---|---|---|
Intercept | -380.3462 | 2695.759 | -0.141 | 0.889 | -6022.634 5261.941 |
Rmt | 211.9918 | 351.157 | 0.604 | 0.553 | -522.987 946.971 |
Rmt2 | -3.4256 | 11.425 | -0.300 | 0.768 | -27.338 20.486 |
Omnibus: | 1.115 | Durbin-Watson: | 0.880 |
---|---|---|---|
Prob(Omnibus): | 0.573 | Jarque-Bera (JB): | 1.042 |
Skew: | 0.441 | Prob(JB): | 0.594 |
Kurtosis: | 2.401 | Cond. No. | 1.48e+05 |
# 上证指数在最近一个月的表现
eachIndex = '000001.XSHG'
pastDay = 30
curDate = datetime.date.today()
preDate = datetime.date.today() + datetime.timedelta(days = -pastDay)
curDate = str(curDate);preDay = str(preDate)
olsResult,testInfo = calHerdSign(eachIndex,pastDay,curDate,preDate)
# 上证指数回归结果
olsResult.summary()
Dep. Variable: | close | R-squared: | 0.394 |
---|---|---|---|
Model: | OLS | Adj. R-squared: | 0.330 |
Method: | Least Squares | F-statistic: | 6.175 |
Date: | Wed, 30 Mar 2016 | Prob (F-statistic): | 0.00859 |
Time: | 13:15:42 | Log-Likelihood: | -122.86 |
No. Observations: | 22 | AIC: | 251.7 |
Df Residuals: | 19 | BIC: | 255.0 |
Df Model: | 2 | ||
Covariance Type: | nonrobust |
coef | std err | t | P>|t| | [95.0% Conf. Int.] | |
---|---|---|---|---|---|
Intercept | 2957.6327 | 34.934 | 84.664 | 0.000 | 2884.516 3030.750 |
Rmt | -2.1349 | 0.630 | -3.389 | 0.003 | -3.453 -0.816 |
Rmt2 | 0.0055 | 0.002 | 3.173 | 0.005 | 0.002 0.009 |
Omnibus: | 8.493 | Durbin-Watson: | 0.253 |
---|---|---|---|
Prob(Omnibus): | 0.014 | Jarque-Bera (JB): | 6.187 |
Skew: | -1.204 | Prob(JB): | 0.0453 |
Kurtosis: | 3.973 | Cond. No. | 2.54e+05 |
# 中小板指数在最近一个月的表现
eachIndex = '399005.XSHE'
pastDay = 30
curDate = datetime.date.today()
preDate = datetime.date.today() + datetime.timedelta(days = -pastDay)
curDate = str(curDate);preDay = str(preDate)
olsResult,testInfo = calHerdSign(eachIndex,pastDay,curDate,preDate)
# 中小板指数回归结果
olsResult.summary()
Dep. Variable: | close | R-squared: | 0.896 |
---|---|---|---|
Model: | OLS | Adj. R-squared: | 0.885 |
Method: | Least Squares | F-statistic: | 82.20 |
Date: | Wed, 30 Mar 2016 | Prob (F-statistic): | 4.42e-10 |
Time: | 13:15:59 | Log-Likelihood: | -128.96 |
No. Observations: | 22 | AIC: | 263.9 |
Df Residuals: | 19 | BIC: | 267.2 |
Df Model: | 2 | ||
Covariance Type: | nonrobust |
coef | std err | t | P>|t| | [95.0% Conf. Int.] | |
---|---|---|---|---|---|
Intercept | 8545.7859 | 176.865 | 48.318 | 0.000 | 8175.603 8915.969 |
Rmt | -25.4929 | 2.394 | -10.647 | 0.000 | -30.504 -20.481 |
Rmt2 | 0.0563 | 0.006 | 10.065 | 0.000 | 0.045 0.068 |
Omnibus: | 2.192 | Durbin-Watson: | 1.593 |
---|---|---|---|
Prob(Omnibus): | 0.334 | Jarque-Bera (JB): | 1.858 |
Skew: | -0.621 | Prob(JB): | 0.395 |
Kurtosis: | 2.305 | Cond. No. | 9.07e+05 |
# 创业板指数在最近一个月的表现
eachIndex = '399006.XSHE'
pastDay = 30
curDate = datetime.date.today()
preDate = datetime.date.today() + datetime.timedelta(days = -pastDay)
curDate = str(curDate);preDay = str(preDate)
olsResult,testInfo = calHerdSign(eachIndex,pastDay,curDate,preDate)
# 创业板指数回归结果
olsResult.summary()
Dep. Variable: | close | R-squared: | 0.968 |
---|---|---|---|
Model: | OLS | Adj. R-squared: | 0.964 |
Method: | Least Squares | F-statistic: | 282.8 |
Date: | Wed, 30 Mar 2016 | Prob (F-statistic): | 7.29e-15 |
Time: | 13:16:16 | Log-Likelihood: | -99.227 |
No. Observations: | 22 | AIC: | 204.5 |
Df Residuals: | 19 | BIC: | 207.7 |
Df Model: | 2 | ||
Covariance Type: | nonrobust |
coef | std err | t | P>|t| | [95.0% Conf. Int.] | |
---|---|---|---|---|---|
Intercept | -4273.8887 | 2024.107 | -2.111 | 0.048 | -8510.393 -37.384 |
Rmt | 117.2996 | 43.645 | 2.688 | 0.015 | 25.950 208.649 |
Rmt2 | -0.5243 | 0.234 | -2.237 | 0.037 | -1.015 -0.034 |
Omnibus: | 1.348 | Durbin-Watson: | 0.580 |
---|---|---|---|
Prob(Omnibus): | 0.510 | Jarque-Bera (JB): | 0.646 |
Skew: | -0.419 | Prob(JB): | 0.724 |
Kurtosis: | 3.061 | Cond. No. | 3.43e+06 |
# 上证指数在最近一年的表现
eachIndex = '000001.XSHG'
pastDay = 360
curDate = datetime.date.today()
preDate = datetime.date.today() + datetime.timedelta(days = -pastDay)
curDate = str(curDate);preDay = str(preDate)
olsResult,testInfo = calHerdSign(eachIndex,pastDay,curDate,preDate)
# 上证指数回归结果
olsResult.summary()
Dep. Variable: | close | R-squared: | 0.566 |
---|---|---|---|
Model: | OLS | Adj. R-squared: | 0.562 |
Method: | Least Squares | F-statistic: | 155.3 |
Date: | Wed, 30 Mar 2016 | Prob (F-statistic): | 7.02e-44 |
Time: | 13:48:02 | Log-Likelihood: | -1795.2 |
No. Observations: | 241 | AIC: | 3596. |
Df Residuals: | 238 | BIC: | 3607. |
Df Model: | 2 | ||
Covariance Type: | nonrobust |
coef | std err | t | P>|t| | [95.0% Conf. Int.] | |
---|---|---|---|---|---|
Intercept | 4408.0786 | 52.373 | 84.167 | 0.000 | 4304.905 4511.252 |
Rmt | -9.9527 | 0.658 | -15.135 | 0.000 | -11.248 -8.657 |
Rmt2 | 0.0169 | 0.001 | 12.644 | 0.000 | 0.014 0.019 |
Omnibus: | 22.299 | Durbin-Watson: | 0.141 |
---|---|---|---|
Prob(Omnibus): | 0.000 | Jarque-Bera (JB): | 84.312 |
Skew: | 0.156 | Prob(JB): | 4.92e-19 |
Kurtosis: | 5.881 | Cond. No. | 2.21e+05 |
本社区仅针对特定人员开放
查看需注册登录并通过风险意识测评
5秒后跳转登录页面...
移动端课程