Ценообразование плавающей облигации в Quantlib с использованием Python
Я пытаюсь оценить очень простую облигацию с плавающей ставкой в python, используя оболочку Quantlib (v1.2) SWIG. Я изменил пример, включенный в документацию.
Моя облигация имеет 4-летний срок погашения. У libor установлено значение 10%, а спред облигации равен 0. Мой вопрос: если я делаю дисконтирование по ставке 10%, почему PV не равен 100? Я получаю значение 99,54.
Спасибо!
from QuantLib import *
frequency_enum, settle_date = 4, Date(5, 1, 2010)
maturity_date = Date(5, 1, 2014)
face_amount = 100.0
settlement_days = 0
fixing_days = 0
calendar = NullCalendar()
settle_date = calendar.adjust(settle_date)
todays_date = calendar.advance(settle_date, -fixing_days, Days)
Settings.instance().evaluationDate = todays_date
rate = 10.0 / 100.0
flat_forward = FlatForward(settle_date,
rate,
Thirty360(),
Compounded,
frequency_enum)
discounting_term_structure = RelinkableYieldTermStructureHandle(flat_forward)
index_term_structure = RelinkableYieldTermStructureHandle(flat_forward)
index = USDLibor(Period(3, Months), index_term_structure)
schedule = Schedule(settle_date,
maturity_date, Period(frequency_enum),
NullCalendar(),
Unadjusted, Unadjusted,
DateGeneration.Forward, False)
floating_bond = FloatingRateBond(settlement_days,
face_amount,
schedule,
index,
Thirty360(),
Unadjusted,
fixing_days,
[], # Gearings
[0], # Spreads
[], # Caps
[], # Floors
False, # Fixing in arrears
face_amount,
settle_date)
bond_engine = DiscountingBondEngine(discounting_term_structure)
floating_bond.setPricingEngine(bond_engine)
# coupon pricers
pricer = BlackIborCouponPricer()
volatility = 0.0
vol = ConstantOptionletVolatility(settlement_days,
calendar,
Unadjusted,
volatility,
Thirty360())
pricer.setCapletVolatility(OptionletVolatilityStructureHandle(vol))
setCouponPricer(floating_bond.cashflows(), pricer)
print floating_bond.NPV(), floating_bond.cleanPrice(), floating_bond.dirtyPrice()
1 ответ
Ставки купонов устанавливаются с помощью счетчика дней USDLibor (то есть Actual/360), который не соответствует предоставленному счетчику дней платежей (30/360). Вы можете увидеть это, проверив купоны:
cfs = floating_bond.cashflows()
coupons = [ as_coupon(c) for c in cfs[:-1] ] # the last one is the redemption
print [ (c.rate(), c.accrualPeriod()) for c in coupons ]
что дает вам T = 0,25 для всех купонов, но ставки ниже 10%.
Чтобы получить желаемую цену, вы должны сопоставить ставку и период начисления. Одним из способов является передача Actual360() в качестве счетчика дней облигации, который дает цену 100,002 на моей машине (я не исследовал дальше, но это расхождение может быть связано с конечной датой фиксации LIBOR, которая определяется с помощью календарь USD и может не совпадать точно с концом купона). Другой способ - создать пользовательский индекс LIBOR с внутренним счетчиком дней 30/360; Я не пробовал это сам, но вы можете сделать это, создав соответствующий экземпляр класса IborIndex.