程序依赖
提供数据的网站(集思录)、中登公司
**第三方库依赖: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.text
return None
except Exception as e:
print("http 请求失败!!,", e)
return None
def get_bonds_list(url):
'''获取可转债列表'''
resp = get_request(url)
resp_json = json.loads(resp)
datas = resp_json["rows"]
if datas is None:
return None
return datas
查询可转债详细信息
def get_bonds_detail(datas, bondCode):
if datas == None or bondCode == None:
print("请求参数为空,请检查程序!!")
return None
result = None;
for cell in datas:
data=cell["cell"]
bond_id = data["bond_id"]
if bond_id == bondCode:
result = data
break
else:
print("没有查询到需要找的可转债,请重新开始!!")
print("*"*50)
return None
bondId = 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").text
if cvtRt is None:
cvtRt = "-"
result["cvt_rt"] = cvtRt
indusity = soup.find(class_="jisilu_nav").select("a")[1].text
if indusity is None:
indusity = "-"
result["indusity"] = indusity
# 利息
rate = soup.find(id="cpn_desc").text
if rate is None:
rate = "-"
result["rate"] = rate
# 到期赎回价
redeem_price = soup.find(id="redeem_price").text
if redeem_price is None:
redeem_price = "-"
result["redeem_price"] = redeem_price
# 回售价
put_price = soup.find(id="put_price").text
if put_price is None:
put_price = "-"
result["put_price"] = put_price
# 担保
guarantor = soup.find(id="guarantor").text
if guarantor is None:
guarantor = "-"
result["guarantor"] = guarantor
# 转债占流通市值占比
convert_amt_ratio = soup.find(id="convert_amt_ratio").text
if convert_amt_ratio is None:
convert_amt_ratio = "-"
result["convert_amt_ratio"] = convert_amt_ratio
# 查询股东质押率
pledge = get_pledge(result["stock_cd"])
result["pledge"] = pledge
return result
通过中登公司管网 查询股东质押比例(质押比例每周最后一个交易日才更新,当前如果不是周六的话,就往前推6天,取上一周的)
def get_pledge(stock_cd):
'''查询股东质押比例,暂时发现周日好像无法查询'''
# queryData = "2021.01.02"113035
queryData = time.strftime("%Y.%m.%d", time.localtime())
today = datetime.datetime.today().weekday() - 1
if 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].text
if 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 = priceHs
leftYear = float(data["year_left"]) - 2
if leftYear > 0:
priceHsYear = format(float(priceHs) / leftYear, ".2f")
data["priceHsYear"] = priceHsYear + "%"
return data
根据利息计算价值
def calc_back(newRateList, yearLeft, priceBack):
yearLeft = float(yearLeft)
leftYear = yearLeft - 2
rateTotal = 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.8
return result
def calc_maturity(newRateList, yearLeft, redeemPrice):
yearLeft = float(yearLeft)
rateTotal = 0
if 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.8
return 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("输入为空,需要重新输入")
continue
if input_str=="q":
break
input_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_price
data=tools.calc_rate(data)
# 输出当前转债的信息
tools.print_data(data)
127007 ** 湖广转债分析**
**总结下: **湖广转债,违约概率很低,最差的情况,以当前价格买的话,最后收益略高于货币基金。 其所处行业还不错,但公司暂时不是很缺钱,暂时基本上不能通过下调转股价,来增加触发强赎概率(说明短期内,除非市场环境影响,公司自己主动采取措施提升股价的希望很小)。 但是投资者如果长期持有的话,是不会亏本的,在剩余的3.5年中,还是有不小的概率触发强赎的。 整体评价一般。
**注: 以上分析,都是分析在最差的情况下,能有什么样的收益率,投资可转债想要好收益率,当然是在强赎的情况下。 用安道全的话说,每只可转债都应该强赎,且概率都很大。 但这两年发行的可转债很多,质量也都参差不齐,未来是否有转债会违约,谁也说不准,但相信只要在 到期价值以内购买,AA级以上的债卷,长期持有,收益率想来是不会太差的,风险也小。 巴菲特: 投资的第一条原则是 不要亏损, 第二条原则是, 参照第一条 ...
**
全部0条评论
快来发表一下你的评论吧 !