业务需求分析

  • 根据输入的可转债代码和价格(可选),分析单个可转债主要信息

  • 分析的主要字段是:

    • 基本信息:代码、名称、现价、剩余年限、行业、溢价率

    • 已转股比例: 此比例过高的话,大股东提升股价或下修转股价的动力就弱

    • 到期价值:赎回价+持有期未付利息之和*80%,  扣除了20%的税

    • 到期收益率:到期价值/当前转债价格-100%

    • 到期年化收益率:到期收益率/剩余年限

    • 回售价值:[回售价+当期的利息(按第四年算)] +持有到第四年所有未付利息之和*80%

    • 回售收益率:回售价值/当前转债价格-100%

    • 回售年化收益率:回售收益率/ 当前持有到第四年的年限(如果小于1,则直接取回售收益率)

    • 股东质押比例:此值越高,代表公司越缺钱,将债主转成股东的动力越大

    • 评级:评级越高,违约的风险越低

    • PB:市值/净资产, PB越大,说明下修转股价的空间越大

    • 发行规模: 此值越大说明盘子越大

    • 有无回售条款: 个别大公司,可能没有,尽量买有回售的

    • 有无担保: 有的话可减少违约风险

    • 转债占比:当前剩余的可转债占公司当前流通市值的比值

    • 是否登记强赎:如果登记了强赎,买之前应仔细看强赎日期

  • 关于转债利息部分,大部分转债都是一年一付,且是按转债发行日期开始计算,与持有人持有时间无关,所以此处计算利息时,认为超过1年,则按两年利息计算

程序分析

程序依赖

  • 提供数据的网站(集思录)、中登公司

  • 第三方库依赖:requests、bs4、prettytable

程序逻辑分析

  • 抓取所有可转债列表,通过输入的转债代码过滤出具体转债

  • 根据转债代码,找到当前转债的 行业、已转股比例、担保情况、利息等信息

  • 在中登官网获取该公司的质押比例

  • 计算到期价值、到期收益率、到期年化收益率、回售价值、回售收益率、回售年化收益率

  • 格式化输出所有关键字段信息

程序重要代码

请求可转债列表

def get_request(url):header = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36"}try:resp = requests.get(url, headers=header)resp.encoding = "utf-8"if resp.status_code == 200:return resp.textreturn Noneexcept Exception as e:print("http 请求失败!!,", e)return Nonedef get_bonds_list(url):'''获取可转债列表'''resp = get_request(url)resp_json = json.loads(resp)datas = resp_json["rows"]if datas is None:return Nonereturn datas

查询可转债详细信息

def get_bonds_detail(datas, bondCode):if datas == None or bondCode == None:print("请求参数为空,请检查程序!!")return Noneresult = None;for cell in datas:data=cell["cell"]bond_id = data["bond_id"]if bond_id == bondCode:result = databreakelse:print("没有查询到需要找的可转债,请重新开始!!")print("*"*50)return NonebondId = result["bond_id"]# 查询债券详细信息content = get_request("https://www.jisilu.cn/data/convert_bond_detail/%s" % bondId)if not content:print("查询单个转债信息失败,bondId: %s" % bondId)return None# 解析行业,已转股比例等信息soup = BeautifulSoup(content, "html.parser")cvtRt = soup.find(id="cvt_rt").textif cvtRt is None:cvtRt = "-"result["cvt_rt"] = cvtRtindusity = soup.find(class_="jisilu_nav").select("a")[1].textif indusity is None:indusity = "-"result["indusity"] = indusity# 利息rate = soup.find(id="cpn_desc").textif rate is None:rate = "-"result["rate"] = rate# 到期赎回价redeem_price = soup.find(id="redeem_price").textif redeem_price is None:redeem_price = "-"result["redeem_price"] = redeem_price# 回售价put_price = soup.find(id="put_price").textif put_price is None:put_price = "-"result["put_price"] = put_price# 担保guarantor = soup.find(id="guarantor").textif guarantor is None:guarantor = "-"result["guarantor"] = guarantor# 转债占流通市值占比convert_amt_ratio = soup.find(id="convert_amt_ratio").textif convert_amt_ratio is None:convert_amt_ratio = "-"result["convert_amt_ratio"] = convert_amt_ratio# 查询股东质押率pledge = get_pledge(result["stock_cd"])result["pledge"] = pledgereturn result

通过中登公司管网 查询股东质押比例(质押比例每周最后一个交易日才更新,当前如果不是周六的话,就往前推6天,取上一周的)

def get_pledge(stock_cd):'''查询股东质押比例,暂时发现周日好像无法查询'''# queryData = "2021.01.02"113035queryData = time.strftime("%Y.%m.%d", time.localtime())today = datetime.datetime.today().weekday() - 1if today!=6:today = datetime.date.today()- datetime.timedelta(days=6)queryData=today.strftime("%Y.%m.%d")content = get_request("http://www.chinaclear.cn/cms-rank/queryPledgeProportion?queryDate=%s&secCde=%s" % (queryData, stock_cd))soup = BeautifulSoup(content, "html.parser")frTmp = soup.find(class_="Stock Stock2")tdList = frTmp.find_all("td")pledge = tdList[-1].textif pledge is None:pledge = "-"else:pledge = pledge + "%"return pledge

计算投资价值及收益率

def calc_rate(data):'''计算收益率'''# 过滤利息newRateList = []rateList = data["rate"].split("%")# 将每年的利息过滤出来for r in rateList:newR = re.findall(r"\d.\d", r)if len(newR) > 0:newRateList.append(float(newR[0]))# 到期价值=到期赎回价+ 除最后一年外,所有未付利息之和*80%maturity = calc_maturity(newRateList, data["year_left"], data["redeem_price"])data["maturity"] = maturity# 到期收益率price = float(data["price"])priceDq = format((maturity - price)/price*100, ".2f")data["priceDq"] = priceDq + "%"# 到期年化收益率priceDqYear = format(float(priceDq) / float(data["year_left"]), ".2f")data["priceDqYear"] = priceDqYear + "%"# 回售价= 100+ 除最后两年,所有未付利息之和*80% (由于大部分转债都是最后两年开始回售,此处利息按第四年算)priceBack = 100 + newRateList[3]backPrice = calc_back(newRateList, data["year_left"], priceBack)data["backPrice"] = backPrice# 回售收益率priceHs = format((backPrice - price)/price*100, ".2f")data["priceHs"] = priceHs + "%"# 回售年化收益率priceHsYear = priceHsleftYear = float(data["year_left"]) - 2if leftYear > 0:priceHsYear = format(float(priceHs) / leftYear, ".2f")data["priceHsYear"] = priceHsYear + "%"return data

根据利息计算价值

def calc_back(newRateList, yearLeft, priceBack):yearLeft = float(yearLeft)leftYear = yearLeft - 2rateTotal = float(0)if leftYear >= 1:rateTotal += newRateList[3]if leftYear >= 2:rateTotal += newRateList[2]if leftYear >= 3:rateTotal += newRateList[1]if leftYear >= 4:rateTotal += newRateList[0]# 扣除20%的税result = priceBack + rateTotal * 0.8return resultdef calc_maturity(newRateList, yearLeft, redeemPrice):yearLeft = float(yearLeft)rateTotal = 0if yearLeft > 1:# 大于1年,按两年利息算,最赎回价+ 倒数第二年的利息rateTotal += newRateList[4]if yearLeft > 2:rateTotal += newRateList[3]if yearLeft > 3:rateTotal += newRateList[2]if yearLeft > 4:rateTotal += newRateList[1]if yearLeft > 5:rateTotal += newRateList[0]# 扣除20%的税result = float(redeemPrice) + rateTotal * 0.8return result

最终结果打印

def print_data(data):table=PrettyTable(header=False)table.add_row(["转债代码",data["bond_id"]])table.add_row(["转债名称",data["bond_nm"]])table.add_row(["现价",data["price"]])table.add_row(["评级",data["rating_cd"]])table.add_row(["PB(下调转股价空间)",str(data["pb"])+"(PB越大说明下修转股价的空间越大)"])table.add_row(["已转股比例",str(data["cvt_rt"])+"(已转股的比率太多了的话,建议不要买了,公司提升股价的愿望较弱)"])table.add_row(["剩余年限",data["year_left"]])table.add_row(["到期价值",str(data["maturity"])+"(按当前情况买入,持有到期来估算,加上持有中的利息,已扣除利息税,持有超过1年按2年利息计算)"])table.add_row(["到期收益率",data["priceDq"]])table.add_row(["到期年化收益率",data["priceDqYear"]])table.add_row(["回售价值",str(data["backPrice"])+"(按当前情况买入,持有到倒数第二年计算,加上持有中的利息,已扣除利息税,持有超过1年按2年利息计算)"])table.add_row(["回售收益率",data["priceHs"]])table.add_row(["回售年化收益率",data["priceHsYear"]])table.add_row(["有无回售条款","无(无回售条款,最好不要买)" if data["put_price"]=="-" else "有"])table.add_row(["有无担保",data["guarantor"]])table.add_row(["转债占比",str(data["convert_amt_ratio"])+"(表示当前剩余可转债占当前流通市值的比值)"])table.add_row(["股东质押比例",str(data["pledge"])+"(此值越高,说明公司越缺钱,公司提高股价或者下修转股价的概率越大)"])table.add_row(["行业",data["indusity"]])table.add_row(["溢价率",str(data["premium_rt"])+"%"])table.add_row(["是否登记强赎","否" if data["force_redeem"]==None else data["force_redeem"].replace("\r\n",",")])print(table)

主方法调用

while True:print("请输入要分析的可转债代码与价格,中间用逗号分隔(如不输入价格,默认按当前价),输入q退出!!")input_str=input("请输入:")if input_str==None or input_str.strip()==None or len(input_str)==0:print("输入为空,需要重新输入")continueif input_str=="q":breakinput_list=input_str.split(",")input_code=input_list[0].strip()input_price=input_list[1].strip() if len(input_list)>1 else None# 获取可转债列表datas=tools.get_bonds_list("https://www.jisilu.cn/data/cbnew/cb_list/?___jsl=LST___t=1609766310721")# 查询转债详细信息,及组装行业,已转股比率等信息data=tools.get_bonds_detail(datas,input_code)if data==None:continue# 计算收益率if input_price != None:data["price"]=input_pricedata=tools.calc_rate(data)# 输出当前转债的信息tools.print_data(data)

使用案例

127007 湖广转债分析

  • 评级:AA+ ,评级比较高,表示违约的概率小

  • PB:0.63, PB是 市值/净资产,这个值越小,说明公司下调转股价的空间就越小,小于1,基本上不会下调转股价了

  • 已转股比例:29.71% , 说明之前涨到了 130以上了,已经转了一部分股票了,这个比例还不算高,说明还有一大部分没转股

  • 到期价值:111.44, 根据年限及利息,从现在拿着,一直等到到期赎回,每张相当于 111.44元

  • 到期收益率:11.38%, 以当前的价格买入,持有到期的收益率

  • 到期年化收益率:3.27%, 用到期收益率除以剩余年限,这个收益率比货币基金高点,比债券基金少点

  • 回售价值:102.7, 表示从现在开始持有到第四年,加上利息,如果回售的话,每张大概是102.7元,收益率是 2.56%, 年化收益率是 1.79%,价值跟货币基金差不多

  • 股东质押比例:7.77% , 不是很高,说明公司暂时不是很缺钱,相对而言,转股的动力会比较弱

  • 行业: 有线电视网络  , 这是传媒行业,根据之前统计的已退市可转债情况来看,这个行业 触发强赎的概率还是比较高的

总结下: 湖广转债,违约概率很低,最差的情况,以当前价格买的话,最后收益略高于货币基金。 其所处行业还不错,但公司暂时不是很缺钱,暂时基本上不能通过下调转股价,来增加触发强赎概率(说明短期内,除非市场环境影响,公司自己主动采取措施提升股价的希望很小)。 但是投资者如果长期持有的话,是不会亏本的,在剩余的3.5年中,还是有不小的概率触发强赎的。 整体评价一般。

以上分析,都是分析在最差的情况下,能有什么样的收益率,投资可转债想要好收益率,当然是在强赎的情况下。  用安道全的话说,每只可转债都应该强赎,且概率都很大。  但这两年发行的可转债很多,质量也都参差不齐,未来是否有转债会违约,谁也说不准,但相信只要在 到期价值以内购买,AA级以上的债卷,长期持有,收益率想来是不会太差的,风险也小。  巴菲特: 投资的第一条原则是 不要亏损, 第二条原则是, 参照第一条 ... 

注:以上文章较早发布于 公众号中,这些数据在当前已经不适用了,此次发布主要是以学习编程及分析思路为主

程序猿与投资生活实录已改名为  程序猿知秋,WX同款,欢迎关注!

Python—写个可转债分析器相关推荐

  1. 用python写一个可转债的投资策略

    写一个投资策略需要考虑到很多因素,这里是一个基本的可转债投资策略的示例: 选择财务稳健的公司发行的可转债. 观察市场价格和债券指标,如净价.价值.估值等. 当可转债价格较低时买入,当价格较高时卖出. ...

  2. 动手写的Python的HTML语法分析器(面向对象)

    动手写的Python的HTML语法分析器(面向对象) 主要包括4个文件,util.py文件主要负责截取每个块. rules.py文件定义两个类,超类Rule和分别对应的子类,子类定义了不同的划分块的要 ...

  3. 用python写计算机专业_自学open cv,用Python写的,本人是一名学生党,因为我本专业不是搞计算机的_cc霜_学生党_教育_教育其他...

    自学open cv,用Python写的,本人是一名学生党,因为我本专业不是搞计算机的,所以一切从0开始,自己学习的时候就整理一些笔记,以防忘记了.

  4. Python写的代码打包成.exe可执行文件

    Python写的代码打包成.exe可执行文件 1. 安装pyinstaller 2. [在线生成icon](http://www.ico51.cn/) 3. 打包命令 pyinstaller -i x ...

  5. 用python做算法_自己用python写的螺旋矩阵生成算法

    自己用python写的螺旋矩阵生成算法 如果输入6,可以生成如下矩阵: 1 20 19 18 17 16 2 21 32 31 30 15 3 22 33 36 29 14 4 23 34 35 28 ...

  6. python写一个通讯录step by step V3.0

    python写一个通讯录step by step V3.0 更新功能: 数据库进行数据存入和读取操作 字典配合函数调用实现switch功能 其他:函数.字典.模块调用 注意问题: 1.更优美的格式化输 ...

  7. python俄罗斯方块算法详解_用 Python 写一个俄罗斯方块游戏 (

    @@ -2,34 +2,34 @@ > * 原文作者:[Dr Pommes](https://medium.com/@pommes) > * 译文出自:[掘金翻译计划](https://g ...

  8. Python到底是什么样的语言? Python和Java比谁更快? TensorFlow的主体是用Python写的吗?

    Python到底是什么样的语言? Python和Java比谁更快? TensorFlow的主体是用Python写的吗? Python到底是什么样的语言? 解析: 这里是一些关键点:Python是解释型 ...

  9. python编写测试工具-python 写一个性能测试工具(一)

    国庆重新学习了一下go的gin高性能测试框架. 用JMeter来测试gin与flask接口的性能,差别很大. 为什么我自己不尝试写一个性能工具,性能工具的核心就是 并发 和 请求. 请求可以选择Pyt ...

最新文章

  1. 聊一聊 Python 安装中的 --enable-shared
  2. Generic Data Access Objects -范型DAO类设计模式
  3. 【备忘】linux shell 字符串操作(长度,查找,替换,匹配)详解
  4. log4j打印mybatis执行的sql
  5. 笔记3——C++类的一些特性
  6. JVM之垃圾收集器回收种类
  7. [Json] C#ConvertJson|List转成Json|对象|集合|DataSet|DataTable|DataReader转成Json (转载)...
  8. 服务器能做镜像文件吗,如何给服务器做镜像
  9. sticky-footer布局
  10. Python3.4下使用sqlalchemy
  11. android 锁屏后定时器,iOS锁屏或者后台计时器定时解决方法
  12. druid1.2.8源码悦读:第五天
  13. Mybatisplus argument type mismatch
  14. PXC 安装 (yum操作)
  15. 查看word的版本型号
  16. 7. Applepay 解码实操-golang
  17. linux fat get entry,Linux kernel FAT32文件系统分析
  18. android语音识别方法示例代码
  19. 误删桌面计算机图标win10,win10此电脑图标误删
  20. 「分治法」棋盘覆盖问题

热门文章

  1. 二本程序员投简历被公司嘲讽:过面试的可能性不大,别白跑了
  2. 爱数之文件备份与恢复
  3. 2017-5-5 QQ面板 (用户控件、timer控件,轮询实现聊天功能)
  4. 0007windows搭建vue
  5. html 载入视频wmv,[转]Html中添加.wmv视频文件-Windows Media Player
  6. 员工口中的50家最好的科技公司
  7. C++ 缓冲区 (buffer)
  8. 安卓去除虚拟按键(home键,返回键,列表键)
  9. Greedy Algorithm correctness proof
  10. 【微信小程序】快捷util封装