# 不同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`