3
$\begingroup$

I am having trouble using QuantLib with Python to calculate American options with discrete dividends. I am using Anaconda, Spyder, Python 3.6, and the most recent version of QuantLib. I created functions in pricingfunctions.py, which streamline the building process for pricing options and the greeks based on the code on this webpage - http://www.bnikolic.co.uk/blog/ql-american-disc-dividend.html:

import QuantLib as ql
#%%
def create_american_process(valuation_date, rf_rate, spot, ivol):

#set calendar & day count
calendar = ql.UnitedStates()
day_counter = ql.ActualActual()

#set evaluation date
ql.Settings.instance().evaluation_date = valuation_date    

#set rate & vol curves
rate_ts = ql.FlatForward(valuation_date, ql.QuoteHandle(rf_rate), 
                     day_counter)

vol_ts = ql.BlackConstantVol(valuation_date, calendar, 
                         ql.QuoteHandle(ivol), day_counter)  
#create process
process = ql.BlackScholesProcess(ql.QuoteHandle(spot),
                             ql.YieldTermStructureHandle(rate_ts),
                             ql.BlackVolTermStructureHandle(vol_ts))
return process

#%%
def american_px_greeks(valuation_date, expiry, call_or_put, strike,   div_dates, 
                       div_values, time_steps, process):

#create instance as call or put
if call_or_put.lower() == 'call':
    option_type = ql.Option.Call 
elif call_or_put.lower() == 'put':
    option_type = ql.Option.Put 
else:
    raise ValueError("The call_or_put value must be call or put.")        

#set exercise and payoff
exercise = ql.AmericanExercise(valuation_date, expiry)
payoff = ql.PlainVanillaPayoff(option_type, strike)

#create option instance
option = ql.DividendVanillaOption(payoff, exercise, div_dates, div_values)

#set mesh size for finite difference engine    
grid_points = time_steps - 1                                  

#create engine
engine = ql.FDDividendAmericanEngine(process, time_steps, grid_points)
option.setPricingEngine(engine)
return option

#%%
def print_option_results(option):    
    print("NPV: ", option.NPV())
    print("Delta: ", option.delta())
    print("Gamma: ", option.gamma())
    return None   

Then I run the below script, but the outputs for NPV, Delta and Gamma are all 0.0, which is wrong. The NPV should be in the 12 to 13 range, and the Delta close to 0.50, while Gamma is negligible. I am not sure what is wrong. Any insights are much appreciated. Thanks

import QuantLib as ql
from pricingfunctions import create_american_process
from pricingfunctions import american_px_greeks
from pricingfunctions import print_option_results

#%%
#parameters
vol = 0.25
strike = 100
spot = ql.SimpleQuote(100)
rf_rate = ql.SimpleQuote(0.01)
ivol = ql.SimpleQuote(vol)
call_or_put = 'call'
div_dates = [ql.Date(14, 5, 2014), ql.Date(14, 8, 2014), ql.Date(14, 11, 2014)]
div_values = [1.0, 1.0, 1.0]
expiry = ql.Date(15, 1, 2016)
valuation_date = ql.Date(17, 4, 2014)
time_steps = 456 

process_test = create_american_process(valuation_date, rf_rate, spot, ivol)
option_test = american_px_greeks(valuation_date, expiry, call_or_put, strike, div_dates, div_values, time_steps, process_test)
print_option_results(option_test)
$\endgroup$
4
$\begingroup$

You're not setting the global evaluation date. If you don't, you're in December 2017 and your option has expired a good while ago.

Adding

ql.Settings.instance().evaluationDate = valuation_date

before the calculations will give you the expected results.

$\endgroup$
  • $\begingroup$ thanks very much. i realized the error. instead of using evaluationDate, i used evaluation_date. subtle but bad mistake. appreciate the response Luigi. cheers $\endgroup$ – fmc100 Dec 6 '17 at 17:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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