Skip to main content

Bài 4: Xác suất vỡ nợ

Trước khi tiếp cận với ứng dụng các thuật toán Học máy đối với dữ liệu tài chính, chúng ta sẽ cùng nhau tiếp cận bài toán xác suất vỡ nợ (tiếng anh là Probability of Default hay viết tắt là PD). Trong thị trường tài chính, xác suất vỡ nợ là xác suất mà một công ty phát hành trái phiếu không đáp ứng được các nghĩa vụ hợp đồng của mình theo đúng tiến độ. Bên cạnh trường hợp phổ biến nhất là doanh nghiệp không thanh toán dẫn đến phá sản, ta có thể xây bản cáo bạch trái phiếu xác định các trường hợp vỡ nợ khác, chẳng hạn như việc không đáp ứng một nghĩa vụ nào đó trong hợp đồng hoặc vi phạm giao ước tài chính.

1. Giới thiệu

Trong bài viết này, chúng ta sẽ tập trung vào xác suất vỡ nợ có thời hạn một năm của giá trái phiếu doanh nghiệp theo thị trường. Thời hạn một năm cho đến khi đáo hạn được chọn để tính toán xác suất vỡ nợ theo thị trường bởi lí do sau:

  • Trong khoảng thời gian ngắn hơn một hoặc hai năm, các công ty phải chịu tác động của chu kỳ kinh doanh.
  • Trong khoảng thời gian dài hơn, hiệu ứng của chu kỳ kinh doanh có xu hướng có tác động ít hơn và cấu trúc vốn của công ty trở nên quan trọng hơn, từ đó làm cho mức độ rủi ro dài hạn ít theo chu kỳ hơn và ổn định hơn.

Chúng ta sẽ tận dụng bảng "Tỷ lệ chuyển đổi trung bình trong một năm cho các doanh nghiệp toàn cầu" của Standard & Poor với dữ liệu lịch sử từ năm 1981-2019 để đánh giá các xác suất quan sát được của một xếp hạng cụ thể chuyển đổi sang xếp hạng khác trong suốt một năm.

2. Thu thập và chuyển đổi dữ liệu

Để tính toán xác suất vỡ nợ theo thị trường, trước tiên chúng ta phải thu được giá trái phiếu hiện tại của công ty. Nếu bạn chưa biết làm thế nào để thu thập được thông tin này thì đừng lo, đã có Selenium giúp bạn. Selenium là công cụ chúng ta có thể sử dụng để tự động hóa hoạt động trình duyệt do người dùng thực hiện, chẳng hạn như tải một trang web và điền vào biểu mẫu trên trang web đó. Nó yêu cầu một WebDriver cụ thể cho trình duyệt web của một người.

Trong trường hợp bạn chưa cài đặt Selenium, bạn có thể truy cập các liên kết tương ứng của chúng và tải chúng xuống bằng cách sử dụng pip (tham khảo cách sử dụng pip tại đây). Ngoài ra, ta cũng sẽ cần một chromedriver, có thể tải xuống bằng Python với gói WebDriver-manager trong PyPi.

Chúng ta sẽ sử dụng tập các câu lệnh Selenium để mô phỏng các thao tác nhấn phím và nhấp chuột của người dùng trong trình duyệt như một phương tiện để trỏ đến dữ liệu trái phiếu Trade Reporting and Compliance Engine (TRACE) do Cơ quan quản lý ngành tài chính (FINRA) cung cấp, từ đó truy cập dữ liệu cần thiết để tính toán xác suất vỡ nợ của thị trường.

Trước hết, chúng ta sẽ cài đặt những thư viện cần thiết sử dụng pip và import những thư viện sẽ dùng trong bài viết này.

# Mô phỏng thao tác người dùng để đào dữ liệu
!pip install selenium
# Đơn giản hóa việc quản lý trình điều khiển nhị phân cho các trình duyệt khác nhau.
!pip install webdriver_manager
# Truy cập dữ liệu tài chính công khai từ Internet và nhập dữ liệu đó vào Python dưới dạng DataFrame.
!pip install pandas_datareader
# Tính toán đại số
!pip install sympy
import time
import numpy as np
import pandas as pd
import pandas_datareader as dr
from datetime import date
from datetime import datetime as dt
from datetime import timedelta
from sympy import solve, symbols
import matplotlib.pyplot as plt

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import Select, WebDriverWait
from webdriver_manager.chrome import ChromeDriverManager

Chúng ta sẽ tải xuống thông tin về trái phiếu của công ty từ cơ sở dữ liệu TRACE, được duy trì bởi FINRA bằng đoạn mã dưới đây. Một số công ty bạn có thể thử, ví dụ: |Mã công ty| Tên công ty| |:-:|:-:| |HES|Hess| |F|Ford Motor| |KHC|Kraft Heinz Co| |DVN|Devon Energy| |...|...|

Một số tần suất coupon có thể sử dụng: ALL, Annual, Anytime, Bi-Monthly, Monthly, N/A, None, Pays At Maturity, Quarterly, Semi-Annual, Variable, ...

# Bắt buộc
company_ticker = "HES"

# Tuỳ chọn
company_name = "Hess"

# Tuỳ chọn đầu vào:
coupon_frequency = "Semi-Annual"
# Đoạn mã Selenium để thu thập dữ liệu
options = Options()
options.add_argument("--headless")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
driver = webdriver.Chrome(
service=Service(ChromeDriverManager().install()), options=options
)

# Lưu thời gian bắt đầu thực thi vào biến begin
begin = time.time()

# Truy cập vào FINRA's TRACE Bond Center
driver.get("http://finra-markets.morningstar.com/BondCenter/Results.jsp")

# Chọn đồng ý
WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, ".button_blue.agree"))
).click()

# Chọn chỉnh sửa tìm kiếm
WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, "a.qs-ui-btn.blue"))
).click()

# Chọn Tên tổ chức phát hành
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "input[id=firscreener-issuer]"))
)
inputElement = driver.find_element(By.ID, "firscreener-issuer")
inputElement.send_keys(company_name)

# Chọn biểu tượng
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "input[id=firscreener-cusip]"))
)
inputElement = driver.find_element(By.ID,"firscreener-cusip")
inputElement.send_keys(company_ticker)

# Chọn tìm kiếm nâng cao
WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, "a.ms-display-switcher.hide"))
).click()

# Chọn Coupon Frequency
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "select[name=interestFrequency]"))
)
Select(
(driver.find_elements(By.CSS_SELECTOR,"select[name=interestFrequency]"))[0]
).select_by_visible_text(coupon_frequency)

# Chọn hiển thị kết quả
WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, "input.button_blue[type=submit]"))
).click()

# Chờ kết quả
WebDriverWait(driver, 10).until(
EC.presence_of_element_located(
(By.CSS_SELECTOR, ".rtq-grid-row.rtq-grid-rzrow .rtq-grid-cell-ctn")
)
)

# Tạo DataFrame lưu trữ thông tin
frames = []
for page in range(1, 11):
bonds = []
WebDriverWait(driver, 10).until(
EC.presence_of_element_located(
(By.CSS_SELECTOR, (f"a.qs-pageutil-btn[value='{str(page)}']"))
)
)
time.sleep(2)

headers = [
title.text
for title in driver.find_elements(By.CSS_SELECTOR,
".rtq-grid-row.rtq-grid-rzrow .rtq-grid-cell-ctn"
)[1:]
]

tablerows = driver.find_elements(By.CSS_SELECTOR,
"div.rtq-grid-bd > div.rtq-grid-row"
)
for tablerow in tablerows:
tablerowdata = tablerow.find_elements(By.CSS_SELECTOR,"div.rtq-grid-cell")
bond = [item.text for item in tablerowdata[1:]]
bonds.append(bond)

# Chuyển về DataFrame
df = pd.DataFrame(bonds, columns=headers)

frames.append(df)

try:
driver.find_element(By.CSS_SELECTOR,"a.qs-pageutil-next").click()
except:
break

bond_prices_df = pd.concat(frames)

# Lưu thời gian kết thúc
end = time.time()

# Tính tổng thời gian chương trình chạy
print(f"Total runtime of the program is {end - begin} seconds")

bond_prices_df

Chúng ta cũng đã tải xuống thông tin về giá và xếp hạng cho trái phiếu do một công ty phát hành cụ thể phát hành từ cơ sở dữ liệu trái phiếu được đánh giá cao, TRACE từ FINRA. Sau khi tải xuống, chúng ta tiếp tục sạch dữ liệu, chuyển đổi một số dữ liệu liên quan đến kỳ hạn trái phiếu và lọc dữ liệu để có thể tập trung phân tích vào các trái phiếu có kỳ hạn ngắn hơn thông qua hàm dưới đây.

def bond_dataframe_filter(df):
# Loại bỏ những bản ghi về thông tin trái phiếu bị thiếu lợi suất và xếp hạng tín dụng
df["Yield"].replace("", np.nan, inplace=True)
df["Moody's®"].replace({"WR": np.nan, "": np.nan}, inplace=True)
df["S&P"].replace({"NR": np.nan, "": np.nan}, inplace=True)
for col in ["Yield", "Moody's®", "S&P"]:
df = df.dropna(subset=[col])

# Tạo cột Số năm đáo hạn Maturity Years phù hợp với
# Khoản thanh toán nửa năm một lần Semi-Annual Payments từ trái phiếu doanh nghiệp
now = dt.strptime(date.today().strftime("%m/%d/%Y"), "%m/%d/%Y")
df["Raw_Maturity"] = pd.to_datetime(df["Maturity"]).dt.strftime("%m/%d/%Y")
df["Maturity"] = [(dt.strptime(x, "%m/%d/%Y") - now).days for x in df["Raw_Maturity"]]
df["Maturity Years"] = [round((x/360)/0.5)*0.5 for x in df["Maturity"]]

# Ép kiểu dữ liệu về dạng số thực
for col in ["Maturity", "Yield", "Coupon", "Price"]:
df[col] = df[col].astype(float)

return df[(df["Maturity Years"] > 0) & (df["Maturity Years"] <= 5)]
bond_df_result = bond_dataframe_filter(bond_prices_df)
bond_df_result

3. Tính dòng tiền chiết khấu

Chúng ta sẽ sử dụng các kỹ thuật định giá trái phiếu (Bond Prices) để tính xác suất vỡ nợ bằng cách sử dụng giá trái phiếu doanh nghiệp hiện tại. Việc định giá trái phiếu doanh nghiệp tương tự như bất kỳ tài sản rủi ro nào; nó phụ thuộc vào giá trị hiện tại của các dòng tiền kỳ vọng (Expected Cash Flow hay $ECF$) trong tương lai theo lãi suất suất chiết khấu $d$ (Discount Rate).

\begin{equation} BOND\ PRICE = \frac{ECF_1}{1+d}\ +\ \frac{ECF_2}{(1+d)^2}\ +\ \frac{ECF_3}{(1+d)^3} \end{equation}

Việc định giá trái phiếu doanh nghiệp cũng cần tính đến khả năng trái phiếu không trả được nợ và không trả lại đầy đủ tiền gốc. Khi đó, ta cần ước tính dòng tiền kỳ vọng và lãi suất chiết khấu được điều chỉnh theo rủi ro.

Để định giá trái phiếu, trước hết ta tìm ECF ở mỗi thời kỳ bằng cách cộng tích của khoản thanh toán mặc định (Default Payout) và xác suất vỡ nợ (P) với tích của khoản thanh toán đã hứa (thanh toán phiếu lãi và trả nợ gốc) và xác suất không vỡ nợ (1-P), hay còn gọi là như xác suất sống sót. \begin{equation} ECF_1 = (P)(Default\ Payout)\ +\ (1-P)(Coupon\ Payment) \end{equation}

\begin{equation} ECF_2 = (1-P){(P)\ (Default\ Payout)\ +\ (1-P)(Coupon\ Payment)} \end{equation*}

\begin{equation} ECF_3 = (1-P)^2{(P)\ (Default\ Payout)\ +\ (1-P)(Coupon\ Payment\ +\ Principal)} \end{equation*}

\begin{equation} Default\ Payout = Principal\ \ Recovery\ Rate \end{equation*}

Nếu trái phiếu vỡ nợ, khoản thanh toán vỡ nợ là tích của tỷ lệ thu hồi nợ và vốn gốc. Trong trường hợp vốn gốc bằng mệnh giá trái phiếu (ví dụ: $100), tỷ lệ thu hồi tương ứng tỷ lệ phần trăm của khoản lỗ được thu hồi từ một trái phiếu bị vỡ nợ. Tỷ lệ thu hồi khác nhau tùy theo ngành, mức độ thâm niên trong cấu trúc vốn, mức độ đòn bẩy trong cấu trúc vốn nói chung và liệu một chứng khoán cụ thể có được bảo đảm hay được thế chấp bằng cách khác hay không. Trong bài viết này, ta sẽ giả định tỷ lệ thu hồi đối với trái phiếu doanh nghiệp là 40%, một giả định phổ biến trong thực tế.

Sau khi các dòng tiền kỳ vọng được tính toán, chúng được chiết khấu trở lại giai đoạn 0 với tỷ lệ chiết khấu được điều chỉnh theo rủi ro (d) để tính giá trái phiếu. Tỷ lệ chiết khấu được điều chỉnh theo rủi ro là tỷ lệ thu được bằng cách kết hợp phần bù rủi ro dự kiến với tỷ lệ phi rủi ro trong quá trình tính toán giá trị hiện tại của một khoản đầu tư rủi ro.

\begin{equation} Risk-adjusted\ Discount\ Rate = Risk-free\ Interest\ Rate + Expected\ Risk\ Premium \end{equation}

với $Risk-adjusted\ Discount\ Rate$ là Tỷ lệ chiết khấu được điều chỉnh theo rủi ro, $Risk-free\ Interest\ Rate$ là Lãi suất phi rủi ro, và $Expected\ Risk\ Premium$ là Phần bù rủi ro dự kiến.

Ta sử dụng tỷ lệ chiết khấu (đã điều chỉnh theo rủi ro) để tính đến các cân nhắc về tính thanh khoản, thời gian đáo hạn và thuế khiến trái phiếu doanh nghiệp có mức chênh lệch quan sát được so với lợi tức của trái phiếu phi rủi ro như trái phiếu do chính phủ phát hành trong một nền kinh tế ổn định. Lợi nhuận yêu cầu tối thiểu dự kiến đối với một nhà đầu tư trái phiếu bằng tổng của những yếu tố sau:

Yếu tốMô tả
Default Risk PremiumPhần bù rủi ro mặc định bồi thường cho các nhà đầu tư có khả năng vỡ nợ doanh nghiệp.
Liquidity PremiumPhí thanh khoản bồi thường cho các nhà đầu tư khi đầu tư vào các chứng khoán kém thanh khoản hơn như trái phiếu.
Maturity PremiumPhí bảo hiểm đáo hạn bồi thường cho các nhà đầu tư về rủi ro liên quan đến trái phiếu đáo hạn trong nhiều năm tới trong tương lai vốn tiềm ẩn nhiều rủi ro hơn.
Taxation PremiumPhí bảo hiểm thuế bồi thường cho các nhà đầu tư về thu nhập chịu thuế mà trái phiếu tạo ra.
Projected InflationLạm phát dự kiến tính đến sự mất giá của tiền tệ theo thời gian.
Risk-free RateTỷ lệ phi rủi ro đề cập đến tỷ suất lợi nhuận mà nhà đầu tư có thể mong đợi đối với chứng khoán phi rủi ro.

Chúng ta bắt đầu tính toán tỷ lệ chiết khấu được điều chỉnh theo rủi ro thông qua ước tính phần bù rủi ro dự kiến (Expected Risk Premium), được tính bởi công thức sau: \begin{equation} Expected\ Risk\ Premium = (Market\ Rate\ of\ Return - Risk-free\ Rate\ of\ Return) Beta \end{equation*} trong đó $Market\ Rate\ of\ Return$ là tỷ suất lợi nhuận thị trường, $Risk-free\ Rate\ of\ Return$ là tỷ lệ hoàn vốn phi rủi ro, hệ số beta là trọng số được điều chỉnh dựa trên mức độ rủi ro đầu tư liên quan. Bằng cách lựa chọn cẩn thận hệ số beta của trái phiếu doanh nghiệp ngắn hạn đại diện cho thị trường tổng thể, chúng ta có thể tính toán phần bù rủi ro dự kiến sẽ dẫn đến tỷ lệ chiết khấu được điều chỉnh theo rủi ro kết hợp với các cân nhắc về tính thanh khoản, kỳ hạn và thuế để tạo ra xác suất vỡ nợ chính xác hơn khi sử dụng kỹ thuật định giá trái phiếu.

Để tính phần bù rủi ro kỳ vọng, trước hết chúng ta phải tính tỷ suất sinh lợi thị trường. Chúng ta có thể sử dụng mô hình định giá tài sản vốn (CAPM) để xác định tỷ lệ hoàn vốn thị trường.

$$r_m = r_f\ +(\beta*MRP)$$

với $r_m$ là tỷ lệ hoàn vốn thị trường, $r_f$ là lãi suất phi rủi ro, và $MRP$ tương ưng phần bù rủi ro thị trường.

Chứng khoán chính phủ được giả định là không có rủi ro, ít nhất là từ quan điểm tín dụng. Với giả định này, tỷ lệ thích hợp để sử dụng trong tính toán tỷ lệ hoàn vốn thị trường là chứng khoán của chính phủ có thời hạn xấp xỉ bằng tài sản được định giá và đủ thanh khoản để lợi suất không có phí bảo hiểm rủi ro thanh khoản. Cổ phiếu được giả định là có thời hạn dài, do đó, lợi suất trái phiếu chính phủ dài hạn là đại diện thích hợp cho lãi suất phi rủi ro.

Trong bước này, lợi suất trái phiếu kho bạc Hoa Kỳ kỳ hạn 10 năm sẽ được sử dụng làm lãi suất phi rủi ro và có thể tính từ dữ liệu Yahoo Finance thông qua đoạn mã dưới đây.

# Ten-Year Risk-free Rate
timespan = 100
current_date = date.today()
past_date = current_date - timedelta(days=timespan)
ten_year_risk_free_rate_df = dr.DataReader("^TNX", "yahoo", past_date, current_date)
ten_year_risk_free_rate = ten_year_risk_free_rate_df.iloc[len(ten_year_risk_free_rate_df) - 1, 5] / 100
ten_year_risk_free_rate

Ta tận dụng phần bù rủi ro thị trường hàng năm do Aswath Damodaran, giáo sư tại Trường Kinh doanh Stern thuộc Đại học New York cung cấp. Theo lý thuyết định giá tài sản, $beta$ đại diện cho loại rủi ro. Bản thân thị trường có hệ số beta là 1. Do đó, hệ số beta sẽ bằng 1 khi tính toán tỷ suất sinh lợi của thị trường.

market_risk_premium = 0.0472
stock_market_beta = 1

Từ những dữ kiện trên, ta tính được tỷ lệ hoàn vốn thị trường.

market_rate_of_return = ten_year_risk_free_rate + (stock_market_beta * market_risk_premium)
market_rate_of_return

Sau khi tính được Tỷ lệ hoàn vốn thị trường, ta tiếp tục xác định Phần bù rủi ro kỳ vọng bằng phần chênh lệch giữa Tỷ lệ hoàn vốn thị trường và lãi suất phi rủi ro nhân với hệ số beta của trái phiếu. Trong bước này, chúng ta sẽ sử dụng Lãi suất phi rủi ro một năm để Phần bù rủi ro dự kiến phù hợp với khoảng thời gian đối với tỷ lệ chiết khấu được điều chỉnh theo rủi ro. Ta thực hiện điều này bằng cách lấy Lợi tức của trái phiếu kho bạc Hoa Kỳ kỳ hạn 10 năm có tính thanh khoản rất cao và tăng nó lên lũy thừa 1/10 để chuyển đổi lợi tức thành tương đương một năm.

# Lãi suất phi rủi ro một năm
one_year_risk_free_rate = (1 + ten_year_risk_free_rate) ** (1 / 10) - 1
one_year_risk_free_rate

Cuối cùng, ta sẽ tính hệ số beta của trái phiếu doanh nghiệp. Hệ số beta của trái phiếu là độ nhạy của tỷ suất sinh lợi của trái phiếu đó đối với tỷ suất sinh lợi của chỉ số thị trường. Nó là thước đo rủi ro hệ thống, không thể đa dạng hóa. Ta có thể tính hệ số beta theo (ít nhất) một trong hai cách dưới đây.

# Quỹ Chỉ số Trái phiếu Doanh nghiệp Ngắn hạn Vanguard Cổ phiếu ETF
bond_fund_ticker = "VCSH"

Do sự khác biệt về tính thanh khoản trong trái phiếu doanh nghiệp là rất lớn, chúng ta sử dụng Cổ phiếu ETF của Quỹ chỉ số trái phiếu doanh nghiệp ngắn hạn Vanguard (VCSH) làm đại diện cho trái phiếu đáo hạn ngắn hạn. Phiên bản beta từ chỉ số này sẽ cho phép ta nhúng một số rủi ro thanh khoản và kỳ hạn vào tỷ lệ chiết khấu được điều chỉnh theo rủi ro sẽ được sử dụng để tính xác suất vỡ nợ cho trái phiếu doanh nghiệp mà ta sẽ phân tích. Điều này sẽ cho phép cô lập tốt hơn rủi ro tín dụng liên quan đến trái phiếu được chọn.

Tiếp theo, ta tính hệ số beta của quỹ trái phiếu (đối với S&P):

# Tải dữ liệu cho quỹ trái phiếu và thị trường
market_data = dr.get_data_yahoo("SPY", past_date, current_date) # thị trường
fund_data = dr.get_data_yahoo("VCSH", past_date, current_date) # quỹ trái phiếu
# Cách #1 - Phương pháp hiệp phương sai/phương sai

# Tính hiệp phương sai giữa quỹ và thị trường -- đây là tử số trong phép tính Beta
fund_market_cov = fund_data["Adj Close"].cov(market_data["Adj Close"])
print("covariance between fund and market: ", fund_market_cov)

# Tính phương sai thị trường (S&P) -- đây là mẫu số trong phép tính Beta
market_var = market_data["Adj Close"].var()
print("market variance: ", market_var)

# Tính Beta
bond_fund_beta_cv = fund_market_cov / market_var
print("bond fund beta (using covariance/variance): ", bond_fund_beta_cv)
# Cách #2 - Phương pháp tương quan

# Tính độ lệch chuẩn của thị trường bằng cách lấy căn bậc hai của phương sai, để sử dụng trong mẫu số
market_stdev = market_var**0.5
print("market standard deviation: ", market_stdev)

# Tính độ lệch chuẩn của quỹ trái phiếu, để sử dụng trong tử số

fund_stdev = fund_data["Adj Close"].std()
print("fund standard deviation: ", fund_stdev)

# Tính tương quan Pearson giữa quỹ trái phiếu và thị trường (S&P), để sử dụng trong tử số
fund_market_Pearson_corr = fund_data["Adj Close"].corr(
market_data["Adj Close"], method="pearson"
)
print("Pearson correlation between fund and market: ", fund_market_Pearson_corr)

# Tính Beta
fund_beta_corr = fund_stdev * fund_market_Pearson_corr / market_stdev
print("bond fund beta (using correlation): ", fund_beta_corr)

Lưu ý rằng .corr() ở trên có thể được sử dụng để tính bất kỳ chỉ số nào trong số ba chỉ số tương quan mà chúng ta đã thảo luận sử dụng các tham số như pearson, kendall hoặc spearman.

# Beta của trái phiếu có thể được tính bằng một trong 2 hàm trên (bond_fund_beta_cv hoặc fund_beta_corr)
bond_beta = fund_beta_corr
bond_beta

Bây giờ chúng ta có tất cả các thành phần cần thiết để tính Phần bù rủi ro dự kiến.

# Phần bù rủi ro dự kiến
expected_risk_premium = (market_rate_of_return - one_year_risk_free_rate) * bond_beta
expected_risk_premium

Chúng ta sẽ sử dụng lãi suất phi rủi ro một năm để nó phù hợp với khoảng thời gian mà chúng ta muốn đối với Tỷ lệ chiết khấu được điều chỉnh theo rủi ro và sử dụng nó để chiết khấu các dòng tiền kỳ vọng nhằm xác định xác suất vỡ nợ.

# Lãi suất phi rủi ro một năm
one_year_risk_free_rate = (1 + ten_year_risk_free_rate) ** (1 / 10) - 1
one_year_risk_free_rate

We can now combine the risk-free interest rate and the expected risk premium to obtain the risk-adjusted discount rate.

# Tỷ lệ chiết khấu được điều chỉnh theo rủi ro
risk_adjusted_discount_rate = one_year_risk_free_rate + expected_risk_premium
risk_adjusted_discount_rate

Ta đã xem xét mô hình CAPM và tìm thấy Tỷ lệ chiết khấu được điều chỉnh theo rủi ro, thông tin đầu vào cho ước tính xác suất vỡ nợ dựa trên thị trường. Để tìm được Lãi suất chiết khấu đã điều chỉnh theo rủi ro, chúng ta phải tìm Lãi suất phi rủi ro kỳ hạn một năm và Phần bù rủi ro kỳ vọng. Lãi suất phi rủi ro một năm bằng cách lấy căn bậc mười của Lãi suất phi rủi ro 10 năm trong khi Phần bù rủi ro kỳ vọng được tính bằng cách tìm Phần bù rủi ro thị trường và Hệ số beta, trong đó beta có thể được tính bằng cách sử dụng mối tương quan và độ lệch chuẩn, hoặc hiệp phương sai và phương sai thị trường, do mối quan hệ toán học giữa các biến này. Tiếp theo, chúng ta sẽ tính toán xác suất vỡ nợ do thị trường.

4. Tính xác suất vỡ nợ với SymPy

Bước cuối cùng trước khi chạy hàm xác minh tài khoản vỡ nợ của trái phiếu là xác định Tài khoản thanh toán gốc, Tỷ lệ thu hồi nợ, và xác suất vỡ nợ (kí hiệu P) và sử dụng hàm trong thư viện Python SymPy để tính.

def bonds_probability_of_default(coupon, maturity_years, bond_price, principal_payment, risk_adjusted_discount_rate):
# Công thức dưới đây dành cho Dòng tiền nửa năm
price = bond_price
prob_default_exp = 0
times = np.arange(0.5, (maturity_years - 0.5) + 1, 0.5)
semi_annual_coupon = coupon / 2

# Tính ECF
cashflows = np.array([])
for i in times[:-1]:
cashflows = np.append(cashflows, semi_annual_coupon)
cashflows = np.append(cashflows, semi_annual_coupon + principal_payment)

for i in range(len(times)):
# Đoạn mã này được sử dụng nếu chỉ còn một khoản thanh toán
if len(times) == 1:
prob_default_exp += (cashflows[i] * (1 - P) + cashflows[i] * recovery_rate * P) / np.power((1 + risk_adjusted_discount_rate), times[i])
# Đoãn mã này được sử dụng nếu còn nhiều khoản thanh toán
else:
if times[i] == 0.5:
prob_default_exp += (cashflows[i] * (1 - P) + principal_payment * recovery_rate * P) / np.power((1 + risk_adjusted_discount_rate), times[i])
else:
prob_default_exp += (np.power((1 - P), times[i - 1]) * (cashflows[i] * (1 - P) + principal_payment * recovery_rate * P)) / np.power((1 + risk_adjusted_discount_rate), times[i])

prob_default_exp = prob_default_exp - price
implied_prob_default = solve(prob_default_exp, P)
implied_prob_default = round(float(implied_prob_default[0]) * 100, 2)

if implied_prob_default < 0:
return 0.0
else:
return implied_prob_default
# Khởi tạo các biến đầu vào của hàm bonds_probability_of_default
principal_payment = 100
recovery_rate = 0.40
P = symbols("P")

Bây giờ chúng ta đã sẵn sàng để chạy hàm bond_probability_of_default để tính xác suất vỡ nợ theo thị trường cho các trái phiếu công ty đã chọn.

bond_df_result.head(1)
# Việc tính toán này có thể mất một chút thời gian nếu có nhiều khoản thanh toán bằng coupon
bond_df_result["Probability of Default %"] = bond_df_result.head(1).apply(
lambda row: bonds_probability_of_default(
row["Coupon"],
row["Maturity Years"],
row["Price"],
principal_payment,
risk_adjusted_discount_rate,
),
axis=1,
)

bond_df_result.head(1)

5. Trực quan hoá Ma trận chuyển dịch

Xếp hạng tín dụng được sử dụng cho trái phiếu do các tập đoàn và tổ chức chính phủ phát hành cũng như chứng khoán đảm bảo bằng tài sản (ABS) và chứng khoán đảm bảo bằng thế chấp (MBS). Ba cơ quan xếp hạng tín dụng lớn trên toàn cầu là Moody’s Investors Service, Standard & Poor’s, và Fitch Ratings. Mỗi bên đều cung cấp xếp hạng chất lượng tín dụng cho các tổ chức phát hành và đây là những xếp hạng theo thứ tự tập trung vào xác suất vỡ nợ. Những cơ quan này sẽ xem xét tổn thất dự kiến do vỡ nợ (LGD) bằng phương pháp ghi chú, đây là một sự điều chỉnh đối với xếp hạng của tổ chức phát hành để phản ánh mức độ ưu tiên của yêu cầu đối với các vấn đề nợ cụ thể của tổ chức phát hành đó. Xếp hạng này thường dành cho khoản nợ không có bảo đảm cấp cao. Xếp hạng nợ thứ cấp sau đó được điều chỉnh, hay còn gọi là "được ghi chú", bằng cách hạ thấp nó xuống một hoặc hai cấp—ví dụ: từ A+ xuống A hoặc xa hơn nữa xuống A–. Việc bao gồm tổn thất do vỡ nợ bên cạnh xác suất vỡ nợ giải thích tại sao chúng được gọi là "xếp hạng tín dụng" chứ không chỉ là "xếp hạng vỡ nợ". Các cơ quan xếp hạng báo cáo ma trận chuyển đổi dựa trên dữ liệu lịch sử của họ và sử dụng ma trận chuyển đổi để cho thấy khả năng xếp hạng thay đổi (hoặc giữ nguyên) trong thời gian một năm.

Chúng ta có thể xác minh tính chính xác của xác suất vỡ nợ do thị trường bằng ma trận chuyển đổi của các cơ quan xếp hạng. Cụ thể, bài viết này sử dụng Tỷ lệ chuyển đổi trung bình trong một năm của Standard & Poor cho các tập đoàn toàn cầu sử dụng dữ liệu lịch sử từ năm 1981-2019 để xác minh xác suất vỡ nợ do thị trường đã tính toán trước đó thông qua đoạn mã bên dưới đây.

def prob_default_term_structure(df):

fig, (ax1, ax2) = plt.subplots(1, 2, clear=True)
fig.subplots_adjust(wspace=0.5)
Mgroups = df.groupby("Moody's®")
ax1.clear()
ax1.margins(0.5)
ax1.set_xlabel("Days Until Maturity")
ax1.set_ylabel("Probability of Default %")
ax1.set_title("Moody's® Ratings")
for name, group in Mgroups:
ax1.plot(
group["Maturity"],
group["Probability of Default %"],
marker="o",
linestyle="",
ms=12,
label=name,
)
ax1.legend(numpoints=1, loc="upper left")

SPgroups = df.groupby("S&P")
ax2.clear()
ax2.margins(0.5)
ax2.set_xlabel("Days Until Maturity")
ax2.set_ylabel("Probability of Default %")
ax2.set_title("S&P Ratings")

for name, group in SPgroups:
ax2.plot(
group["Maturity"],
group["Probability of Default %"],
marker="o",
linestyle="",
ms=12,
label=name,
)
ax2.legend(numpoints=1, loc="upper left")
plt
prob_default_term_structure(bond_df_result)
tgt_website = r"https://www.spglobal.com/ratings/en/research/articles/200429-default-transition-and-recovery-2019-annual-global-corporate-default-and-rating-transition-study-11444862"
def get_transition_matrix(tgt_website):
df_list = pd.read_html(tgt_website)
matrix_result_df = df_list[22]
return matrix_result_df

transition_matrix_df = get_transition_matrix(tgt_website)
sp_clean_result_df = pd.DataFrame(transition_matrix_df.iloc[:34, :19].dropna(axis=0))
sp_clean_result_df

Ma trận chuyển đổi năm 2019 của Standard & Poor ở trên cho thấy xác suất của một xếp hạng cụ thể chuyển sang xếp hạng khác trong suốt năm tiếp theo. Một tổ chức phát hành được xếp hạng A có 78.88% xác suất duy trì ở mức đó, 0.03% xác suất chuyển lên hạng AAA; xác suất tăng lên AA là 0.22%; xác suất chuyển xuống BBB là 0.86%; 0.10% xuống BB; 0.02% đối với B, 0.01% đối với CCC, CC hoặc C; và 0.05% cho D, ở mức mặc định.

Selenium có thể được tận dụng để truy xuất xếp hạng tín dụng của Standard & Poor từ đó ta có thể xếp hạng tín dụng của trái phiếu doanh nghiệp và xác định xác suất chuyển đổi xếp hạng cụ thể sang D (mặc định) trong năm tới theo ma trận chuyển đổi của Standard & Poor's 2019.

# Lấy xác suất vỡ nợ mỗi xếp hạng

sp_rating_list = [ "AAA", "AA+", "AA", "AA-", "A+", "A", "A-", "BBB+", "BBB", "BBB-", "BB+", "BB", "BB-", "B+", "B", "B-"]

ccc_list = ["CCC+", "CCC", "CCC-", "CC+", "CC", "CC-", "C+", "C", "C-"]

sp_rating = None

for i in sp_rating_list:
if bond_df_result["S&P"].iloc[0] == i:
sp_rating = bond_df_result["S&P"].iloc[0]

if sp_rating is None:
for i in ccc_list:
if bond_df_result["S&P"].iloc[0] == i:
sp_rating = "CCC/C"

sp_transition_dp = 0

for i in range(33):
if transition_matrix_df.loc[i][0] == sp_rating:
sp_transition_dp += float(sp_clean_result_df.loc[i][18])

sp_transition_dp

Có vẻ như xác suất vỡ nợ do thị trường ta tính toán cho trái phiếu doanh nghiệp có kỳ hạn gần nhất gần bằng với xác suất vỡ nợ được xác định từ dữ liệu lịch sử trong ma trận chuyển đổi năm 2019 của Standard & Poor.

# So sánh kỳ hạn gần nhất Xác suất vỡ nợ theo thị trường với xác suất vỡ nợ lịch sử trong ma trận chuyển đổi năm 2019 của Standard & Poor
print("Market-implied probability of default = %s" % (bond_df_result["Probability of Default %"].iloc[0]))
print("Standard & Poor’s probability of default = %s" % (sp_transition_dp))

Từ ví dụ trên, các kỹ thuật định giá trái phiếu sử dụng Tỷ lệ chiết khấu được điều chỉnh theo rủi ro thực hiện khá tốt việc xác định rủi ro vỡ nợ của công ty và có thể đủ để xếp hạng các công ty theo mức độ tín nhiệm. Tuy nhiên, cần lưu ý một số giả định ta đặt ra và thực tế ứng dụng tuỳ trong doanh nghiệp.

Yếu tốGiả địnhThực tế
Đường cong lợi suất trái phiếu chính phủBằng phẳngCó thể dốc lên hoặc dốc xuống
Tỷ lệ khôi phục40%Có thể thử nghiệm với 30% hoặc 60%
Quá trình hồi vốnTức thờiThời gian trì hoãn kéo dài có thể xảy ra giữa sự kiện vỡ nợ và việc thu hồi tiền mặt cuối cùng
Xác suất vỡ nợ hàng nămNhư nhauKhông nhất thiết phải đúng như vậy

Hi vọng bài viết này sẽ giúp các bạn nắm được những kiến thức tài chính cơ bản cũng như cơ chế được sử dụng để dự đoán xác suất vỡ nợ trước khi có Học máy. Từ đó, chúng ta có thể so sánh cùng một bài toán nhưng khi tiếp cần với phương pháp Học máy thì có những ưu và nhược điểm gì ở các phần sau.

Chúc các bạn học tập vui vẻ!

Tham khảo

Copyright (c) 2020 HDVI. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Lưu ý: Thông báo giấy phép MIT ở trên được sao chép ở đây để tuân thủ các yêu cầu của nó, nhưng nó không áp dụng cho nội dung trong các ghi chú bài học này.