阅读:0
听报道
【风险提示】
本文原始数据来自于WIND信用债板块的收盘价,对于市场成交不活跃的个券,可能与实际市场表现不完全符合。
2020年11月10日,20永煤SCP003违约,对信用债市场的情绪和流动性带来负面冲击,目前冲击仍在继续。我们希望可以及时监测信用债异常成交价格的情况。使用WIND的Python接口监测信用债异常成交的步骤如下:
1 获得所有信用债的收盘价(以MTN为例)
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from WindPy import w
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示正负号
我们先通过WIND接口获得MTN的所有wind代码,因为MTN的全部个券有6200多只,所以我们要分开获取收盘价。
w.start()
_code = w.wset("sectorconstituent", "date=2020-11-16;sectorid=1000004570000000")
# 获取MTN的所有代码
_code1 = ','.join(_code.Data[1][0:5000])
_code2 = ','.join(_code.Data[1][5000:])
# 将代码分拆合并
_data1 = w.wsd(_code1, "close", "2020-11-13", "2020-11-16", "")
_data1 = pd.DataFrame(_data1.Data, index=_data1.Codes, columns=[x.strftime('%Y-%m-%d') for x in _data1.Times])
_data2 = w.wsd(_code2, "close", "2020-11-13", "2020-11-16", "")
_data2 = pd.DataFrame(_data2.Data, index=_data2.Codes, columns=[x.strftime('%Y-%m-%d') for x in _data2.Times])
# 获得MTN的所有券在2020-11-13日与2020-11-16日的成交价
_data = pd.concat([_data1, _data2])
最终获得数据大概如下:
2 提取异常成交的个券
比如我们设定,成交价跌幅超过0.5元的,就认为是异常成交,并按照跌幅排序
_data['diff'] = _data['2020-11-16'] - _data['2020-11-13']
_abnormal = _data[_data['diff'] < -0.5]
_abnormal = _abnormal.sort_values('diff')
从下图可以看到,我们从6289只MTN中,筛选出98只跌幅超过0.5元的个券,其中最大的跌幅是-14.5元。
3 获得异常成交个券的详细信息
我们已经获得了异常成交个券,我们需要了解更多的信息,比如个券的名称,存续债券规模,到期日,地区,行业,是否是城投,甚至各种财务指标等。我们就用个券的wind代码,来匹配各项信息。
_data = w.wss(','.join(_abnormal.index), "sec_name,issuerupdated,outstandingbalance,maturitydate,term,repo_lastestdate,abs_industry,abs_industry1,abs_province,municipalbond", "tradeDate=2020-11-16")
_data = pd.DataFrame(np.array(_data.Data).T, columns=_data.Fields, index=_data.Codes)
_data = _abnormal.join(_data)
下图中的信息,可以根据自己需求,进行添加或者删改
我们也可以比较方便的做一个统计分析,比如我们来看看,异常成交的MTN个券的企业性质和地区分布如下。从下图中可以看到,地方国有企业的异常下跌券数,是明显高于其他企业性质的。
代码如下:
fig = plt.figure(figsize=(16,8))
ax1 = fig.add_subplot(121)
_data['ABS_INDUSTRY1'].hist(ax=ax1, grid=False, xrot=90)
ax2 = fig.add_subplot(122)
_data['ABS_PROVINCE'].hist(ax=ax2, grid=False, xrot=90, bins=50)
以上就是我们的案例演示部分,我们可以将短期融资券、超短期融资券、中期票据、交易所公司债等信用债的数据,都按照类似的方法提取,并且可以对价格观测的时间进行灵活设定,我们把完全代码列示如下:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from WindPy import w
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示正负号
def trans_code(code, firsttime, lasttime):
w.start()
_data = w.wsd(code, "close", firsttime, lasttime, "")
_data = pd.DataFrame(_data.Data, index=_data.Codes, columns=[x.strftime('%Y-%m-%d') for x in _data.Times])
return _data
def get_data(sector, firsttime, lasttime):
w.start()
if sector == 'cp':
_code = w.wset("sectorconstituent", "date={};sectorid=1000004566000000".format(lasttime))
# 短期融资券-一般短期融资券,500多只
_code = ','.join(_code.Data[1])
_data = trans_code(_code, firsttime, lasttime)
return _data
elif sector == 'scp':
_code = w.wset("sectorconstituent", "date={};sectorid=1000004194000000".format(lasttime))
# 短期融资券-超短期融资券,2200多只
_code = ','.join(_code.Data[1])
_data = trans_code(_code, firsttime, lasttime)
return _data
elif sector == 'mtn':
_code = w.wset("sectorconstituent", "date={};sectorid=1000004570000000".format(lasttime))
# 中期票据-一般中期票据,6200多只
_code1 = ','.join(_code.Data[1][0:5000])
_code2 = ','.join(_code.Data[1][5000:])
_data1 = trans_code(_code1, firsttime, lasttime)
_data2 = trans_code(_code2, firsttime, lasttime)
_data = pd.concat([_data1, _data2])
return _data
elif sector == 'cb':
# 一般公司债,3700多只
_code = w.wset("sectorconstituent", "date={};sectorid=1000009966000000".format(lasttime))
_code = ','.join(_code.Data[1])
_data = trans_code(_code, firsttime, lasttime)
return _data
elif sector == 'pcb':
# 公司债-私募债,5100多只
_code = w.wset("sectorconstituent", "date={};sectorid=1000009967000000".format(lasttime))
_code1 = ','.join(_code.Data[1][0:5000])
_code2 = ','.join(_code.Data[1][5000:])
_data1 = trans_code(_code1, firsttime, lasttime)
_data2 = trans_code(_code2, firsttime, lasttime)
_data = pd.concat([_data1, _data2])
return _data
else:
print("You may input wrong arguments.")
def abnormal(sector, firsttime, lasttime, threshold):
_data = get_data(sector, firsttime, lasttime)
_data['diff'] = _data[lasttime] - _data[firsttime]
_abnormal = _data[_data['diff'] < threshold]
return _abnormal
def get_abnormal(sector, firsttime, lasttime, threshold):
w.start()
_abnormal = abnormal(sector, firsttime, lasttime, threshold)
_data = w.wss(','.join(_abnormal.index),
"sec_name,issuerupdated,outstandingbalance,maturitydate,term,repo_lastestdate,"
"abs_industry,abs_industry1,abs_province,municipalbond",
"tradeDate={}".format(lasttime))
_data = pd.DataFrame(np.array(_data.Data).T, columns=_data.Fields, index=_data.Codes)
_data = _abnormal.join(_data)
print(_data)
return _data
data_cp = get_abnormal('cp', '2020-11-13', '2020-11-16', -0.5)
data_scp = get_abnormal('scp', '2020-11-13', '2020-11-16', -0.5)
data_mtn = get_abnormal('mtn', '2020-11-13', '2020-11-16', -0.5)
data_cb = get_abnormal('cb', '2020-11-13', '2020-11-16', -0.5)
data_pcb = get_abnormal('pcb', '2020-11-13', '2020-11-16', -0.5)
话题:
0
推荐
财新博客版权声明:财新博客所发布文章及图片之版权属博主本人及/或相关权利人所有,未经博主及/或相关权利人单独授权,任何网站、平面媒体不得予以转载。财新网对相关媒体的网站信息内容转载授权并不包括财新博客的文章及图片。博客文章均为作者个人观点,不代表财新网的立场和观点。