2
$\begingroup$

I am trying to add a holiday to my calendar in QuantLib such that my option pricing model considers this in pricing where I would expect that the time to expiry should decrease with the inclusion of a holiday, and my option reduce in price. However, when I use the .addHoliday method it successfully adds the holiday to the Calendar, but the option price doesn't change. It seems as if the option time to expiry is used from the DayCounter object and doesn't use the Calendar. Would my interpretation here be correct and if so, how would I add a holiday such that it affects my option pricing? My expectation is that the option price decreases by the same amount as if I reduced the expiry date by a day. Example below

import QuantLib as ql

def get_option_price(add_holiday):
    calculation_date = ql.Date(18, 1, 2023)
    ql.Settings.instance().evaluationDate = calculation_date

    expiry = ql.Date(30, 1, 2023)
    spot_price = 100.
    strike_price = 105.
    volatility = 0.50
    dividend_rate = 0
    option_type = ql.Option.Call

    risk_free_rate = 0.001
    day_count = ql.Actual365Fixed()
    calendar = ql.UnitedStates(0)
    
    if add_holiday:
        calendar.addHoliday(ql.Date(24, 1, 2023))
    print(add_holiday, ql.Calendar.holidayList(calendar, calculation_date, expiry))

    payoff = ql.PlainVanillaPayoff(option_type, strike_price)
    exercise = ql.EuropeanExercise(expiry)
    european_option = ql.VanillaOption(payoff, exercise)

    spot_handle = ql.QuoteHandle(ql.SimpleQuote(spot_price))
    flat_ts = ql.YieldTermStructureHandle(ql.FlatForward(calculation_date, risk_free_rate, day_count))
    dividend_yield = ql.YieldTermStructureHandle(ql.FlatForward(calculation_date, dividend_rate, day_count))
    flat_vol_ts = ql.BlackVolTermStructureHandle(ql.BlackConstantVol(calculation_date, calendar, volatility, day_count))
    bsm_process = ql.BlackScholesMertonProcess(spot_handle, dividend_yield, flat_ts, flat_vol_ts)

    european_option.setPricingEngine(ql.AnalyticEuropeanEngine(bsm_process))
    print(european_option.NPV(), european_option.delta())

get_option_price(False)
get_option_price(True)
False ()
1.7305073013860064 0.3111915181849204
True (Date(24,1,2023),)
1.7305073013860064 0.3111915181849204
$\endgroup$
11
  • $\begingroup$ Most tools use expiry as a fraction of 365 or 365.25 days and a holiday has no impact on that (unless the expiry date itself would be a holiday and you shift to the next or prior business day). After all, the actual days to expiry are still the same, if there are holidays in between or not. You also specify actual/365 which means it counts every day und uses 365 days for computing the year fraction $\endgroup$
    – AKdemy
    Jan 20, 2023 at 10:53
  • $\begingroup$ I'm a little surprised of the implementation of a calendar and then not using it to calculate time to expiry. After all, time to expiry should be in trading time. For example, if it were Monday morning and I had an expiry on Friday evening, and Christmas Day was Wednesday, I would only want to use the equivalent of 4 days till expiry. Otherwise QuantLib is forcing me to change my expiry date or my volatility to get a realistic option price. Using this example, in QuantLib, is there any way for me to have a holiday reduce the time to expiry of an option keeping all the other properties as is? $\endgroup$ Jan 20, 2023 at 12:27
  • 1
    $\begingroup$ That's not how it works, but it's an interesting concept. In some markets (notbaly, Brazil), the interest on some debts only accrues during working days - doesn't accrue during holidays. But in most of the world, interest accrues daily. Can you please articulate why you want your option to be priced this way? $\endgroup$ Jan 20, 2023 at 12:48
  • 1
    $\begingroup$ @Dimitri Vulis' comment about Brazil is important. Howver, your term sheet (or the exchange) will determine the specifications. For example, if you have ACT/365FIXED, you will count all days (if holiday or weekend), and FIXED means you also do not care about a leap year. In order to get a realistic option price, you need to follow the convention. I doubt the convention will be to only count working days. This answer shows how a realistic option price is computed given details about expiry and delivery date etc. $\endgroup$
    – AKdemy
    Jan 20, 2023 at 13:19
  • 1
    $\begingroup$ @pinkusfloyd "I believe this is how professional options traders price their options" I'm not even going to comment on whether this believe is correct, but if it were the case, it wouldn't imply that "professional options traders" are right. Appeals to authority don't work in quantitative finance :) I do urge you to read this article doi.org/10.1002/wilm.10871 by Espeg Haug. $\endgroup$ Jan 20, 2023 at 13:45

1 Answer 1

3
$\begingroup$

Replace

    day_count = ql.Actual365Fixed()
    calendar = ql.UnitedStates(0)

with

    calendar = ql.UnitedStates(0)
    day_count = ql.Business252(calendar)

to get the behavior you expect. If you want only the volatility to be affected, use business/252 for the vol curve and act/365F for the rate curves.

$\endgroup$
3
  • $\begingroup$ This is perfect, thank you! $\endgroup$ Jan 22, 2023 at 1:03
  • $\begingroup$ A follow up question: it seems like doing it this way slows down the options calculation significantly (around 4x slower). Not sure if it's relevant but I also have the enable intraday/high resolution date enabled. Is this expected? @luigi-ballabio $\endgroup$ Feb 15, 2023 at 5:19
  • $\begingroup$ That's expected. The other day count conventions are simple calculations, e.g., (expiry date - valuation date)/365; the business/252 convention needs to look at each day between the two dates to see if it's a business day or a holiday. $\endgroup$ Feb 15, 2023 at 9:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.