前言
很多朋友习惯了同花顺、大智慧等看盘软件,经常问到筹码分布如何计算。
说起来筹码分布的理论在庄股时代堪称是一个划时代产品,虽然历经level2数据、资金流统计、拆单算法与反拆单算法等新型技术的变革,庄股时代也逐渐淡出市场,但其背后的市场逻辑仍然具备一定的参考意义。
本篇就以BigQuant平台为基础,复现经典筹码理论的基础变量计算,为因子挖掘提供更多参考特征。
资金和筹码
资金是推动筹码移动的源动力,资金的强弱决定了筹码移动的方向。买入的资金强于卖出的筹码,说明筹码需求大于供应,股价就会上涨。相反,卖出的筹码强于买入的资金,说明筹码需求小于供应,股价就会下跌。当买入的力量和卖出的力量接近平衡时,说明供求相近,股价就会横盘震荡。
筹码理论背后的经典逻辑
-
谁的筹码不抛
在筹码价位较高,没有明显出货迹象时,试想一只股票下跌了30%以上,而从没有放量,高端和低端筹码都不动,这是不正常的,散户重在散,下跌到一定程度一定会有很多人止损和出局,而持续盘跌不放量,只能说明其中有主力被套了,因为主力一般无法止损出局,那样成本太高了。这种股最适用于擒庄操作
-
谁的筹码不卖
在筹码价位较低时,一只股票上涨了20%以上,而从不放量,底端密集筹码不动也是不正常的,散户一般很少有人经得起如此引诱而一致不出货,这只能说明其中有主力在运做,而多数主力没有30%以上的利润是不会离场的,因为那样除去费用纯利就太低了。这种股最适用于坐轿操作。
-
机会和风险提示
有些股票虽然高位无量,但其拉升时出现了放量或长时间盘整,使筹码出现了高位集中,这些股一般是主力离场了,后市风险会较大。有些股低位放量或长时间盘整,出现筹码低位密集,一般是有主力进行收集造成的,操作起来机会比较大。
筹码理论的关键参数
-
筹码分布
计算历史所有筹码的换手价位,类似分价表
-
成本均线
以成交量为权重的价格平均线,用来表示N日内的市场参与者平均建仓成本。无穷成本平均线是最重要的成本均线,反映上市以来所有交易者的平均建仓成本,是市场牛熊的重要分水岭。
-
筹码集中度
刻画主要筹码堆积的主要区域的幅度,数值越大表示筹码集中的幅度越大,筹码就越分散。
-
活跃筹码
价附近的筹码是最不稳定的,也是最容易参与交易的,因为在股价附近的股票持有者,最经受不住诱惑,盈利的想赶快把浮动盈利换成实际盈利;被套的想趁着亏损得还少赶快卖掉,利用资金买另外的股票,把亏损赶快挣回来。而远离股价,在下方的筹码,由于有了一定的利润,持股信心会增强;在上方的筹码,由于被套太深而不愿割肉,所以在股价附近的筹码是最活跃的,而在股价上下,远离股价的筹码是不太活跃的。 活跃筹码的数值很小时是很值得注意的一种情况。比如,一只股票经过漫长的下跌后,活跃筹码的值很小(小于10),大部分筹码都处于被套较深的状态,这时多数持股者已经不愿意割肉出局了,所以这时候往往能成为一个较好的买入点;再比如:一只股票经过一段时间的上涨,活跃筹码很小(小于10),大部分筹码都处于获利较多的状态,如果这时控盘强弱的值较大(大于20),前期有明显的庄股特征,总体涨幅不太大,也能成为一个较好的买入点。所以,在股价运行到不同的阶段时,考虑一下活跃筹码的多少,能起到很好的辅助效果。
筹码理论的股价周期阐述
股价走势循环周期的四个阶段
A阶段:无穷成本均线由向下到走平;俗称筑底阶段;
B阶段:无穷成本均线由走平到向上;俗称拉升阶段,可称为上升阶段;
C阶段:无穷成本均线由向上到走平;俗称作头(顶)阶段;
D阶段:无穷成本均线由走平到向下;俗称派发阶段,可称作下降阶段;
1、筹码的价位分布计算
instruments = ['601700.SHA']
#这里尽量包含从上市日期开始到最后的数据
df = D.history_data(instruments, start_date='2005-01-02', end_date='2018-07-04',
fields=['open','close','adjust_factor','turn','volume']) #获取历史数据
df['real_close']=df['close']/df['adjust_factor']#获取真实收盘价
df['real_open']=df['open']/df['adjust_factor']#获取真实开盘价
df['turn']=df['turn']/100#获取换手率
df['avg_price']=np.round(df['real_close']+df['real_open'])/2#计算每日平均成本,这里按照0.5元一个价位做分析
df=df.sort_values(by='date',ascending=False).reset_index(drop=True)#日期按降序排列
df['turn_tomo']=df['turn'].shift(1) #计算明日的换手率
df['remain_day']=1-df['turn_tomo'] #计算当日的剩余筹码比例
#假设N日后,上市第一天的剩余筹码比率就是每日剩余比例的累乘即:剩余筹码比例=(1-明天换手率)*(1-后日换手率)*...*(1-最新日换手率),以此类推各日的剩余筹码
df['remain_his']=df['remain_day'].cumprod()*df['turn']
df['remain_his']=df['remain_his'].fillna(df['turn'])#最新一日的筹码就是当日的换手率
#关键统计,统计最后一天的各价位历史筹码堆积量(百分比)
ss=df.groupby('avg_price')[['remain_his']].sum().rename(columns={'remain_his':'筹码量'})
ss.head(10)
| | 筹码量 |
| avg_price | |
| 3.5 | 0.060804 |
| 4.0 | 0.044996 |
| 4.5 | 0.120760 |
| 5.0 | 0.120956 |
| 5.5 | 0.059544 |
| 6.0 | 0.149679 |
| 6.5 | 0.075149 |
| 7.0 | 0.073177 |
| 7.5 | 0.069574 |
8.0 | 0.141947 |
---|
#检查一下各价位筹码总和是不是1
ss['筹码量'].sum()
1.0000001
2、筹码理论的Winner指标
#计算end_date时某一价位的获利比例
pp=ss.reset_index()
pp[pp.avg_price <=3.5]['筹码量'].sum()
0.06080448
#计算end_date时收盘价的获利比例
pp[pp.avg_price <=df['real_close'].iloc[-1]]['筹码量'].sum()
0.9996914
3、筹码理论的Cost指标
ss['筹码累积量']=ss['筹码量'].cumsum()
ss.head()
| | 筹码量 | 筹码累积量 |
| avg_price | | |
| 3.5 | 0.060804 | 0.060804 |
| 4.0 | 0.044996 | 0.105800 |
| 4.5 | 0.120760 | 0.226561 |
| 5.0 | 0.120956 | 0.347516 |
5.5 | 0.059544 | 0.407060 |
---|
#给定累计获利比率winner_ratio,计算对应的价位,表示在此价位上winner_ratio的筹码处于获利状态
winner_ratio=0.5
for i in range(len(ss)-1):
if ss['筹码累积量'].iloc[i] < winner_ratio and ss['筹码累积量'].iloc[i+1]> winner_ratio:
cost=ss.index[i]
cost
5.5
4、计算全市场各股票的winner指标
instruments = ['601700.SHA','601699.SHA']
#这里尽量包含从上市日期开始到最后的数据
df = D.history_data(instruments, start_date='2005-01-02', end_date='2018-02-14',
fields=['open','close','adjust_factor','turn','volume']) #获取历史数据
df['real_close']=df['close']/df['adjust_factor']#获取真实收盘价
df['real_open']=df['open']/df['adjust_factor']#获取真实开盘价
df['turn']=df['turn']/100
df['avg_price']=np.round(df['real_close']+df['real_open'])/2#计算每日平均成本,这里按照0.5元一个价位做分析
df=df.sort_values(by='date',ascending=False).reset_index(drop=True)#日期按降序排列
df['turn_tomo']=df.groupby('instrument')['turn'].apply(lambda x:x.shift(1)) #计算明日的换手率
df['remain_day']=1-df['turn_tomo'] #计算当日的剩余筹码比例
#假设N日后,上市第一天的剩余筹码比率就是每日剩余比例的累乘即:剩余筹码比例=(1-明天换手率)*(1-后日换手率)*...*(1-最新日换手率),以此类推各日的剩余筹码
df['remain_his']=df.groupby('instrument')['remain_day'].apply(lambda x:x.cumprod())
df['remain_his']=df['remain_his']*df['turn']
df['remain_his']=df['remain_his'].fillna(df['turn'])#最新一日的筹码就是当日的换手率
#关键统计,统计最后一天的各价位历史筹码堆积量(百分比)
ss=df.groupby(['instrument','avg_price'])[['remain_his']].sum().rename(columns={'remain_his':'筹码量'}).reset_index()
real_close=df.groupby('instrument')[['real_close']].apply(lambda x:x.iloc[0]).reset_index()
pp=ss.merge(real_close,on='instrument')
#计算end_date时收盘价的获利比例
winner=pp[pp.avg_price<=pp.real_close].groupby('instrument')[['筹码量']].sum().rename(columns={'筹码量':'winner'})
winner
| | winner |
| instrument | |
| 601699.SHA | 0.639122 |
601700.SHA | 0.817013 |
---|
#检查各股票各价位的筹码总和是否为1
ss.groupby('instrument')['筹码量'].sum()
instrument
601699.SHA 1.0
601700.SHA 1.0
Name: 筹码量, dtype: float32
计算全市场各股票每日的winner指标
instruments = ['601700.SHA','601699.SHA']
#这里尽量包含从上市日期开始到最后的数据
df_all = D.history_data(instruments, start_date='2005-01-02', end_date='2018-02-14',
fields=['open','close','adjust_factor','turn','volume']) #获取历史数据
def cal_winner_day(df_all):
winner=[]
for k in list(df_all.date):
df=df_all[df_all.date<=k]
df['real_close']=df['close']/df['adjust_factor']#获取真实收盘价
df['real_open']=df['open']/df['adjust_factor']#获取真实开盘价
df['turn']=df['turn']/100#获取换手率
df['avg_price']=np.round(df['real_close']+df['real_open'])/2#计算每日平均成本,这里按照0.5元一个价位做分析
df=df.sort_values(by='date',ascending=False).reset_index(drop=True)#日期按降序排列
df['turn_tomo']=df['turn'].shift(1)#计算明日的换手率
df['remain_day']=1-df['turn_tomo'] #计算当日的剩余筹码比例
#假设N日后,上市第一天的剩余筹码比率就是每日剩余比例的累乘即:剩余筹码比例=(1-明天换手率)*(1-后日换手率)*...*(1-最新日换手率),以此类推各日的剩余筹码
df['remain_his']=df['remain_day'].cumprod()
df['remain_his']=df['remain_his']*df['turn']
df['remain_his']=df['remain_his'].fillna(df['turn'])#最新一日的筹码就是当日的换手率
#关键统计,统计最后一天的各价位历史筹码堆积量(百分比)
ss=df.groupby('avg_price')[['remain_his']].sum().rename(columns={'remain_his':'筹码量'}).reset_index()
ss['real_close']=df['real_close'].iloc[0]
#计算end_date时收盘价的获利比例
winner_day=ss[ss.avg_price<=ss.real_close]['筹码量'].sum()
winner.append(winner_day)
result=pd.DataFrame({'winner':winner},index=df_all.date)
return result
winner_all=df_all.groupby('instrument').apply(cal_winner_day)
winner_all.reset_index().sort_values(by='date',ascending=False).head()
| | instrument | date | winner |
| 4497 | 601700.SHA | 2018-02-14 | 0.817013 |
| 2773 | 601699.SHA | 2018-02-14 | 0.639122 |
| 2772 | 601699.SHA | 2018-02-13 | 0.518967 |
| 4496 | 601700.SHA | 2018-02-13 | 0.816618 |
2771 | 601699.SHA | 2018-02-12 | 0.530768 |
---|