---
# System prepended metadata

title: 不同day count下計算債券價格
tags: [Python, 期貨與選擇權, 債券, 財務工程]

---

# 不同day count下計算債券價格


:::info
Calculate the dirty and the clean price for a bond under actual/actual and 30/360 day count conversion.
Input: Bond maturity date, settlement date, bond yield, and the coupon rate.
The bond is assumed to pay coupons 
:::
### 目標
計算actual/actual和30/360的day count計算方法下，債券的淨價和全價。
輸入: 債券到期日、結算日、債券收益率YTM和票面利率coupon rate。
假設債券半年付息一次。

## 程式碼 (by python)
### 輸入資料
將 settlement date 、 maturity date 、 coupon rate 以及 bond yield (YTM) 輸入，並且透過 flag 輸入 1 或 2 來判斷 day count 的種類。
並且

```pyhton=
import math
import datetime

settlement_date = input("Please input settlement date. \n")
settlement_date = datetime.datetime.strptime(settlement_date,'%Y%m%d').date()

maturity_date = input("Please input maturity date.\n")
maturity_date = datetime.datetime.strptime(maturity_date,'%Y%m%d').date()

coupon_rate = float(input("Please input coupon_rate. \n"))
bond_yield = float(input("Please input bond yield(YTM). \n"))
flag = input("Please select day count. Input \"1\" ==> actual/actual, input \"2\" ==> 30/360. ")
face_value = 100

m_date = datetime.date(settlement_date.year, maturity_date.month, maturity_date.day)  #將到期日的月分和日期移到交割日的那一年來比較
#為了找出在settlement date前後的coupon date來算出 coupon periods 和 days in periods
```
### 使用actual/actual
```python=
if flag == "1":   #actual/actual
  if m_date < settlement_date:  # m_date 比 settlement_date 早
    if settlement_date.month - m_date.month > 6:  # m_date 比 settlement_date早了超過6個月的話
      if maturity_date.month <= 6:
        m_date = datetime.date(settlement_date.year, m_date.month+6, m_date.day)
      else:
        n = maturity_date.month - 6
        m_date = datetime.date(settlement_date.year+1, m_date.month+n, m_date.day)

    interval = settlement_date - m_date  
    time_before_settlement = interval.days  #算出settlement_date和上一個coupon_date距離有幾天

    if maturity_date.month <= 6:
      coupon_date = datetime.date(settlement_date.year, m_date.month+6, m_date.day)
    else:
      n = maturity_date.month - 6
      coupon_date = datetime.date(settlement_date.year+1, m_date.month+n, m_date.day)
    previous_coupon_date = datetime.date(m_date.year, m_date.month, m_date.day)

    periods = coupon_date - settlement_date
    time_after_settlement = periods.days    #算出settlement_date和下一個coupon_date距離有幾天
    w = time_after_settlement/(time_before_settlement + time_after_settlement)  

  elif m_date > settlement_date:  # settlement_date 比 m_date 早
    if m_date - settlement_date > 6:  # settlement_date 比 m_date 早了超過6個月
      if maturity_date.month <= 6:
        m_date = datetime.date(settlement_date.year-1, m_date.month+6, m_date.day)
      else:
        m_date = datetime.date(settlement_date.year, m_date.month-6, m_date.day)

    interval = m_date - settlement_date 
    time_after_settlement = interval.days   #算出settlement_date和下一個coupon_date距離有幾天
    coupon_date = datetime.date(m_date.year, m_date.month, m_date.day)
    if maturity_date.month <= 6:
      previous_coupon_date = datetime.date(settlement_date.year-1, m_date.month+6, m_date.day)
    else:
      previous_coupon_date = datetime.date(settlement_date.year, m_date.month-6, m_date.day)
    
    periods = settlement_date - previous_coupon_date
    time_before_settlement = periods.days   #算出settlement_date和上一個coupon_date距離有幾天
    w = time_after_settlement/(time_before_settlement + time_after_settlement)  
  else:
    w = 1 #交割日的和coupon date 一樣
```
### 使用30/360
```python=
elif flag == "2":   # 30/360
  if m_date < settlement_date:  # m_date 比 settlement_date 早
    if settlement_date.month - m_date.month > 6:  # m_date 比 settlement_date早了超過6個月的話
      if maturity_date.month <= 6:
        m_date = datetime.date(settlement_date.year, m_date.month+6, m_date.day)
      else:
        n = maturity_date.month - 6
        m_date = datetime.date(settlement_date.year+1, m_date.month+n, m_date.day)

    time_before_settlement = (settlement_date.year - m_date.year) * 360 + \
                (settlement_date.month - m_date.month) * 30 + \
                (settlement_date.day - m_date.day)  #算出settlement_date和上一個coupon_date距離有幾天
    if maturity_date.month <= 6:
      coupon_date = datetime.date(settlement_date.year, m_date.month+6, m_date.day)
    else:
      n = maturity_date.month - 6
      coupon_date = datetime.date(settlement_date.year+1, m_date.month+n, m_date.day)
    previous_coupon_date = datetime.date(m_date.year, m_date.month, m_date.day)

    time_after_settlement = (coupon_date.year - settlement_date.year) * 360 + \
                (coupon_date.month - settlement_date.month) * 30 + \
                (coupon_date.day - settlement_date.day)
                
    w = time_after_settlement/(time_before_settlement + time_after_settlement)  

  elif m_date > settlement_date:  # settlement_date 比 m_date 早
    if m_date - settlement_date > 6:  # settlement_date 比 m_date 早了超過6個月
      if maturity_date.month <= 6:
        m_date = datetime.date(settlement_date.year-1, m_date.month+6, m_date.day)
      else:
        m_date = datetime.date(settlement_date.year, m_date.month-6, m_date.day)
        
    time_after_settlement = (m_date.year - settlement_date.year) * 360 + \
          (m_date.month - settlement_date.month) * 30 + \
          (m_date.day - settlement_date.day)    #算出settlement_date和下一個coupon_date距離有幾天
    coupon_date = datetime.date(m_date.year, m_date.month, m_date.day)
    if maturity_date.month <= 6:
      previous_coupon_date = datetime.date(settlement_date.year-1, m_date.month+6, m_date.day)
    else:
      previous_coupon_date = datetime.date(settlement_date.year, m_date.month-6, m_date.day)
    
    periods = settlement_date - previous_coupon_date

    time_before_settlement = (settlement_date.year - previous_coupon_date.year) * 360 + \
          (settlement_date.month - previous_coupon_date.month) * 30 + \
          (settlement_date.day - previous_coupon_date.day)
          #算出settlement_date和上一個coupon_date距離有幾天
    w = time_after_settlement/(time_before_settlement + time_after_settlement)  

  else:
    w = 1    #解決日期相等時的狀況
else:
  print("Please input 1 or 2 to select day count")    #防呆，要求輸入必須為1or2
```
### 計算期數(完整經過的期數)
```python=
years = maturity_date.year - settlement_date.year
if maturity_date.month > 6:
  times = years * 2 -1
else:
  times = years * 2 #半年配息一次
coupon = (face_value * coupon_rate)/2 
dirty_price = 0
clean_price = 0
for i in range(times):
  dirty_price += coupon * math.pow(1+bond_yield/2,-w-i)
dirty_price += 100 * math.pow(1+bond_yield/2,-w-i)

accured_interest = coupon * (1-w)
clean_price = dirty_price - accured_interest

print("dirty_price = ",dirty_price)
print("clean_price = ",clean_price)
print("accured_interest = ",accured_interest)

```
### 執行畫面
![](https://i.imgur.com/0v5Y0wW.png)
###### 以actual/actual為例

首先會輸入 settlement date，日期中間不需要空格，接著輸入 maturity date，還有 coupon rate 和 bond yield，最後選擇 day count 的種類，輸入 1代表使用 actual/actual，輸入 2 代表使用 30/360，就能得到 dirty price 和clean price，還有 accrued interest 的值。


---


###### tags: `財務工程`、`期貨與選擇權`、`債券`、`Python`
