OpenSourceRisk / ORE-SWIG

Other
49 stars 46 forks source link

CrossCurrency Pricing with coupon data. #6

Open jmelo11 opened 4 years ago

jmelo11 commented 4 years ago

Hi to all,

I'm trying to price a LIBOR6M/CLPCamara XCCY swap with coupon information. For this, I'm building each IborCoupon (for the libor leg) and OvernightIndexedCoupon/IborCoupon (for the CLPCamara leg) and then building two legs and passing them to de CrossCurrencySwap constructor in python (plus their currencies). Unfortunatelly, i constatly get "Wrong number of in currency leg NPVs returned by engine" when using CrossCcySwapEngine and trying different conbinations. Also I'm unable to retrieve coupon cashflows.

I'm puzzled by the problem since there are more pricing engines that might fit but documentation is scarce and the error does not provide enought information to deduct the problem.

Any help is highly appreciated.

Here is an script for reproducibility:

import QuantExt as qe

today = qe.Date(8, 5, 2020)
qe.Settings.instance().evaluationDate = today

#curves
libor6m = qe.FlatForward(0, qe.UnitedStates(), 0.05, qe.Actual360())
icp = qe.FlatForward(0, qe.Chile(), 0.05, qe.Actual360()) #Chile() might not be exported to Quantext-SWIG
fed = qe.FlatForward(0, qe.UnitedStates(), 0.05, qe.Actual360())
usd_col = qe.FlatForward(0, qe.Chile(), 0.05, qe.Actual360())

#handles
libor_handle = qe.RelinkableYieldTermStructureHandle(libor6m)
icp_handle = qe.RelinkableYieldTermStructureHandle(icp)
fed_handle = qe.RelinkableYieldTermStructureHandle(fed)
usd_col_handle = qe.RelinkableYieldTermStructureHandle(usd_col)

#index
libor6m_index = qe.USDLibor(qe.Period(6, qe.Months), libor_handle)
icp_index = qe.CLPCamara(icp_handle)
fed_index = qe.OvernightIndex('fed', 0, qe.USDCurrency(), qe.UnitedStates(), qe.Actual360(), fed_handle)

#swap
years = 5
end_dates = [today+i*180 for i in range(1,5*2 +1 )]
start_dates = [today+i*180 for i in range(5*2)]
notional1 = 10000
notional2 = notional1*800
spread = 0.35/100
fx = qe.QuoteHandle(qe.SimpleQuote(800))

libor_coupons = []
icp_coupons = []
for start, end in zip(start_dates,end_dates):

    c = qe.IborCoupon(paymentDate=end, nominal=notional1, startDate=start,
                                           endDate=end, fixingDays=0,
                                           index=libor6m_index, gearing=1,
                                           spread=spread)

    libor_coupons.append(c)
    #c  = ql.OvernightIndexedCoupon(end, notional2, start, end, icp_index)
    c = qe.IborCoupon(paymentDate=end, nominal=notional2, startDate=start,
                      endDate=end, fixingDays=0,
                      index=icp_index, gearing=1,
                      spread=0)
    #c = qe.FixedRateCoupon(paymentDate=end, nominal=notional2, rate=1.5/100, dayCounter=qe.Actual360(), startDate=start,endDate=end)
    icp_coupons.append(c)

leg1 = qe.Leg(libor_coupons)
leg2 = qe.Leg(icp_coupons)

swap = qe.CrossCcySwap(leg1, qe.USDCurrency(), leg2, qe.CLPCurrency())

#pricer setting
black_ibor_pricer = qe.BlackIborCouponPricer()
qe.setCouponPricer(swap.leg(0), black_ibor_pricer)
qe.setCouponPricer(swap.leg(1), black_ibor_pricer)

#Does not work
#engine = qe.CrossCcySwapEngine(ql.CLPCurrency(), icp_handle, ql.USDCurrency(),fed_handle, fx)
#engine = qe.OvernightIndexedCrossCcyBasisSwapEngine(icp_handle, ql.CLPCurrency(),fed_handle, ql.USDCurrency(), fx)
#swap.setPricingEngine(engine)
#print(swap.NPV())

#Works
schedule1 = qe.Schedule(end_dates)
schedule2 = qe.Schedule(end_dates)
swap = qe.CrossCcyBasisSwap(payNominal=notional1, payCurrency=qe.USDCurrency(), paySchedule=schedule1, payIndex=libor6m_index, paySpread=spread,
                            recNominal=notional2, recCurrency=qe.CLPCurrency(), recSchedule=schedule2, recIndex=icp_index,recSpread=0)

engine = qe.CrossCcySwapEngine(qe.CLPCurrency(), icp_handle, qe.USDCurrency(),fed_handle, fx)
swap.setPricingEngine(engine)
print(swap.NPV())

#diferent payment schedule per leg
end_dates = [today+i*90 for i in range(1,5*4 +1 )]
schedule2 = qe.Schedule(end_dates)
swap = qe.CrossCcyBasisSwap(payNominal=notional1, payCurrency=qe.USDCurrency(), paySchedule=schedule1, payIndex=libor6m_index, paySpread=spread,
                            recNominal=notional2, recCurrency=qe.CLPCurrency(), recSchedule=schedule2, recIndex=icp_index,recSpread=0)

engine = qe.CrossCcySwapEngine(qe.CLPCurrency(), icp_handle, qe.USDCurrency(),fed_handle, fx)
swap.setPricingEngine(engine)
print(swap.NPV())
jmelo11 commented 4 years ago

Realized that the testcase for the crosscurrency leg constructor, in the python folder, is also not working. I guess is something known. Is there any guidance on how could be fixed?

rolandlichters commented 2 years ago

We have brushed up the test cases recently, for the upcoming release. They should be all working now.