A brief introduction to the QuantLib in Python…

QuantLib is an open-source framework for quantitative finance  written in C++. There is an active community who develop and extend the library. QuantLib covers a wide range of financial instruments and markets like IR, FX and Equities and provide pricing engines and models, optimization algorithm, a Monte-Carlo framework, business day conventions, day count conventions, holidays calendars and even more… and grows continuously.

There are existing interfaces to different language like Python, Ruby, Java and more via swig. In the following I will describe how to build the QuantLib for Python.

In the following description I assume that you have already installed Python with IPython including all dependencies, numpy, scipy, pandas and matplotlib. A good starting point are distributions like Anaconda or WinPython (for Windows only). These distribution are shipped with many more useful libraries and provide an easy way to install more packages. Its worth to check them out, if haven’t tried them yet.

For windows you can find pre-build executables of the QuantLib at Christoph Gohlke’s website. If you want to have the most recent version you should clone the current master branch from GitHub and build the library and the python package yourself.

To build QuantLib from sources under Windows you need the correct Visual Studio depending on the Python version you are targeting. For Python 3.3 you need Visual Studio 2010 and for Python 2.7 you need Visual Studio 2008. Additional dependencies are the boost library and swig.

I will not cover how to install the dependencies but you can find binary installer for swig under windows on the swig project website and there also exists precompiled binaries for the boost library on source forge. Add the path to swig command to your PATH environment variable.

The following steps are valid for Python 2.7 and 3.3:

0. Clone the git repository either with using git:

cd c:\path\to\quantlib
git clone https://github.com/lballabio/quantlib .

or download as a zipped file from GitHub.

1. Open the QuantLib_vcXX.sln and build it in “Release” or “Release static runtime” configuration. For more details check the install documentation on the QuantLib project site. You will find the solution under

c:\path\to\quantlib\QuantLib

2. Open command line window and set required environment variables

SET QL_DIR=c:\path\to\quantlib\QuantLib
SET INCLUDE=c:\path\to\boost;%INCLUDE%
SET LIB=c:\path\to\boost\lib;%LIB%

3. Create the interface code with swig

cd c:\path\to\quantlib\QuantLib-SWIG\python
python setup.py wrap

4. Build and install the package

python setup.py build
python setup.py install

5. Test your install

python setup.py test

If you use Visual Studio 2010 and target Python 2.7 you will encounter the error message “Unable to find vcversall.bat“. The following “hack” works for me:

Set an additional environment variable at step 2:

SET VS90COMNTOOLS=%VS100COMNTOOLS%

Under unix you can also find some pre-build packages (e.g. for Ubuntu) in your package-manager or you build it from sources yourself with the usual configure, make and make install chain (see here and for Mac OS X here). After you build the library you can continue with step 3 above. Be sure you have installed swig before. Just download the source from the swig project and install via the usual unix install commands.

After we have managed to install QuantLib Python package I want to show you how you can use the QuantLib C++ classes from Python. You can download the following simple example  from my repository “IPythonScripts” on GitHub.

In the first example we will see how to setup an interest rate swap and use a discounting pricing engine to calculate the NPV and the fair rate for this swap.

First we need to import the QuantLib package, since we want also produce some plots we import numpy and matplotlib.

import numpy as np
import matplotlib.pyplot as plt
import QuantLib as ql

In the next step we will setup the yield curve (aka yieldtermstructure). For simplicity we will use an flat forward curve. I will use the same curve for discounting and calculation of the forwards. QuantLib supports multi curve setups, as I will maybe show in a later post or you can see in the examples how to setup more realistic yield curves.


# Set Evaluation Date
today = ql.Date(31,3,2015)
ql.Settings.instance().setEvaluationDate(today)
# Setup the yield termstructure
rate = ql.SimpleQuote(0.03)
rate_handle = ql.QuoteHandle(rate)
dc = ql.Actual365Fixed()
disc_curve = ql.FlatForward(today, rate_handle, dc)
disc_curve.enableExtrapolation()
hyts = ql.YieldTermStructureHandle(disc_curve)

The yieldTermStructure object provides an method which gives us the discount factor for a particular date (QuantLib.Date object) or time in years (with 0 = evaluationDate). This method is called discount.  I am using the numpy method vectorize to apply this function on arrays or list of times and then generate a plot of the discount curve.

discount = np.vectorize(hyts.discount)
tg = np.arange(0,10,1./12.)
plt.plot(tg, discount(tg))
plt.xlabel("time")
plt.ylabel("discount factor")
plt.title("Flat Forward Curve")

discountcurve

In the next step we will setup up a plain vanilla EURIBOR 6M Swap with maturity in 10 years. Therefore we generate an index and using the handle to our yield curve as forward curve and two schedules, one for the fixed rate leg with annual payments and one for the float leg with semi annual payments.

start = ql.TARGET().advance(today, ql.Period("2D"))

end = ql.TARGET().advance(start, ql.Period("10Y"))

nominal = 1e7

typ = ql.VanillaSwap.Payer

fixRate = 0.03

fixedLegTenor = ql.Period("1y")

fixedLegBDC = ql.ModifiedFollowing

fixedLegDC = ql.Thirty360(ql.Thirty360.BondBasis)

index = ql.Euribor6M(ql.YieldTermStructureHandle(disc_curve))

spread = 0.0

fixedSchedule = ql.Schedule(start, end, fixedLegTenor, index.fixingCalendar(), fixedLegBDC, fixedLegBDC, ql.DateGeneration.Backward, False)
floatSchedule = ql.Schedule(start, end, index.tenor(), index.fixingCalendar(), index.businessDayConvention(), index.businessDayConvention(), ql.DateGeneration.Backward, False)

swap = ql.VanillaSwap(typ, nominal, fixedSchedule, fixRate, fixedLegDC, floatSchedule, index, spread, index.dayCounter())

The last step before we can calculate the NPV we need a pricing engine. We are going to use the discountingSwapEngine. As the name suggests, it will discount all future payments to the evaluation date and calculate the difference between the present values of the two legs.

engine = ql.DiscountingSwapEngine(ql.YieldTermStructureHandle(disc_curve))
swap.setPricingEngine(engine)

print(swap.NPV())
print(swap.fairRate())

That was a very brief demonstration of the QuantLib. The examples which are shipped with the QuantLib give a much more detailed insight. So you may have a look on these.

7 thoughts on “A brief introduction to the QuantLib in Python…

  1. Dear Matthias,

    thank you very much for this interesting post. I’m working trough your QuantLib-Pyhon blogs right now. And I think it is a good introduction 🙂

    After computing the NPV and FairRate, I wanted to see the details of the cash-flow-structure. So I added:

    for i, d in enumerate(fixedSchedule): # the fixed payment schedule
    print( i+1, d, ” “, fixRate*nominal, “Eur” )

    which results in:

    1 April 2nd, 2015 300000.0 Eur
    2 April 4th, 2016 300000.0 Eur
    3 April 3rd, 2017 300000.0 Eur
    4 April 3rd, 2018 300000.0 Eur
    5 April 2nd, 2019 300000.0 Eur
    6 April 2nd, 2020 300000.0 Eur
    7 April 6th, 2021 300000.0 Eur
    8 April 4th, 2022 300000.0 Eur
    9 April 3rd, 2023 300000.0 Eur
    10 April 2nd, 2024 300000.0 Eur
    11 April 2nd, 2025 300000.0 Eur

    Unfortunately I have no idea how to get something similar for the floating leg. It seams that I need to compute the forward rates from the index-object?

    for i, d in enumerate(floatSchedule):
    print( i+1, d, [ index.FORWARDRATE(d) ] )

    Thank you very much
    Bernd

    Like

    1. If you iterate the floating leg (coupons) instead of schedule you can use the function indexFixing of the coupon, which yields the floating rate. Or you use the ibor index object to compute the fixing. Or you can use directly the forward curve (get the two discount factors and calculate it by hand). But the coupon expose all functions to calculate and inspect the cashflow (like fixing date, fixing, accrual days, etc…)

      Liked by 1 person

      1. Dear Matthias. Thank you very much for your answer.
        It sounds as if you first solution is the most suited for my purpose. Because the evaluated object should know it’s expected fixings because they are part of the valuation. So extracting those after computing the NPV should assure that the expected fixings are in line with the NPV.

        However, I failed to find the correct syntax in the web for doing so. I am not sure what you mean with “the function indexFixing of the coupon” because I have no coupon objects. Only a swap object. So the first step seams to be getting the coupon object from the swap object:

        swap.floatingLeg()

        But how top extract the expected fixings out of it?

        Liked by 1 person

      2. Dear Bernd,

        Yes you can get the leg (a vector of cashflows). You can iterate over it try to cast the each cashflow to a coupon object with the function as_coupon(). The coupon has a rate() method to get the rate.

        Liked by 1 person

      3. Again thank you very much for your help!

        I was able to extract what I was looking for:
        Iterating over the floating leg I got the date and amount of the cash flow.
        Calling “as_coupon()” on the leg elements I was able to get the rate

        for i in range(0, len(swap.floatingLeg())-1):
        print( “i=”,i, ” “, swap.floatingLeg()[i].date(), ” “, swap.floatingLeg()[i].amount(), ” “, ql.as_coupon( swap.floatingLeg()[i] ).rate() )

        Not supprisingly, the rates are not (really) changing because of the flat forward curve.

        i= 0 April 4th, 2016 153216.70923430953 0.029815143418568345
        i= 1 October 3rd, 2016 150713.48497647018 0.029811458566774324
        i= 2 April 3rd, 2017 150713.48497647018 0.029811458566774324
        i= 3 October 2nd, 2017 150713.48497647242 0.029811458566774765
        i= 4 April 3rd, 2018 151547.82448187243 0.029812686783319168
        i= 5 October 2nd, 2018 150713.48497647242 0.029811458566774765
        i= 6 April 2nd, 2019 150713.48497647242 0.029811458566774765
        i= 7 October 2nd, 2019 151547.82448187022 0.02981268678331873
        i= 8 April 2nd, 2020 151547.82448187022 0.029812686783318734
        i= 9 October 2nd, 2020 151547.82448187022 0.02981268678331873
        i= 10 April 6th, 2021 154051.25449262204 0.029816371837281683
        i= 11 October 4th, 2021 149879.21404410407 0.029810230417611862
        i= 12 April 4th, 2022 150713.48497647242 0.029811458566774765
        i= 13 October 3rd, 2022 150713.48497647242 0.029811458566774765
        i= 14 April 3rd, 2023 150713.48497647018 0.029811458566774324
        i= 15 October 2nd, 2023 150713.4849764724 0.02981145856677476
        i= 16 April 2nd, 2024 151547.82448187243 0.02981268678331917
        i= 17 October 2nd, 2024 151547.82448187022 0.02981268678331873

        Liked by 1 person

Leave a comment