債券

Python中的Macaulay或修改的持續時間

  • February 7, 2021

我想問一下,pyhton 中是否有任何函式可以計算 macaulay 或修改後的持續時間,當到期時間不是整數時,例如到期時間是 1514 天,並且您需要 macaulay 或修改後的持續時間的精確答案。

也許 somoene 可以分享他們的程式碼。

謝謝

python 中沒有內部函式來獲取持續時間(例如 excel),儘管程式並不難。您基本上需要天數、費率和折扣係數。

正如 noob2 所提到的,可以使用 QuantLib 來獲得它,儘管在您熟悉建構所需的對象之前有一個學習曲線。

這是一個簡單的範例,可以幫助您入門:

import QuantLib as ql

days = 1514
coupon = 0.028
yld = 0.000054

start = ql.Date().todaysDate()
maturity = start + ql.Period(days, ql.Days)

bond = ql.FixedRateBond(2, ql.TARGET(), 1000, start, maturity, ql.Period('1Y'), [coupon], ql.ActualActual())
rate = ql.InterestRate(yld, ql.ActualActual(), ql.Compounded, ql.Annual)
simple_duration = ql.BondFunctions.duration(bond, rate, ql.Duration.Simple)
mod_duration = ql.BondFunctions.duration(bond, rate, ql.Duration.Modified)
mac_duration = ql.BondFunctions.duration(bond, rate, ql.Duration.Macaulay)
print(mac_duration, mod_duration, )

這將輸出: 3.9742030045989956 3.9739884092248974

或者你可以根據你想要的準確度,定義你自己的 python 函式:

coupon = 0.028
yld = 0.000054

def durations(c, y, m, n):
   macaulay_duration = ((1+y) / (m*y)) - ( (1 + y + n*(c-y)) / ((m*c* ((1+y)**n - 1)) + m*y) )
   modified_duration = macaulay_duration / (1 + y)
   return macaulay_duration, modified_duration

print( durations(coupon, yld, 1, days/365) )

這將輸出:(3.98414223634245, 3.983927104278819)

第1部分

這不完全是您所要求的,而是到達那裡的中間步驟。很容易組合一個簡單的函式來計算一組現金流的麥考利持續時間,將 pv 率、現金流量和周期作為輸入——不是日期,只是周期,即周期 1、2、3 , ETC。

下面我有一個債券的玩具範例,它每年支付兩次 6%(即每 6 個月支付 3%)並且按面值報價。

如果您以年為單位,即第一學期為 0.5 期,則必須將費率年化,使 6% 變為 6.09%。如果您以學期為單位通過週期,因此第一學期是周期 1,則比率必須為 3%,並且最終結果必須除以 2,因為我們希望將持續時間作為以年為單位的時間加​​權平均度量。

def mac_duration(periods, cash, pv_rate):
   
   periods= np.float64(periods)
   cash = np.float64(cash)
   pv = np.zeros(cash.size)
  
   for i in range(cash.size):
       pv[i] = cash[i] / ( 1 + pv_rate)** periods[i]
   sum_pv = np.sum(pv)
  
   return np.dot(pv/sum_pv, periods)

def mod_duration(periods, cash, my_rate):
   return mac_duration(periods, cash, my_rate) / (1 + my_rate)    
   
cash = [30,30,30,30,30,1030]
rate = 6e-2
rate_sem = rate/2
rate_annual = (1 + rate_sem)**2 - 1
periods_sem = np.arange(1,7)
periods_years = periods_sem / 2
  
mac_dur_ann = mac_duration( periods_years, cash, rate_annual)
mac_dur_sem = mac_duration( periods_sem, cash, rate_sem) / 2

第2部分

現在您只需要一個函式來計算日期之間的天數,將其轉換為年份分數,並將結果傳遞給上面的函式。

您會注意到,由於我們使用的是 act/365,所以結果略有不同,因為付款不再恰好在半年發生(7 月 1 日是 1 月 1 日之後的 181 天,並且 181 != 365/2)。如果您在一年只支付一次的債券上計算它(參見 cash2),只要在閏年沒有計算,您就會得到相同的結果。

此外,您現在需要指定從何時開始計算天數。對於另一個函式,這隱含在周期中,即周期 1 是從起點算起的 1 個週期。

def mac_duration_dates(dates, cash, pv_rate, day_0, day_count = 365):
   
   yearfrac = ([ (d - day_0).days / day_count for d in dates])
   out = mac_duration( yearfrac, cash, pv_rate )
   return out

day_0 = pd.to_datetime(date(2013,1,1))
df = pd.DataFrame() 
df['month'] = np.arange(6,42,6)
df['dates'] = df.apply(lambda x: day_0 + pd.DateOffset(months = x['month']), axis = 1)
mac_dur_with_dates = mac_duration_dates(df['dates'], cash, rate_annual, day_0 = day_0, day_count = 365)


cash2 = [0,60,0,60,0,1060]
mac_dur2 = mac_duration( periods_years, cash2, 6e-2)
mac_dur_with_dates2 = mac_duration_dates(df['dates'], cash2, 6e-2, day_0 = day_0, day_count = 365)
print( np.isclose(mac_dur_with_dates2, mac_dur2))

引用自:https://quant.stackexchange.com/questions/53290