01
引言
“以史为鉴,可以知兴替”,这句话背后的逻辑是人性不变、历史重演。金融市场也一样,以历史行情为借鉴,可以了解行情涨跌、市场牛熊的更替。历史会重演是股票技术分析的三大假设之一,认为交易者心理与市场行为紧密相关,价格形态反映了交易者对市场预期的心理,因此市场会重复人性行为的变化。实际上,投资人类天性,成败取决大行情。利弗摩尔在《股票大作手回忆录》里强调:“想要赚大钱,你就必须在大波动里面去捕捉机会”。
所谓“不谋全局者,不足谋一域”,天天盯盘的人容易只见树木不见森林,在股市每天的涨涨跌跌中迷失方向。要想在大波动里捕捉机会,还得适时跳出市场,站在全局的视角去分析和把握当前行情所处的阶段。本文以沪深300指数为例,对历史行情进行探索性分析,同时借助时间序列的相似性、动态规整分析,分析股市牛熊兴替的规律,考察当前行情所处的历史阶段,为整体把握和量化分析市场提供参考。每一次大的行情,如05-07大牛市、08年金融危机、15年股灾等都伴随着一定的历史背景(如下图所示),感兴趣的读者可结合事件驱动深入挖掘。

02
数据探索性分析
本文的数据来源于tushare pro,分析样本为沪深300指数上市至今(2022年6月24日)历史交易数据。
导入需要用到的模块
import itertools
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pylab import mpl
mpl.rcParams['font.sans-serif']=['SimHei']
mpl.rcParams['axes.unicode_minus']=False
import seaborn as sns
import tushare as ts
from fastdtw import fastdtw
#在tushare pro网站上注册https://tushare.pro/register?reg=218422,可以获取相应的tokentoken='输入你的token'pro=ts.pro_api(token)def get_data(code,start='20000101', end='20220624'): df=pro.index_daily(ts_code=code,start_date=start,end_date=end) df.index=pd.to_datetime(df.trade_date) df = df.rename(columns={'vol': 'volume'}) df=(df.sort_index()).drop('trade_date',axis=1) return df[['open','high','low','close','volume']]
indexs={'上证综指': '000001.SH','深证成指': '399001.SZ','沪深300': '000300.SH', '创业板指': '399006.SZ','上证50': '000016.SH','中证500': '000905.SH', '中小板指': '399005.SZ','上证180': '000010.SH'}index_close=pd.DataFrame()for name,code in indexs.items(): index_close[name]=get_data(code).close
#数据保存本地#index_close.to_csv('index_data.csv')#读取本地数据#index_close=pd.read_csv('index_data.csv',index_col=0)
指数相关性分析
获取市场上常用的几个指数,包括上证综指、深证成指、沪深300、创业板指、上证50、中证500、中小板指和上证180价格数据,各指数的价格相关性如下表所示。市场上各指数的相关性均较高,其中大盘指数上证综指、深证成指、沪深300和上证50相关系数均在0.9以上,中小板和创业板指、中证500的相关系数0.9以上,沪深300与其他指数的相关系数均高于0.84,具有一定的市场代表性,因此下文以沪深300指数历史行情为例,探索市场的牛熊兴替。各指数的累计涨跌幅如下图所示,创业板的累计涨幅2倍多(2010年上市以来),整体上小市值指数上涨优于大市值指数。
index_close.corr()

(index_close.dropna()/index_close.dropna().iloc[0]).plot(figsize=(16,7));

下面通过编程获取某段时间期间指数的最大回撤和最大涨幅,以及持续时间。该部分代码较长,此处省略,完整代码见知识星球。
class Period_performance(object): def __init__(self,data,years): pass def cal_days(self,d0,d1): pass def max_drawdown(self,ss): pass def max_up(self,ss): pass
将1-3年内回撤超过30%视为市场熊市,2005年11月至2022年6月,共有6次大熊市,其中2007年10月16日——2008年11月04日期间跌幅最大,259个交易日跌幅高达72.3%。比较近的大跌实际上是自2021年2月10日至2022年4月26日,其中受俄乌冲突加剧、上海疫情反复、全局通胀预期、投资者悲观情绪蔓延等因素叠加影响,今年三月和四月份市场加速大跌,4月26日止跌反弹。
data=index_close['沪深300'].dropna()years=[('2007','2008'),('2009','2010'),('2011','2012'),('2015','2016'),('2018','2019'),('2021','2022')]ppf=Period_performance(data,years)md_df=ppf.show_period_ret(flag=True)md_df

上述大跌都受到多个因素的影响,基于当时的历史背景,以某一个比较有代表性的事件或典型事实为代表,比如2007年10月16日——2008年11月04日期间正处于金融危机,因此下面使用“08金融危机”为代名词,以此类推。
dates=md_df[['起始日期','结束日期']].valuesevents=['08金融危机','欧债危机','通胀压力','15股灾','中美贸易战','近期大跌']colors=['green','gray','black','lime','teal','red']plt.figure(figsize=(16,7))data.plot()for i in range(len(dates)): data[dates[i][0]:dates[i][1]].plot(c=colors[i],label=events[i]); plt.legend();

将这六个时间序列单独抽取出来进行可视化。
for i in range(len(dates)): d0=dates[i][0] d1=dates[i][1] dd=data[d0:d1] dd.reset_index(drop=True,inplace=True) day0=pd.to_datetime(d0).strftime('%Y%m%d') day1=pd.to_datetime(d1).strftime('%Y%m%d') (dd/dd.iloc[0]).plot(figsize=(16,7),label=events[i]); plt.legend()

大跌之前必有大涨,反之亦然,这是物极必反的道理。通过历史行情回溯,沪深300指数共经历了六次大牛市(把最近一次反弹放在一起做对比),可见A股市场并非市场传言的“牛短熊长”,实际上,牛熊的兴替更迭周期类似,上涨周期长,下跌相对周期较短。在“08金融危机”股市暴跌之前(持续259交易日),A股市场经历长达576个交易日的超级牛市,最大涨幅高达618%,至今还未有被突破(创业板2010年才出现,2015年创历史新高)。交易者在这段时间参与股市获得很高的收益,但大多数人在随后的大跌中不但交回盈利还倒亏本金。指数最近的一次反弹是2022年4月26日至今(6月27日),沪深300指数两个月反弹了15%。
upd0=dates[:,1]upd1=dates[:,0]upd0=np.insert(upd0,0,pd.to_datetime('2005-01-01'))upd1=np.insert(upd1,len(upd1),pd.to_datetime('2022-06-23'))years1=list(zip(upd0,upd1))ppf1=Period_performance(data,years1)max_up_df=ppf1.show_period_ret(flag=False)max_up_df

类似的,为了分析方便,使用某一事件或典型事实来代替这些上涨期间。实际上每一次的大涨大跌都是多因素叠加共振的结果,其中的典型事件可能起到催化剂作用,而投资者的交易情绪更像是一堆干柴,遇火则燃。
dates1=max_up_df[['起始日期','结束日期']].valuesevents1=['股权分置改革','四万亿计划','量化宽松','互联网金融','周期牛市','科创板','近期反弹']colors=['DarkRed','red','Brown','IndianRed','RosyBrown','OrangeRed','Red']plt.figure(figsize=(16,7))data.plot()for i in range(len(dates1)): data[dates1[i][0]:dates1[i][1]].plot(c=colors[i],label=events1[i]); plt.legend()

03
牛熊序列相似性分析
以上对A股市场的牛熊兴替做了简单的探索性分析,下面将使用更专业的量化手段对牛熊期间价格时间序列作进一步分析。首先,通过对比上涨和下跌期间,考察涨跌幅、涨跌速度和持续时间的相似性。从下跌斜率和持续时间上看,近期的一次大跌与“欧债危机”(2009.8至2010.7)期间更相似:下跌前均有一段较长时间的上涨。08年金融危机后,各国出台救市政策,推出量化宽松政策,国内更是祭出“四万亿刺激计划”,期间实体经济仍处于下行,投资机会较少,资金大多流入股市房市,市场在资金的推动下经历了184天的大涨,涨幅高达132%;类似的,2019至2021年2月,市场经历了514个交易日累计上涨95%的行情,以科技股和白酒股最为亮眼,这波行情也主要是宽松资金拉动的结果,期间新冠疫情又进一步倒闭政策宽松。这两个时间序列下跌过程在基本面和交易者行为反馈上也有相似的地方,外部局势严峻叠加投资者恐慌心理,造成短时间内连续下跌。
def get_time_series(data,dates): data_list=[] for i in range(len(dates)): d0=dates[i][0] d1=dates[i][1] dd=data[d0:d1] dd.reset_index(drop=True,inplace=True) data_list.append(list(dd/dd.iloc[0])) return data_listdef cal_similiarty(data,dates,events): df_temp=pd.DataFrame(get_time_series(data,dates)).T df=pd.DataFrame() name='下跌' if '危机' in ''.join(events) else '上涨' df[name+'幅度']=df_temp.apply(lambda x:abs(x-1).dropna().max()) df[name+'速度']=df_temp.apply(lambda x:abs(x- 1).dropna().max()/len(x.dropna())) df['持续时间']=df_temp.apply(lambda x:len(x.dropna())) df.index=events return df
cal_similiarty(data,dates,events)

近期的大跌后反弹与“量化宽松”(2010.07.05-11.08)期间相类似。
cal_similiarty(data,dates1,events1)

下面使用动态时间规整进一步考察这些时间序列的相似度。动态时间规整 (Dynamic Time Warping, DTW),用于计算两个时间序列的相似度,尤其适用于不同长度、不同节奏的时间序列。DTW将自动扭曲(warping)时间序列(即在时间轴上进行局部的缩放),使两个序列形态尽可能一致,得到最大可能的相似度。
def calc_dtw(l_sr): dict_dtw = {} for item1, item2 in itertools.product(l_sr, repeat=2): distance, path = fastdtw(item1[1], item2[1]) dict_dtw[(item1[0], item2[0])] = distance return dict_dtw
def plot_dtw(data,dates,events): data_list=get_time_series(data,dates) dict_dtw = calc_dtw(list(zip(events,data_list))) size=len(events) dist_matrix = np.array(list(dict_dtw.values())).reshape(size, size) df_dist_matrix = pd.DataFrame(data=dist_matrix, index=events, columns=events) plt.figure(figsize=(10, 8)) color='Greens' if '危机' in ''.join(events) else 'Reds' sns.heatmap(df_dist_matrix, square=True, annot=True, cmap=color) plt.show()
events=['08金融危机','欧债危机','量化宽松','15股灾','中美贸易战','近期大跌']plot_dtw(data,dates,events)

08金融危机与其他事件下的距离相对较远。离“近期大跌”距离最小(最相似)的是“中美贸易战”和“欧债危机”时间系列数据,与“最近反弹”最相似的是“量化宽松”,与前面分析结论大致相同。
events1=['股权分置改革','四万亿计划','量化宽松','互联网金融','周期牛市','科创板','近期反弹']plot_dtw(data,dates1,events1)

04
结语
本文以沪深300指数为样本,考察了A股市场2004年至2022年6月期间的牛熊更替情况,结合历史重大事件对市场行情进行了可视化,并利用时间序列的动态相关性分析方法——动态时间规整对比分析了牛熊期间价格时间序列的相似性。股市分析恰似盲人摸象,只有多维度多视角去分析才能更好的把握市场。通过本文的分析,可以得到一个启示:上涨和下跌就像硬币的两面,有涨必有跌,有跌必有涨。市场永远都有机会,大跌并不可怕,每一次大跌都是市场给的一次机会,但要把握好这样的机会,必须严格遵守交易纪律,及时做好止损,学会空仓等待;每一次大涨都是风险的积聚过程,提高风险意识,学会急流勇退,过多的贪婪只会黄粱一梦。
参考资料:Koki Noda.Data Science Tutorial; Similarities between the current bear market and the dot-com bubble
发布者:股市刺客,转载请注明出处:https://www.95sca.cn/archives/69106
站内所有文章皆来自网络转载或读者投稿,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。敬请谅解!