Integrating QuantLib with R and Web – Barrier Options Pricer

Some of QuantLib functionality is ported to R in RQuantLib. In particular the pricing of Barrier options. Unfortunately, only European. But we need American in order to price and simulate future scenarios for the so-called KO-Zertifikate (Knock-Out Warrants), which are quite popular among German retail traders. We show how to quickly adopt the code from QuantLib testsuite, compile it under Linux and integrate with R and web.

We have already shown how to call R scripts from PHP and how to build QuantLib under Ubuntu. Now we will show how to integrate the QuantLib functionality into R and Web by the example of American barrier options.
A quick look at the test suite of QuantLib 1.9.1 readily lets us notice the file /test-suite/barrieroption.cpp, method testHaugValues()
The source code can be read relatively straightforwardly (if you a new to QuantLib, have a look at my notes for newbies).

#include <stdio.h>
#include <stdlib.h>
#include <ql/types.hpp>
#include <ql/time/calendars/nullcalendar.hpp>
#include <ql/time/daycounters/actual360.hpp>
#include <ql/instruments/barrieroption.hpp>
#include <ql/models/equity/hestonmodel.hpp>
#include <ql/pricingengines/barrier/binomialbarrierengine.hpp>
#include <ql/pricingengines/barrier/fdhestonbarrierengine.hpp>
#include <ql/pricingengines/barrier/fdblackscholesbarrierengine.hpp>
#include <ql/pricingengines/barrier/mcbarrierengine.hpp>
#include <ql/pricingengines/blackformula.hpp>
#include <ql/termstructures/yield/flatforward.hpp>
#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
#include <ql/termstructures/volatility/equityfx/blackvariancecurve.hpp>
#include <ql/termstructures/volatility/equityfx/blackvariancesurface.hpp>
#include <boost/make_shared.hpp>

using namespace QuantLib;

boost::shared_ptr<YieldTermStructure>
flatRate(const Date& today,
	const boost::shared_ptr<Quote>& forward,
	const DayCounter& dc) {
	return boost::shared_ptr<YieldTermStructure>(
		new FlatForward(today, Handle<Quote>(forward), dc));
}

boost::shared_ptr<YieldTermStructure>
flatRate(const Date& today, Rate forward, const DayCounter& dc) {
	return flatRate(
		today, boost::shared_ptr<Quote>(new SimpleQuote(forward)), dc);
}


boost::shared_ptr<BlackVolTermStructure>
flatVol(const Date& today,
	const boost::shared_ptr<Quote>& vol,
	const DayCounter& dc) {
	return boost::shared_ptr<BlackVolTermStructure>(new
		BlackConstantVol(today, NullCalendar(), Handle<Quote>(vol), dc));
}


int main(int argc, char* argv[])
{
	char * pEnd;
	long parOPTIONTYPE = strtol(argv[1], &pEnd, 10); //0=CALL | 1=PUT
	double parBARRIER = strtod(argv[2], &pEnd);
	double parSTRIKE = strtod(argv[3], &pEnd);
	double parSPOT = strtod(argv[4], &pEnd);
	double parTIMETOMATURITY = strtod(argv[5], &pEnd);
	double parVOLATILITY = strtod(argv[6], &pEnd);
	double parINTERESTRATE = strtod(argv[7], &pEnd);
	double parDIVIDENDYIELD = strtod(argv[8], &pEnd);
		

	DayCounter dc = Actual360();
	Date today = Date::todaysDate();
	Date exDate = today + Integer(parTIMETOMATURITY * 360 + 0.5);

	boost::shared_ptr<SimpleQuote> spot = boost::make_shared<SimpleQuote>(0.0);
	boost::shared_ptr<SimpleQuote> qRate = boost::make_shared<SimpleQuote>(0.0);
	boost::shared_ptr<YieldTermStructure> qTS = flatRate(today, qRate, dc);
	boost::shared_ptr<SimpleQuote> rRate = boost::make_shared<SimpleQuote>(0.0);
	boost::shared_ptr<YieldTermStructure> rTS = flatRate(today, rRate, dc);
	boost::shared_ptr<SimpleQuote> vol = boost::make_shared<SimpleQuote>(0.0);
	boost::shared_ptr<BlackVolTermStructure> volTS = flatVol(today, vol, dc);
	

	spot->setValue(parSPOT);
	qRate->setValue(parDIVIDENDYIELD);
	rRate->setValue(parINTERESTRATE);
	vol->setValue(parVOLATILITY);
	
	Option::Type optionType = Option::Type::Put;
	if(parOPTIONTYPE==0) optionType = Option::Type::Call;
	
	Barrier::Type barrierType = Barrier::Type::UpOut;
	if(optionType == Option::Type::Call) barrierType = Barrier::Type::DownOut;

	boost::shared_ptr<StrikedTypePayoff> payoff =
		boost::make_shared<PlainVanillaPayoff>(optionType, parSTRIKE);

	boost::shared_ptr<BlackScholesMertonProcess> stochProcess =
		boost::make_shared<BlackScholesMertonProcess>(
			Handle<Quote>(spot),
			Handle<YieldTermStructure>(qTS),
			Handle<YieldTermStructure>(rTS),
			Handle<BlackVolTermStructure>(volTS));

	boost::shared_ptr<Exercise> exercise;
    exercise = boost::make_shared<AmericanExercise>(exDate);

	BarrierOption barrierOption(barrierType, parBARRIER, 0.0, payoff, exercise);

	boost::shared_ptr<PricingEngine> engine;
	Real calculated;

	engine = boost::make_shared<BinomialBarrierEngine<CoxRossRubinstein, DiscretizedBarrierOption> >(stochProcess, 400);
	barrierOption.setPricingEngine(engine);

	calculated = barrierOption.NPV();
	std::cout << calculated << std::endl;
	return 1;
}

Note that we have also borrowed the helpers for flateRate and flatVol (lines 21-42) from test-suite/utilities.hpp and the lines 47-55 are just to read the parameters from command line (recall that argv[0] contains the command, thus we start with argv[1]).

We compile the code on Debian as follows:
QuantLib$ g++ KnockOut.cpp -o KnockOut -lQuantLib -std=c++14

importance of c++14 flag

The flag c++14 (c++11 will also do) is important, if you do not specify it, you will get the following error message:

KnockOut.cpp: In function ‘int main(int, char**)’:
KnockOut.cpp:92:36: error: ‘QuantLib::Option::Type’ is not a class or namespace
Option::Type optionType = Option::Type::Put;
^
KnockOut.cpp:93:44: error: ‘QuantLib::Option::Type’ is not a class or namespace
if(parOPTIONTYPE==0) optionType = Option::Type::Call;
^
KnockOut.cpp:95:39: error: ‘QuantLib::Barrier::Type’ is not a class or namespace
Barrier::Type barrierType = Barrier::Type::UpOut;
^
KnockOut.cpp:96:27: error: ‘QuantLib::Option::Type’ is not a class or namespace
if(optionType == Option::Type::Call) barrierType = Barrier::Type::DownOut;
^
KnockOut.cpp:96:62: error: ‘QuantLib::Barrier::Type’ is not a class or namespace
if(optionType == Option::Type::Call) barrierType = Barrier::Type::DownOut;

[collapse]

Test the program by calling
./KnockOut 0 95 90 100 0.5 0.25 0.08 0.04 (you should get 10.4655)
In order to call it from R use
res = system("/path/to/KnockOut 0 95 90 100 0.5 0.25 0.08 0.04", intern=TRUE)

Of course this is a very quick and dirty solution, in particular, it is can be easily crashed by not supplying or supplying incorrect arguments. However, this code is not meant to be called directly and the plausibility check will be done in PHP, which is much more easier and convenient.

Like this post and wanna learn more? Have a look at Knowledge rather than Hope: A Book for Retail Investors and Mathematical Finance Students

FinViz - an advanced stock screener (both for technical and fundamental traders)