Getting Caplet and Floorlet Prices from QuantLib CapFloor Instruments
Summary
The document asks how to report the value of each caplet or floorlet inside a QuantLib cap or floor, including intrinsic and time value at each fixing date. The example code prices the whole instrument, then attempts to reconstruct per-period values from leg cashflows. Its author notes that the cashflow treatment does not account correctly for the accrual tenor and asks whether the pricing engine exposes the needed breakdown.
The answer points to methods on QuantLib's CapFloor class: optionletsPrice() returns present values for individual optionlets, while optionletsAtmForward() and optionletsDiscountFactor() provide related per-optionlet data. This supplies a route to inspect component values without treating the underlying floating-leg cashflows as optionlet prices. The reply does not show a full intrinsic-versus-time-value calculation or validate the example's dates and conventions, so those details require separate care.
Key ideas
- A cap or floor's floating-leg cashflows are not themselves the present values of its individual optionlets.
- QuantLib's optionletsPrice() method returns present values for individual caplets or floorlets.
- The instrument also exposes optionlet at-the-money forward rates and discount factors.
- The answer identifies useful component data but does not provide a complete method for splitting each optionlet into intrinsic and time value.
Tags
Full text
# QuantLib Python: How to print each caplet/floorlet value, intrinsic value and time value at each fixing date?
# QuantLib Python: How to print each caplet/floorlet value, intrinsic value and time value at each fixing date?
I have the following code to price a floor (can also be used for cap), and have been computing the payoff myself, but I think QL can already do this. Since the cashflows I print out aren't correct as they don't take the tenor (here, I'm only entitled to 6 months of the notional but the cashflows assume 1 year) into account, so I want to get the NPV, intrinsic and time value from each caplet/floorlet if possible using QL functions from the cap pricing engine. I have searched and can't see a way to do this.
```
...
ibor_leg = ql.IborLeg([Notional], schedule, ibor_index)
#use ql.Floor for floor
if Instrument == 'Cap':
capfloor = ql.Cap(ibor_leg, [strike])
elif Instrument == 'Floor':
capfloor = ql.Floor(ibor_leg, [strike])
vols = ql.QuoteHandle(ql.SimpleQuote(volatility))
engine = ql.BlackCapFloorEngine(ts_handle, vols)
capfloor.setPricingEngine(engine)
print("Price:", "${:,.2f}".format(capfloor.NPV()))
#print table of cashflows to check against benchmark
# Compute the cashflows and discounted cashflows for each caplet
cashflows = capfloor.floatingLeg()
intrinsic_value = capfloor.NPV()
discountFactors = [term_structure.discount(cashflow.date()) for cashflow in cashflows]
discountedCashflows = [cashflow.amount() * discountFactor for cashflow,
discountFactor in zip(cashflows,
discountFactors)]
def Payoff(option_Type,Notional,F,K,year_frac,discount_rate):
if option_Type=="Cap":
return max(0,F-K)*Notional*year_frac*discount_rate
elif option_Type == "Floor":
return max(0,K-F)*Notional*year_frac*discount_rate
# Construct the table data
# Print out the NPV, intrinsic and time value for each caplet/floorlet at each fixing date
tableData = []
for i in range(len(schedule)-1):
periodStart = schedule[i]
periodEnd = schedule[i+1]
period = f"{periodStart} - {periodEnd}"
discountRate = term_structure.zeroRate(periodEnd, day_count,compounding,compounding_frequency).rate()
spotRate = ibor_index.fixing(periodStart)
forwardRate = term_structure.forwardRate(periodStart, periodEnd,
day_count,
compounding,
compounding_frequency).rate()
cashflow = cashflows[i].amount()
discountFactor = discountFactors[i]
year_frac = ql.Actual360().yearFraction(periodStart,periodEnd)
if Instrument=='Cap':
intrinsic_value = Payoff('Cap',Notional,spotRate,strike,year_frac,discountFactor)
elif Instrument == 'Floor':
intrinsic_value = Payoff('Floor',Notional,spotRate,strike,year_frac,discountFactor)
discountedCashflow = discountedCashflows[i]
tableData.append([periodStart.ISO(), periodEnd.ISO(), discountRate,
forwardRate, spotRate,
"{:,.2f}".format(cashflow),
discountFactor,
"{:,.2f}".format(discountedCashflow),"{:,.2f}".format(intrinsic_value) ])
# Print the table using tabulate
headers = ["Period Start", "Period End", "Discount Rate", "Forward Rate",
"Spot Rate", "Cashflow", "Discount Factor", "Discounted Cashflow","Value","Intrinsic Value", "Time Value"]
print(tabulate(tableData, headers=headers))
```
## Answer by Luigi Ballabio (score 1)
https://quant.stackexchange.com/a/76518
The `CapFloor` class provides some limited information (see the SWIG wrappers). You can call `capfloor.optionletsPrice()` to get a list of the PVs of the caplets/floorlets and other methods such as `capfloor.optionletsAtmForward()` and `capfloor.optionletsDiscountFactor()` for more data.Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.