2020年更新:本文的方法已经失效,现需采购交易中心数据方可获得个券借贷数据
债券借贷是YH间市场借券卖空最主要的交易途径,买断式回购虽然也能开展借券卖空,但是在出借债券的方式上,YH还是明显更加偏好债券借贷,一方面债券借贷借出时债券不出表,另一方面借贷费用收入是中间业务收入,相比于买断式回购在这两点上具有显著优势。所以债券借贷存量数据对于市场卖空力度是一个很好的指标,尤其是一些新券。目前市场上新券借贷费率显著高于老券,机构借入老券还有可能用于回购融资,而承担高费率借入新券则大概率是用于卖空。
去年,债券市场大牛市,资金也很宽松,债券借贷卖空和融资的需求都减弱不少,然而今年债市波动加剧,国开和GZ最新券卖空力量显著加强,债券借贷的存量也显著上升,以180027为例,在3-4月间其债券借贷存量上升100多亿。在这样的背景下,我们必须对债券借贷数据重新重视起来。此前,债券借贷数据每日均公布在外汇交易中心的网站上,然而目前此数据的链接已经不显示在chinamoney网站上了,虽然并非无法访问,但访问方式很麻烦,也无法一次性导出。我参考18年初固收小黄的公众号文章优化了python爬虫的代码,可以一次性导出指定债券的借贷历史数据到excel,并自动更新数据并保存至原excel文件,可以方便的每日定时运行该程序进行自动更新。
第一部分代码定义几个函数
import datetime import time #外部包,xlwt,xlrd,xlutils是excel读写包,WindPy是Wind包,BeautifulSoup用于网页解析,urllib用于获取网页 import xlwt import xlrd from xlutils.copy import copy from bs4 import BeautifulSoup import urllib import datetime from WindPy import w def getTradingDayList(date): w.start() trade_day_list=[] if date==0: #如果原本没有数据,从T-20日开始 startdate = w.tdaysoffset(-20, time.strftime("%Y-%m-%d"), "TradingCalendar=NIB") else: #获取现有最新数据的下一交易日 startdate = w.tdaysoffset(1, date, "TradingCalendar=NIB") if startdate.Times[0]>=datetime.date.today(): print('Data is up-to-date') else: tm1=w.tdaysoffset(0, time.strftime("%Y-%m-%d"), "TradingCalendar=NIB") #如果今日是交易日,则获取数据截至上一交易日 if tm1.Times[0]==datetime.date.today(): tm1=w.tdaysoffset(-1, time.strftime("%Y-%m-%d"), "TradingCalendar=NIB") trade_day_list = w.tdays(startdate.Times[0],tm1.Times[0], "TradingCalendar=NIB").Times w.stop() return trade_day_list def getlastday(filename): try: #打开文件 data = xlrd.open_workbook(filename) table = data.sheets()[0] rows=table.nrows #获取最后一行第一列的日期 date = xlrd.xldate_as_tuple(table.cell(rows-1,0).value,0) value = datetime.datetime(*date) return value except FileNotFoundError: #找不到文件 return 0 def zqjd_one_day(year, month, day,bond_list): #把日期填入链接,得到实际的url turl="http://www.chinabond.com.cn/jsp/include/EJB/jdtj_dzzq.jsp?sel4=1&tbSelYear6=" + str(year) + "&tbSelMonth6=" + str(month) + "&calSelectedDate6=" + str(day)+ "&ZQFXRJD1=00&FUXFSJD1=00&JXFSJD2=00&JDQX2=00&ZQFXRJD3=00&ZQFXRJD4=00&I_ZQDM_JD=" #交易中心网站已屏蔽爬虫,必须指定header伪装为浏览器否则爬虫无法访问网站 headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'} req = urllib.request.Request(url=turl, headers=headers) #获取网页信息 page = request.urlopen(req) #解析,使用gb18030防止中文乱码 soup = BeautifulSoup(page, "html.parser", from_encoding="gb18030") jqye_list = [] print('Trading Day '+str(year) + str(month).zfill(2) + str(day).zfill(2) + ':' ) for bond_name in bond_list: #找到表格中债券代码匹配的行 bond_position = soup.find('td', text=bond_name) if bond_position is None: #没找到,借贷量为0 bond_jqye = 0 else: #交易中心数据格式为100,000.00,所以去掉.00和逗号 bond_jqye = int(bond_position.next_sibling.next_sibling.string.strip().replace(',', '').replace('.00', '')) print(bond_name + ':' + str(bond_jqye)) jqye_list.append(bond_jqye) return jqye_list def zqjd(bond_list,trade_day_list,filename): #指定excel日期存储格式 datastyle = xlwt.XFStyle() datastyle.num_format_str = 'yyyy/mm/dd' total_jqye_list=[] try: #打开现有文件 data = xlrd.open_workbook(filename, formatting_info=True) table = data.sheets()[0] startrow = table.nrows-1 # 将文件对象拷贝,变成可写的workbook对象 output_workbook = copy(data) # 获得第一个sheet的对象 sheet1 = output_workbook.get_sheet(0) except FileNotFoundError: #找不到文件,则创建Excel文件,excel同单元格可覆盖写入 output_workbook = xlwt.Workbook() sheet1 = output_workbook.add_sheet(u'BondLendingData', cell_overwrite_ok=True) startrow=0 #遍历所有交易日 for trade_day in trade_day_list: #获取每个交易日的借贷信息 jqye_list = zqjd_one_day(trade_day.year, trade_day.month, trade_day.day, bond_list) #暂停5秒,防止过于频繁访问网站被封禁 time.sleep(5) total_jqye_list.append(jqye_list) #Excel的A1单元格写入Date if startrow==0: sheet1.write(0, 0, 'Date') for i in range(len(bond_list)): #从第一行的第二个单元格开始从左至右写入债券代码 sheet1.write(0, i + 1, bond_list[i]) for i in range(len(total_jqye_list)): #每个交易日另起一行,左起写入交易日,格式为指定的日期格式 sheet1.write(startrow + i + 1, 0, trade_day_list[i],datastyle) for j in range(len(total_jqye_list[i])): #写入在该交易日每个债券对应的借贷量 sheet1.write(startrow + i + 1, j + 1, total_jqye_list[i][j]) #逐行保存到Excel文件 output_workbook.save(filename) return
第二部分为主体部分,相对简单
import datetime filename='zqjd_output.xls' #取现有最新数据的日期 date=getlastday(filename) trade_day_list=getTradingDayList(date) #print(trade_day_list) if trade_day_list: bond_list = ['190205', '180210' ,'180027'] zqjd(bond_list,trade_day_list,filename) print('Done!')
python输出如下所示
Trading Day 20190415: 190205:3889000 180210:4238000 180027:1810000 Trading Day 20190416: 190205:4279000 180210:4178000 180027:1854000 Trading Day 20190417: 190205:4473000 180210:4024000 180027:1877000 Done!
excel输出如下所示
Date | 190205 | 180210 | 180027 |
2019/04/15 | 3889000 | 4238000 | 1810000 |
2019/04/16 | 4279000 | 4178000 | 1854000 |
2019/04/17 | 4473000 | 4024000 | 1877000 |
此程序输入参数主要有两个,一个是债券列表,例子中为190205,180210,180027,其二为文件名,本例中zqjd_output.xls,实际上另外还有一个输入是交易日区间,上述代码中交易日是自动获取的,第一次运行从T-20开始获取数据,此后自动更新补全至最新交易日。输出就是一个xls文件,借贷量数字单位为万,可以很方便的进行后续处理和展示。不过需要注意的是,如果更改了债券列表,则需要删除原文件或指定新的文件名,否则更新数据将出现错乱的情况。
文章评论