情绪指数择时模型
由ypyu创建,最终由ypyu 被浏览 610 用户
简介
本帖对国信证券的研报——《国信投资者情绪指数择时模型》进行了复现,文末有策略链接,欢迎克隆研究。
研报在借鉴 A. D.Persaud 风险偏好指数的基础上,根据中国股市特点,将该方法完善改进后移植到 A 股市场,构建了国信投资者情绪指数 GSISI。
A.D.Persaud 因为在金融领域的诸多创新而为众人所知,其在研究货币市场时,发明了一种度量投资者风险偏好的良好方法——风险偏好指数(Risk AppetiteIndex)。基本方法是在度量资产的风险与收益之间的相关系数的基础上设计了风险偏好指数。 该报告在借鉴 A. D.Persaud 风险偏好指数的基础上,根据中国股市特点,将该方法完善改进后移植到 A 股市场,构建了国信投资者情绪指数 GSISI(GuoSen Investor Sentiment Index)。
一些预备知识
β系数 β系数也称为贝塔系数(Beta coefficient),是一种风险指数,用来衡量个别股票或股票基金相对于整个股市的价格波动情况。β系数是一种评估证券系统性风险的工具,用以度量一种证券或一个投资证券组合相对总体市场的波动性,在股票、基金等投资术语中常见。 本帖计算方法:$\beta = \frac{Cov(r_a,r_m)}{\sigma_m^2}(其中Cov(r_a,r_m)是证券 a 的收益与市场收益的协方差,\sigma_m^2是市场收益的方差。)$
Pearson相关系数 Pearson相关系数(Pearson CorrelationCoefficient)是用来衡量两个数据集合是否在一条线上面,它用来衡量定距变量间的线性关系。
spearman相关系数 在 统计学中, 以查尔斯·斯皮尔曼命名的斯皮尔曼等级相关系数,即spearman相关系数。经常用希腊字母ρ表示。 它是衡量两个变量的依赖性的 非参数 指标。 它利用单调方程评价两个统计变量的相关性。 如果数据中没有重复值, 并且当两个变量完全单调相关时,斯皮尔曼相关系数则为+1或−1。
构建方法
Beta 系数衡量申万一级行业相对沪深 300 指数的波动性,而Spearman秩相关系数度量申万一级行业的 Beta系数和其收益率之间的等级相关性。 即 Spearman 秩相关系数度量的是当所有申万一级行业的 Beta 系数按照大小排序(即行业 Beta 轮动)时,其收益率的大小排序(即行业收益率轮动)能保持与 Beta 系数排序(即行业 Beta 轮动)一致性的程度和方向。
这种一致性的程度和方向体现投资者悲观或乐观程度,即投资者情绪。因此,我们发现以下规律:
(1)当两个变量(申万一级行业的 Beta 系数和收益率)排序一致性程度上升,方向相同,$\rho_s\geq0$ ,表示投资乐观情绪上扬; (2)当两个变量(申万一级行业的 Beta 系数和收益率)排序一致性程度上升,方向相反,$\rho_s\leq0$ ,表示投资悲观情绪蔓延
基本思路是首先计算 28 个申万一级行业周收益率以及其相对沪深 300 指数的周 Beta 系数; 然后测算 28 个申万一级行业周收益率与其周 Beta 系数的 Spearman 秩相关系数; 最后以 Spearman 秩相关系数为基础构建国信投资者情绪指数 GSISI。
策略思路: 若 GSISI 连续两次发出看多(或看空)信号,则看多(或看空)沪深 300 指数,且保持这个判断,直到连续两次看空(或看多)信号出现,则发生看空(或看多)沪深 300指数的反转判断;若 GSISI 发出多空交叉互现信号,则除最新信号外,前面的交叉信号作废,以最新信号为判断起点,按照前面两条准则重新分析后面的信号。 具体步骤是:
- 若国信投资者情绪指数 GSISI>37.1,则作为看多沪深 300 的一次警示信号。若紧接着再次GSISI>37.1 ,则作为看多沪深 300 的确认信号,正式看多沪深300,一次判断完成,且保持此判断,直到有相反的判断出现。若紧接着GSISI<37.1 ,则看多沪深 300 的一次警示信号作废,以此最新的信号为判断起点,进行下一轮的判断。
- 类似地,若国信投资者情绪指数GSISI<37.1 ,则作为看空沪深 300 的一次警示信号。若紧接着再次GSISI<37.1 ,则作为看空沪深 300 的确认信号,正式看空沪深300,一次判断完成,且保持此判断,直到有相反的判断出现。若紧接着GSISI>37.1 ,则看空沪深 300 的一次警示信号作废,以此最新的信号为判断起点,进行下一轮的判断。 (这里的37.1是在对Spearman秩相关系数进行显著性检验后得出的)
- 按照步骤(1)(2)循环判断,产生一系列关于沪深 300 的多空观点。如此设计完成国信投资者情绪指数择时模型(GSISI 择时模型)。
如图所示,国信投资者情绪指数 GSISI 基本上暗示了沪深 300 指数的运行趋势,一般而言,投资者情绪乐观时,沪深 300 指数上升,投资者情绪悲观时,沪深 300 指数下行。
提取数据
计算出各个行业的平均利润,用以后续计算
计算GSISI与回测
主函数代码
# Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端
def bigquant_run(input_1, input_2):
#链接数据,求出各行业和沪深300平均周收益率
df = input_2.read_df()
df = df[['date','instrument','close']]
df_1 = input_1
df_2 = pd.merge(df,df_1,on='date')
df_2_filter = df_2[df_2.industry_sw_level1!=0]
df_2_filter = df_2_filter[['date','close','mean_close','industry_sw_level1']]
df1 = df_2_filter.set_index('date').groupby('industry_sw_level1')[['close','mean_close']].rolling(7).corr()
df2 = df1.groupby(level=[0,1]).last()['close'].to_frame('corre').reset_index()
result = df2.merge(df_2_filter,on=['industry_sw_level1','date']).drop_duplicates()#.dropna(how='any')
result['industry_pct_7'] = result.groupby('industry_sw_level1')['mean_close'].pct_change(6)
result['hs300_pct_7'] = result.groupby('industry_sw_level1')['close'].pct_change(6)
result = result.dropna(how='any')
# 引入函数,为后续计算做准备
from scipy.stats import spearmanr
from math import sqrt
def corrcoef(x, y):
n = len(x)
# 求和
sum1 = sum(x)
sum2 = sum(y)
# 求乘积之和
sumofxy = np.sum([a*b for a,b in zip(x,y)])
# 求平方和
sumofx2 = sum([pow(i, 2) for i in x])
sumofy2 = sum([pow(j, 2) for j in y])
num = sumofxy - (float(sum1) * float(sum2) / n)
# 计算皮尔逊相关系数
den = sqrt((sumofx2 - float(sum1 ** 2) / n) * (sumofy2 - float(sum2 ** 2) / n))
return num / den
def cal(df):
from scipy.stats import spearmanr
i = 1
result = []
while i < 101:
result.append(0)
i+=1
for k in range(len(df)):
if k >= 100:
x = np.array(df.iloc[k-100:k]['industry_pct_7'])
y = np.array(df.iloc[k-100:k]['hs300_pct_7'])
corr = corrcoef(x,y)
std = x.std()
beta = corr/std**2
result.append(corr)
df_temp = pd.DataFrame(result,index=df.index,columns=['beta'])
df= pd.concat([df,df_temp],axis=1)
return df
#计算各个行业收益率与沪深300收益率的相关系数与标准差,求出β系数
result = result.set_index('date').groupby('industry_sw_level1').apply(cal).reset_index()
result = result[result['beta']!=0]
result = result.dropna()
#计算出各个行业β系数与沪深300周收益率的spearman秩相关系数,得出GSISI指数
def cal_1(df):
z = []
from scipy.stats import spearmanr
x = np.array(df.iloc[:]['industry_pct_7'])
y = np.array(df.iloc[:]['beta'])
corr = spearmanr(x,y)[0]
return corr
result_1 = result.groupby('date').apply(cal_1)
x = pd.DataFrame(result_1,columns=['spearman'])
#m为交易临界值,编写买卖逻辑。
m = 0.371
x['label_+'] = (x['spearman']>=m)
x['label_-'] = (x['spearman']<=-m)*-0.25
x['label_0'] = x['label_+'] + x['label_-']
def cal_2(df):
result = []
for k in range(len(df)):
x = df.iloc[k]['label_0']
y = df.iloc[k-1]['label_0']
z = x+y
p = 0
if z == -0.5:
p=-1
if z == 2:
p=1
if z == 0.75:
df.iloc[k]['label_2'] = 0
result.append(p)
df_temp = pd.DataFrame(result,index=df.index,columns=['label'])
df= pd.concat([df,df_temp],axis=1)
return df
result_2 = cal_2(x).sort_index().reset_index()
result_2['instrument'] = '000300.HIX'
result_2['buy_condition'] = result_2['label']==1
result_2['sell_condition'] = result_2['label']==-1
return Outputs(data_1=result_2)
\