量化交易策略

如何使用 quantlib 計算拉丁美洲掉期 CLP-TNA(智利)的 NPV?

  • June 25, 2021

我正在嘗試評估拉丁美洲的掉期交易。但 CLP-TNA 估值與實際估值相差甚遠。請建議,我在以下計算 NPV 的方法中缺少什麼。

# construct discount curve and libor curve
risk_free_rate = 0.01
libor_rate = 0.02
day_count = ql.Actual360()

discount_curve = ql.YieldTermStructureHandle(
    ql.FlatForward(calculation_date, risk_free_rate, day_count)
)

 libor_curve = ql.YieldTermStructureHandle(
 ql.FlatForward(calculation_date, libor_rate, day_count)
)
# CLP index
CLP_index = ql.OvernightIndex('CLP', 0, ql.CLPCurrency(), ql.WeekendsOnly(), ql.Actual360())

calendar = ql.WeekendsOnly()
settle_date = calendar.advance(calculation_date, 5, ql.Days)
maturity_date = calendar.advance(settle_date, 10, ql.Years)


 fixed_schedule = ql.Schedule(settle_date, maturity_date, 
                    fixed_leg_tenor, calendar,
                    ql.ModifiedFollowing, ql.ModifiedFollowing,
                    ql.DateGeneration.Forward, False)

 float_schedule = ql.Schedule (settle_date, maturity_date, 
                     float_leg_tenor, calendar,
                     ql.ModifiedFollowing, ql.ModifiedFollowing,
                     ql.DateGeneration.Forward, False)

 notional = 10000000
fixed_rate = 0.025
fixed_leg_daycount = ql.Actual360()
float_spread = 0.004
float_leg_daycount = ql.Actual360()

ir_swap = ql.VanillaSwap(ql.VanillaSwap.Payer, notional, fixed_schedule, 
      fixed_rate, fixed_leg_daycount, float_schedule,
      libor3M_index, float_spread, float_leg_daycount )

swap_engine = ql.DiscountingSwapEngine(discount_curve)
ir_swap.setPricingEngine(swap_engine)

這是一個可能為您指明正確方向的範例。正如 Luigi 所說的那樣,如果你只是使用平坦的曲線,你就不能真正期望得到可比較的值。

因此,第一步是建立一條與彭博可比的曲線。我真的沒有任何 CLP 購買經驗,查看 BBG 上的資訊,看起來這些掉期在 1800 萬之前是零息票,然後支付半價。

import QuantLib as ql
today = ql.Date(25,6,2021)
calendar = ql.WeekendsOnly()
ql.Settings.instance().evaluationDate = today
spot = calendar.advance(today, 2, ql.Days)
dayCount = ql.Actual360()

cop_ois_quotes = [
   ('3M', 0.780),
   ('6M', 1.140),
   ('9M', 1.435),
   ('12M', 1.770),
   ('18M', 2.145),
   ('2Y',  2.430),
   ('3Y',  2.745),
   ('4Y',  3.01),
   ('5Y',  3.28),
   ('6Y',  3.53),
   ('7Y',  3.715),
   ('8Y',  3.835),
   ('9Y',  3.93),
   ('10Y', 4.055),
   ('15Y', 4.365),
   ('20Y', 4.465),
]

helpers = []
clp_ois_yts = ql.RelinkableYieldTermStructureHandle()

index = ql.OvernightIndex('CLICP', 0, ql.CLPCurrency(), ql.WeekendsOnly(), dayCount, clp_ois_yts)
for tenor, value in cop_ois_quotes:
   value /= 100
   quote = ql.QuoteHandle(ql.SimpleQuote(value))
   period = ql.Period(tenor)
   paymentFrequency = ql.Semiannual if period.units() > 2 else ql.Once
   helper = ql.OISRateHelper(2, period, quote, index, paymentFrequency=paymentFrequency)
   helpers.append(helper)
clp_ois_crv = ql.PiecewiseLogLinearDiscount(spot, helpers, ql.ActualActual())
clp_ois_crv.enableExtrapolation()
clp_ois_yts.linkTo(clp_ois_crv)

然後,您可以通過為一些掉期定價來測試您的曲線。在這裡,我為輸入工具定價,因此預計會產生相同的結果,但您可以使用其他日期。

swapType = ql.OvernightIndexedSwap.Payer
nominal = 100

engine = ql.DiscountingSwapEngine(clp_ois_yts)

for tenor, value in cop_ois_quotes:
   value /= 100
   maturity = calendar.advance(spot, ql.Period(tenor))
   freq = '18M' if ql.Period(tenor).units() == 2 else '6M'
   schedule = ql.MakeSchedule(spot, maturity, ql.Period(freq), calendar=calendar)
   ois_swap = ql.OvernightIndexedSwap(swapType, nominal, schedule, 0.0, dayCount, index)
   ois_swap.setPricingEngine(engine)
   print(f"{tenor}: {ois_swap.fairRate()*100:.4f}, {value*100:.4f}")

3M: 0.7800, 0.7800

6M: 1.1400, 1.1400

9M: 1.4350, 1.4350

12M:

1.7700, 1.7700 18M: 2.1450, 2.1450

2Y: 2.4300, 2.4300

3Y: 2.7479, 2.7450

4Y: 3.0100, 3.0100

5Y: 3.2800, 3.2800

6Y: 3.5300, 3.5300

7Y:3.7150、3.7150

8Y:3.8350、3.8350

9Y:3.9312、3.9300

10Y:4.0550、4.0550

15Y:4.3650、4.3650

20Y:4.4651、4.4650

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