Showing posts with label quantlib. Show all posts
Showing posts with label quantlib. Show all posts

Sunday, February 28, 2021

How to cross compile using Docker Desktop experimental feature buildx

Another demo to show the building of packages using experiemtal feature of Docker desktop. Have to enable the experimental feature to cross compile in other architetcures different from the host machine. E.g. cross compile armv7 packages in amd64 or arm64 host of Mac or PC.
Shell script   Select all
cd $HOME mkdir -p my-quantlib cd my-quantlib # get helloworld.ipynb wget https://raw.githubusercontent.com/lballabio/dockerfiles/master/quantlib-jupyter/Hello%20world.ipynb cat >$HOME/my-quantlib/Dockerfile_ql_armv7_1.21 <<'HEREEOF' # Dockerfile_ql_armv7_1.21 # docker buildx build --platform linux/arm/v7 -f Dockerfile_ql_armv7_1.21 -t armv7/quantlib:1.21 . # Build Quantlib libraries for armv7 in arm64/amd64 host ARG tag=latest FROM arm32v7/ubuntu:18.04 LABEL Description="Provide a building environment where the QuantLib Python jupyter-notebook" RUN apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential wget libbz2-dev vim git ENV boost_version=1.67.0 ENV boost_dir=boost_1_67_0 # Build boost RUN echo 'Building boost ...' RUN wget --no-check-certificate https://boostorg.jfrog.i o/artifactory/main/release/${boost_version}/source/${boo st_dir}.tar.gz \ && tar xfz ${boost_dir}.tar.gz \ && rm ${boost_dir}.tar.gz \ && cd ${boost_dir} \ && ./bootstrap.sh \ && ./b2 --without-python --prefix=/usr -j 4 link=shared runtime-link=shared install \ && ./b2 --prefix=/Staging/usr install \ && cd .. && rm -rf ${boost_dir} && ldconfig # Build Quantlib C++ RUN echo 'Building Quantlib C++ ...' ENV quantlib_version=1.21 RUN wget https://github.com/lballabio/QuantLib/releases/download/QuantLib-v${quantlib_version}/QuantLib-${quantlib_version}.tar.gz \ && tar xfz QuantLib-${quantlib_version}.tar.gz \ && rm QuantLib-${quantlib_version}.tar.gz \ && cd QuantLib-${quantlib_version} \ && ./configure --prefix=/usr --disable-static CXXFLAGS=-O3 \ && make -j 4 && make install \ && make DESTDIR=/Staging install \ && make clean \ && cd .. && ldconfig # && cd .. && rm -rf QuantLib-${quantlib_version} && ldconfig # Build Quantlib-Python RUN echo 'Build Quantlib-Python ...' RUN apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get install -y swig python3 python3-pip python-dev libgomp1 # Build Quantlib for Python3 RUN echo 'Install Quantlib Python' ENV quantlib_swig_version=1.21 RUN wget https://github.com/lballabio/QuantLib-SWIG/releases/download/QuantLib-SWIG-v${quantlib_swig_version}/QuantLib-SWIG-${quantlib_swig_version}.tar.gz \ && tar xfz QuantLib-SWIG-${quantlib_swig_version}.tar.gz \ && rm QuantLib-SWIG-${quantlib_swig_version}.tar.gz \ && cd QuantLib-SWIG-${quantlib_swig_version} \ && ./configure CXXFLAGS="--param ggc-min-expand=1 --param ggc-min-heapsize=32768" PYTHON=/usr/bin/python3 \ && make -C Python && make -C Python check && make -C Python install \ && cd .. && rm -rf QuantLib-SWIG-${quantlib_swig_version} && ldconfig # Build jupyter-notebook server RUN python3 -c "print('\033[91m Building jupyter-notebook server ... \033[0m')" RUN pip3 install --no-cache-dir jupyter jupyterlab matplotlib numpy scipy pandas ipywidgets RISE RUN jupyter-nbextension install rise --py --sys-prefix RUN jupyter-nbextension install widgetsnbextension --py --sys-prefix \ && jupyter-nbextension enable widgetsnbextension --py --sys-prefix # Build Quantlib for Python2 RUN apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get install -y python \ && apt-get clean RUN wget https://bootstrap.pypa.io/2.7/get-pip.py \ && python2 get-pip.py \ && rm get-pip.py RUN wget https://dl.bintray.com/quantlib/releases/QuantLib-SWIG-${quantlib_swig_version}.tar.gz \ && tar xfz QuantLib-SWIG-${quantlib_swig_version}.tar.gz \ && rm QuantLib-SWIG-${quantlib_swig_version}.tar.gz \ && cd QuantLib-SWIG-${quantlib_swig_version} \ && ./configure CXXFLAGS="--param ggc-min-expand=1 --param ggc-min-heapsize=32768" \ && make -C Python && make -C Python check && make -C Python install \ && cd .. && rm -rf QuantLib-SWIG-${quantlib_swig_version} && ldconfig RUN pip2 install --no-cache-dir numpy EXPOSE 8888 RUN mkdir /notebooks VOLUME /notebooks COPY *.ipynb /notebooks/ # Starting jupyter-notebook server RUN python3 -c "print('\033[92m Starting jupyter-notebook server at port 8888 \033[0m')" CMD jupyter notebook --no-browser --allow-root --ip=0.0.0.0 --port=8888 --notebook-dir=/notebooks HEREEOF # build and load image (after experimental feature of Docker Desktop is enabled docker buildx build --platform linux/arm/v7 --memory="8g" --output "type=docker,push=false,dest=armv7_ql.tar" -f Dockerfile_ql_armv7_1.21 -t armv7/quantlib:1.21 . docker load < armv7_ql.tar # run image docker run --platform linux/arm/v7 -d -p 8888:8888 --name myquantlibarmv7testing armv7/quantlib:1.21 # list the token of the jupyter-notebook server docker container exec -it myquantlibarmv7testing jupyter notebook list


If using WSL2 docker CLI in Linux, should enable the experimental feature first.
export DOCKER_CLI_EXPERIMENTAL=enabled
docker buildx create --name mybuilder
docker buildx use mybuilder
docker buildx inspect --bootstrap
docker buildx build --platform linux/arm/v7 --memory="8g" --output "type=docker,push=false,dest=armv7_ql.tar" -f Dockerfile_ql_armv7_1.21 -t armv7/quantlib:1.21 .


Thursday, February 25, 2021

How to cross compile QuantLib in docker

This example demo using dockcross to build Quantlib armv7 library packages and cross compile in host X86_64 machine
Shell script   Select all
cd $HOME mkdir -p dockcross cd dockcross cat >$HOME/dockcross/dockcross_ql_1.21 <<'HEREEOF' # dockcross_ql_1.21 # docker build -f dockcross_ql_1.21 -t dockcross/linux-armv7/quantlib:1.21 . # Build Quantlib libraries for armv7 ARG tag=latest FROM dockcross/linux-armv7 ENV DEFAULT_DOCKCROSS_IMAGE dockcross/linux-armv7/quantlib:1.21 ENV CROSS_PREFIX /usr/xcc/armv7-unknown-linux-gnueabi/armv7-unknown-linux-gnueabi/sysroot/usr LABEL Description="Provide a building environment dockcross/linux/armv7 for the QuantLib" RUN apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential wget vim git ENV boost_version=1.67.0 ENV boost_dir=boost_1_67_0 # Install boost dependencies RUN echo 'Building boost and required packages ...' RUN dpkg --add-architecture armhf \ && apt-get update \ && apt-get download libbz2-1.0:armhf libbz2-dev:armhf liblzma-dev:armhf \ && dpkg-deb -x libbz2-1*armhf.deb ./x \ && dpkg-deb -x libbz2-dev_*armhf.deb ./x \ && dpkg-deb -x liblzma-dev_*armhf.deb ./x \ && mv ./x/usr/lib/arm-linux-gnueabihf/* ${CROSS_PREFIX}/lib/ \ && mv ./x/usr/bin/* ${CROSS_PREFIX}/bin/ \ && mv ./x/usr/include/* ${CROSS_PREFIX}/include/ \ && mv ./x/usr/share/* ${CROSS_PREFIX}/share/ \ && mv ./x/lib/arm-linux-gnueabihf/* ${CROSS_PREFIX}/lib/ \ && rm -fr ./x *.deb && ldconfig RUN wget https://sourceforge.net/projects/libpng/files/zlib/1.2.11/zlib-1.2.11.tar.gz/download -O zlib-1.2.11.tar.gz \ && tar xfz zlib-1.2.11.tar.gz \ && rm zlib-1.2.11.tar.gz \ && cd zlib-1.2.11 \ && ./configure --prefix=${CROSS_PREFIX} && make && make install \ && cd .. && rm -rf zlib-1.2.11 && ldconfig # Build boost RUN wget https://dl.bintray.com/boostorg/release/${boost_version}/source/${boost_dir}.tar.gz \ && tar xfz ${boost_dir}.tar.gz \ && rm ${boost_dir}.tar.gz \ && cd ${boost_dir} \ && ./bootstrap.sh --with-toolset=gcc --prefix=${CROSS_PREFIX} \ && touch user-config.jam \ && echo "using gcc : armv7 : ${CXX} ;" > user-config.jam \ && echo "using mpi ;" >> user-config.jam \ && ./b2 --toolset=gcc-armv7 --address-model=32 --architecture=arm --user-config=./user-config.jam --without-python --prefix=${CROSS_PREFIX} -j 4 link=shared runtime-link=shared install \ && cd .. && rm -rf ${boost_dir} && ldconfig # Build Quantlib C++ RUN echo 'Building Quantlib C++ ...' ENV quantlib_version=1.21 RUN wget https://dl.bintray.com/quantlib/releases/QuantLib-${quantlib_version}.tar.gz \ && tar xfz QuantLib-${quantlib_version}.tar.gz \ && rm QuantLib-${quantlib_version}.tar.gz \ && cd QuantLib-${quantlib_version} \ && ./configure --host=x86_64-linux-gnu --target=armv7-unknown-linux-gnueabi --with-boost-include=${CROSS_PREFIX}/include/boost --with-boost-lib=${CROSS_PREFIX}/lib --prefix=${CROSS_PREFIX} --disable-static CXXFLAGS=-O3 \ && make -j 4 && make install \ && make clean \ && cd .. && ldconfig HEREEOF # build image docker build -f dockcross_ql_1.21 -t dockcross/linux-armv7/quantlib:1.21 . # Test dockcross compile docker run --rm dockcross/linux-armv7/quantlib:1.21 > dockcross-quantlib-armv7 chmod +x dockcross-quantlib-armv7 ./dockcross-quantlib-armv7 bash -c '$CXX -v' # Copy example cpp file from image docker run -v $PWD:/opt/mount --rm --entrypoint cp dockcross/linux-armv7/quantlib:1.21 /work/QuantLib-1.21/Examples/Bonds/Bonds.cpp /opt/mount/Bonds.cpp # Use this command to copy whole directory recursively # docker run -v $PWD:/opt/mount --rm --entrypoint cp dockcross/linux-armv7/quantlib:1.21 -r /work/QuantLib-1.21/Examples /opt/mount/QLExamples # Compile and check binary ./dockcross-quantlib-armv7 bash -c '$CXX Bonds.cpp -lQuantLib -o Bonds -static' file Bonds


# install qemu and run in host
sudo apt update
sudo apt install -y qemu-user
qemu-arm Bonds

# Or test run it in armv7 machine e.g. RaspberryPi 3B+
scp Bonds mypi3b:~/.
ssh mypi3b '~/Bonds'

Friday, May 5, 2017

How to translate QuantLib C++ code to Python

Here is a demo of how QuantLib c++ code are translated to Python. This included the code for importing of csv file and construction of volatility surface and the timing of MCDiscreteArithmeticAPEngine. Slicing and manipulation of list/array is much easier in Python than that of C++ code. However, C++ is faster.

QuantLib C++ source code, AsianOption.cpp

AsianOption.cpp    Select all
// g++ -std=c++11 AsianOption.cpp -o AsianOption -lQuantLib #include <ql/quantlib.hpp> #include <boost/timer.hpp> #include <iostream> #include <iomanip> #include <fstream> #include <string> #include <boost/algorithm/string/split.hpp> #include <boost/algorithm/string/classification.hpp> #include <boost/lexical_cast.hpp> using namespace QuantLib; using namespace std; void GetStrikes(string &path, vector<Real> &strikes) { std::ifstream file(path); std::string line; std::vector<std::string> tokens; int linecount = 0; while (std::getline(file, line)) { std::stringstream stringStream(line); std::string content; int item = 0; if (linecount >= 1) while (std::getline(stringStream, content, ',')) { switch (item) { case 0: // strikes are on first column only strikes.push_back(boost::lexical_cast<double>(content)); break; default: break; } item++; } linecount++; } return; /* if hardcode csv data strikes.push_back(0.67263); strikes.push_back(0.71865); strikes.push_back(0.7487); strikes.push_back(0.77129); strikes.push_back(0.78984); strikes.push_back(0.80587); strikes.push_back(0.82034); strikes.push_back(0.83379); strikes.push_back(0.84658); strikes.push_back(0.85792); strikes.push_back(0.87354); strikes.push_back(0.89085); strikes.push_back(0.90904); strikes.push_back(0.9289); strikes.push_back(0.95157); strikes.push_back(0.97862); strikes.push_back(1.01337); strikes.push_back(1.06261); strikes.push_back(1.14631); */ } void GetExpiryDates(string &path, vector<Date> &expirations) { std::ifstream file(path); std::string line; std::vector<std::string> tokens; int linecount = 0; while (std::getline(file, line)) { std::stringstream stringStream(line); std::string content; int item = 0; if (linecount == 0) // expiration dates are on first row only while (std::getline(stringStream, content, ',')) { switch (item) { case 1: case 2: case 3: case 4: boost::algorithm::split(tokens, content, boost::algorithm::is_any_of("/")); expirations.push_back(Date(Day(boost::lexical_cast<int>(tokens.at(1))), Month(boost::lexical_cast<int>(tokens.at(0))), Year(boost::lexical_cast<int>(tokens.at(2))))); break; default: break; } item++; } linecount++; } return; /* if hardcode csv data expirations.push_back(Date(27, June, 2017)); expirations.push_back(Date(27, September, 2017)); expirations.push_back(Date(27, December, 2017)); expirations.push_back(Date(27, June, 2018)); */ } Matrix GetVolData(string &path, vector<Date> &expirations, vector<Real> &strikes) { // Matrix volMatrix(19, 4); Matrix volMatrix(strikes.size(), expirations.size()); std::ifstream file(path); std::string line; std::vector<std::string> tokens; int linecount = 0; while (std::getline(file, line)) { std::stringstream stringStream(line); std::string content; int item = 0; if (linecount >= 1) // vols are on second row onward while (std::getline(stringStream, content, ',')) { switch (item) { case 1: case 2: case 3: case 4: volMatrix[linecount-1][item-1] = boost::lexical_cast<double>(content); // vols are on second column onward break; default: break; } item++; } linecount++; } return volMatrix; /* if hardcode csv data //0.67263,0.144183920277296,0.139374695503699,0.135526204819277,0.12885 volMatrix[0][0] = 0.144183920277296; volMatrix[0][1] = 0.139374695503699; volMatrix[0][2] = 0.135526204819277; volMatrix[0][3] = 0.12885; //0.71865,0.133703802426343,0.129893056346044,0.126909006024096,0.12175 volMatrix[1][0] = 0.133703802426343; volMatrix[1][1] = 0.129893056346044; volMatrix[1][2] = 0.126909006024096; volMatrix[1][3] = 0.12175; //0.7487,0.126860526863085,0.123701764371087,0.121209416342412,0.11695 volMatrix[2][0] = 0.126860526863085; volMatrix[2][1] = 0.123701764371087; volMatrix[2][2] = 0.121209416342412; volMatrix[2][3] = 0.11695; // 0.77129,0.121720863192182,0.118881707209199,0.116979766476388,0.11381 volMatrix[3][0] = 0.121720863192182; volMatrix[3][1] = 0.118881707209199; volMatrix[3][2] = 0.116979766476388; volMatrix[3][3] = 0.11381; // 0.78984,0.117581136690647,0.115218428824572,0.113899219047619,0.11163 volMatrix[4][0] = 0.117581136690647; volMatrix[4][1] = 0.115218428824572; volMatrix[4][2] = 0.113899219047619; volMatrix[4][3] = 0.11163; // 0.80587,0.114363421052632,0.112523118729097,0.111637193240265,0.11019 volMatrix[5][0] = 0.114363421052632; volMatrix[5][1] = 0.112523118729097; volMatrix[5][2] = 0.111637193240265; volMatrix[5][3] = 0.11019; //0.82034,0.111728795180723,0.110489402985075,0.109987692307692,0.10921 volMatrix[6][0] = 0.111728795180723; volMatrix[6][1] = 0.110489402985075; volMatrix[6][2] = 0.109987692307692; volMatrix[6][3] = 0.10921; // 0.83379,0.109805703883495,0.109100413723512,0.108870460584588,0.1086 volMatrix[7][0] = 0.109805703883495; volMatrix[7][1] = 0.109100413723512; volMatrix[7][2] = 0.108870460584588; volMatrix[7][3] = 0.1086; // 0.84658,0.108581646586345,0.108250493273543,0.108197213114754,0.10829 volMatrix[8][0] = 0.108581646586345; volMatrix[8][1] = 0.108250493273543; volMatrix[8][2] = 0.108197213114754; volMatrix[8][3] = 0.10829; // 0.85792,0.108190964125561,0.107986172506739,0.10796631037213,0.10822 volMatrix[9][0] = 0.108190964125561; volMatrix[9][1] = 0.107986172506739; volMatrix[9][2] = 0.10796631037213; volMatrix[9][3] = 0.10822; // 0.87354,0.10859510460251,0.108310304612707,0.108232350773766,0.10849 volMatrix[10][0] = 0.10859510460251; volMatrix[10][1] = 0.108310304612707; volMatrix[10][2] = 0.108232350773766; volMatrix[10][3] = 0.10849; // 0.89085,0.110043016488846,0.109404567049808,0.109102906403941,0.10919 volMatrix[11][0] = 0.110043016488846; volMatrix[11][1] = 0.109404567049808; volMatrix[11][2] = 0.109102906403941; volMatrix[11][3] = 0.10919; // 0.90904,0.112447321958457,0.111343238289206,0.110615417475728,0.11036 volMatrix[12][0] = 0.112447321958457; volMatrix[12][1] = 0.111343238289206; volMatrix[12][2] = 0.110615417475728; volMatrix[12][3] = 0.11036; // 0.9289,0.115567066189624,0.113888152866242,0.112830993150685,0.11201 volMatrix[13][0] = 0.115567066189624; volMatrix[13][1] = 0.113888152866242; volMatrix[13][2] = 0.112830993150685; volMatrix[13][3] = 0.11201; // 0.95157,0.119454321849106,0.117151688909342,0.115569047072331,0.11433 volMatrix[14][0] = 0.119454321849106; volMatrix[14][1] = 0.117151688909342; volMatrix[14][2] = 0.115569047072331; volMatrix[14][3] = 0.11433; // 0.97862,0.123858310308183,0.121275916334661,0.119199029605263,0.11731 volMatrix[15][0] = 0.123858310308183; volMatrix[15][1] = 0.121275916334661; volMatrix[15][2] = 0.119199029605263; volMatrix[15][3] = 0.11731; // 1.01337,0.129434558979809,0.126231870274572,0.123929902439024,0.12145 volMatrix[16][0] = 0.129434558979809; volMatrix[16][1] = 0.126231870274572; volMatrix[16][2] = 0.123929902439024; volMatrix[16][3] = 0.12145; // 1.06261,0.137335982996812,0.133099606048548,0.12994278699187,0.12723 volMatrix[17][0] = 0.137335982996812; volMatrix[17][1] = 0.133099606048548; volMatrix[17][2] = 0.12994278699187; volMatrix[17][3] = 0.12723; // 1.14631,0.150767120085016,0.144773641066454,0.140163713821138,0.13547 volMatrix[18][0] = 0.150767120085016; volMatrix[18][1] = 0.144773641066454; volMatrix[18][2] = 0.140163713821138; volMatrix[18][3] = 0.13547; return volMatrix; */ } void asian() { // Calendar set up Calendar calendar = TARGET(); Date todaysDate(4, April, 2017); Settings::instance().evaluationDate() = todaysDate; DayCounter dayCounter = Actual360(); // Option parameters Asian FX Option::Type optionType(Option::Call); Average::Type averageType = Average::Arithmetic; Date maturity(4, April, 2018); Real strike = 0.74; Volatility volatility = 0.07053702474; Date obsStart(4, March, 2018); Real runningSum = 0; Size pastFixings = 0; vector<Date> fixingDates; for (Date incrementedDate = obsStart; incrementedDate <= maturity; incrementedDate += 1) { if (calendar.isBusinessDay(incrementedDate)) { fixingDates.push_back(incrementedDate); } } // Option parameters // European Exercise boost::shared_ptr<Exercise> europeanExercise( new EuropeanExercise(maturity)); // Payoff boost::shared_ptr<StrikedTypePayoff> payoffAsianOption( new PlainVanillaPayoff(Option::Type(optionType), strike)); // Model parameters Real underlying = 0.748571186; Spread dividendYield = 0.04125; Rate riskFreeRate = 0.0225377; // Market Data // Quote handling Handle<Quote> underlyingH( boost::shared_ptr<Quote>(new SimpleQuote(underlying))); // Yield term structure handling Handle<YieldTermStructure> flatTermStructure( boost::shared_ptr<YieldTermStructure>(new FlatForward(todaysDate, dividendYield, dayCounter))); // Dividend term structure handling Handle<YieldTermStructure> flatDividendTermStructure( boost::shared_ptr<YieldTermStructure>(new FlatForward(todaysDate, riskFreeRate, dayCounter))); // Volatility structure handling: constant volatility Handle<BlackVolTermStructure> flatVolTermStructure( boost::shared_ptr<BlackVolTermStructure>(new BlackConstantVol(todaysDate, calendar, volatility, dayCounter))); // Read csv file string path = "./VolMatrixA.csv"; vector<Real> strikes = {}; GetStrikes(path, strikes); vector<Date> expirations = {}; GetExpiryDates(path, expirations); cout << "strikes.size() " << strikes.size() << endl; cout << "expirations.size() " << expirations.size() << endl; // assert csv data BOOST_ASSERT_MSG(strikes.size() > 0, static_cast<std::stringstream&>(std::stringstream() << "No valid strikes.size() found! It is " << strikes.size()).str().c_str()); BOOST_ASSERT_MSG(expirations.size() > 0, static_cast<std::stringstream&>(std::stringstream() << "No valid expirations.size() found! It is " << expirations.size()).str().c_str()); Matrix volMatrix = GetVolData(path, expirations, strikes); // Volatility Surface BlackVarianceSurface volatilitySurface(Settings::instance().evaluationDate(), calendar, expirations, strikes, volMatrix, dayCounter); volatilitySurface.setInterpolation<Bicubic>(); volatilitySurface.enableExtrapolation(true); const boost::shared_ptr<BlackVarianceSurface> volatilitySurfaceH( new BlackVarianceSurface(volatilitySurface)); Handle<BlackVolTermStructure> volTermStructure(volatilitySurfaceH); // the BS equation behind boost::shared_ptr<BlackScholesMertonProcess> bsmProcess( new BlackScholesMertonProcess(underlyingH, flatDividendTermStructure, flatTermStructure, volTermStructure)); // Options DiscreteAveragingAsianOption discreteArithmeticAsianAverageOption( averageType, runningSum, pastFixings, fixingDates, payoffAsianOption, europeanExercise); // Outputting on the screen cout << "Option type = " << optionType << endl; cout << "Option maturity = " << maturity << endl; cout << "Underlying = " << underlying << endl; cout << "Strike = " << strike << endl; cout << "Risk-free interest rate = " << setprecision(4) << io::rate(riskFreeRate) << endl; cout << "Dividend yield = " << setprecision(4) << io::rate(dividendYield) << endl; cout << "Volatility = " << setprecision(4) << io::volatility(volatility) << endl; cout << "Time-length between successive fixings = weekly time step" << endl; cout << "Previous fixings = " << pastFixings << endl; cout << setprecision(10) << endl; boost::timer timer; // Pricing engine discreteArithmeticAsianAverageOption.setPricingEngine( boost::shared_ptr<PricingEngine>( MakeMCDiscreteArithmeticAPEngine<LowDiscrepancy>(bsmProcess) .withSamples(1500))); // Timer timer.restart(); try { cout << "Discrete ArithMC Price: " << discreteArithmeticAsianAverageOption.NPV() << endl; } catch (exception const& e) { cout << "Erreur: " << e.what() << endl; } cout << " in " << timer.elapsed() << " s" << endl; timer.restart(); } int main(int, char* []) { asian(); }


QuantLib Python source code, AsianOption.py

AsianOption.py    Select all
#!python2 #!/usr/bin/env python # AsianOption.py from QuantLib import * import csv import time # Calendar set up calendar = TARGET() todaysDate = Date(4, April, 2017) Settings.instance().evaluationDate = todaysDate dayCounter = Actual360() # Option parameters Asian FX optionType = Option.Call averageType = Average.Arithmetic maturity = Date(4, April, 2018) strike = 0.74 volatility = 0.07053702474 obsStart = Date(4, March, 2018) runningSum = 0 pastFixings = 0 fixingDates = [ Date(serial) for serial in range(obsStart.serialNumber(), maturity.serialNumber()) if calendar.isBusinessDay(Date(serial)) ] # Model parameters underlying = 0.748571186 dividendYield = 0.04125 riskFreeRate = 0.0225377 #settlementDate = todaysDate # Option parameters # European Exercise europeanExercise = EuropeanExercise(maturity) # Payoff payoffAsianOption = PlainVanillaPayoff(optionType, strike) # Market Data # Quote handling underlyingH = QuoteHandle(SimpleQuote(underlying)) # Yield term structure handling flatTermStructure = YieldTermStructureHandle(FlatForward(todaysDate, dividendYield, dayCounter)) # Dividend term structure handling flatDividendTermStructure = YieldTermStructureHandle(FlatForward(todaysDate, riskFreeRate, dayCounter)) # Volatility structure handling: constant volatility flatVolTermStructure = BlackVolTermStructureHandle(BlackConstantVol(Settings.instance().evaluationDate, calendar, volatility, dayCounter)) # Read csv file with open('VolMatrixA.csv', 'rb') as f: reader = csv.reader(f) csv_list = list(reader) expirations = [ Date(int(col.split("/")[1]), int(col.split("/")[0]), int(col.split("/")[2])) for col in csv_list[0][1:] ] # expirations are on first row[0] and for second column[1:] onward strikes = [ float(row[0]) for row in csv_list[1:] ] # strikes are for second row [1:] onward and on first column [0] """ # if hardcode csv data expirations = [Date(27, June, 2017), Date(27, September, 2017), Date(27, December, 2017), Date(27, June, 2018)] strikes = [0.67263, 0.71865, 0.7487, 0.77129, 0.78984, 0.80587, 0.82034, 0.83379, 0.84658, 0.85792, 0.87354, 0.89085, 0.90904, 0.9289, 0.95157, 0.97862, 1.01337, 1.06261, 1.14631] volMatrix = [ [0.144183920277296,0.139374695503699,0.135526204819277,0.12885], [0.133703802426343,0.129893056346044,0.126909006024096,0.12175], [0.126860526863085,0.123701764371087,0.121209416342412,0.11695], [0.121720863192182,0.118881707209199,0.116979766476388,0.11381], [0.117581136690647,0.115218428824572,0.113899219047619,0.11163], [0.114363421052632,0.112523118729097,0.111637193240265,0.11019], [0.111728795180723,0.110489402985075,0.109987692307692,0.10921], [0.109805703883495,0.109100413723512,0.108870460584588,0.1086], [0.108581646586345,0.108250493273543,0.108197213114754,0.10829], [0.108190964125561,0.107986172506739,0.10796631037213,0.10822], [0.10859510460251,0.108310304612707,0.108232350773766,0.10849], [0.110043016488846,0.109404567049808,0.109102906403941,0.10919], [0.112447321958457,0.111343238289206,0.110615417475728,0.11036], [0.115567066189624,0.113888152866242,0.112830993150685,0.11201], [0.119454321849106,0.117151688909342,0.115569047072331,0.11433], [0.123858310308183,0.121275916334661,0.119199029605263,0.11731], [0.129434558979809,0.126231870274572,0.123929902439024,0.12145], [0.137335982996812,0.133099606048548,0.12994278699187,0.12723], [0.150767120085016,0.144773641066454,0.140163713821138,0.13547] ] """ # assert csv data assert len(strikes) > 0, "No valid len(strikes) found ! It is " + str(len(strikes)) assert len(expirations) > 0, "No valid len(expirations) found ! It is " + str(len(expirations)) #volMatrix = Matrix(len(strikes), len(expirations)) volMatrix = [[float(y) for y in x[1:]] for x in csv_list[1:]] # vols are for second row [1:] and for second column [1:] onward print "len(strikes) ", len(strikes) print "len(expirations) ", len(expirations) # Volatility Surface volatilitySurface = BlackVarianceSurface(Settings.instance().evaluationDate, calendar, expirations, strikes, volMatrix, dayCounter) volatilitySurface.setInterpolation("Bicubic") volatilitySurface.enableExtrapolation() volTermStructure = BlackVolTermStructureHandle(volatilitySurface) # the BS equation behind bsmProcess = BlackScholesMertonProcess(underlyingH, flatDividendTermStructure, flatTermStructure, volTermStructure) # Options discreteArithmeticAsianAverageOption = DiscreteAveragingAsianOption(averageType, runningSum, pastFixings, fixingDates, payoffAsianOption, europeanExercise) # Outputting on the screen optionTypeKeyName = dict((v,k) for k, v in vars(Option).iteritems() if v == optionType) print "Option type = ", optionTypeKeyName[optionType] print "Option maturity = ", maturity print "Underlying = ", underlying print "Strike = ", strike print "Risk-free interest rate = ", '{0:.{prec}f}%'.format(riskFreeRate*100.00, prec=4) print "Dividend yield = ", '{0:.{prec}f}%'.format(dividendYield*100.00, prec=4) print "Volatility = ", '{0:.{prec}f}%'.format(volatility*100.00, prec=4) print "Time-length between successive fixings = weekly time step" print "Previous fixings = ", pastFixings print "" # Pricing engine engine = MCDiscreteArithmeticAPEngine(bsmProcess, "LowDiscrepancy", requiredSamples=1500) discreteArithmeticAsianAverageOption.setPricingEngine(engine) # Timer start = time.time() print "Discrete ArithMC Price: ", discreteArithmeticAsianAverageOption.NPV() print ' in ' + '{0:.2f}'.format(time.time() - start), 's\n'


VolMatrixA.csv file is the data source of the Volatility Surface

VolMatrixA.csv    Select all
Strike ,6/27/2017,9/27/2017,12/27/2017,6/27/2018 0.67263,0.144183920277296,0.139374695503699,0.135526204819277,0.12885 0.71865,0.133703802426343,0.129893056346044,0.126909006024096,0.12175 0.7487,0.126860526863085,0.123701764371087,0.121209416342412,0.11695 0.77129,0.121720863192182,0.118881707209199,0.116979766476388,0.11381 0.78984,0.117581136690647,0.115218428824572,0.113899219047619,0.11163 0.80587,0.114363421052632,0.112523118729097,0.111637193240265,0.11019 0.82034,0.111728795180723,0.110489402985075,0.109987692307692,0.10921 0.83379,0.109805703883495,0.109100413723512,0.108870460584588,0.1086 0.84658,0.108581646586345,0.108250493273543,0.108197213114754,0.10829 0.85792,0.108190964125561,0.107986172506739,0.10796631037213,0.10822 0.87354,0.10859510460251,0.108310304612707,0.108232350773766,0.10849 0.89085,0.110043016488846,0.109404567049808,0.109102906403941,0.10919 0.90904,0.112447321958457,0.111343238289206,0.110615417475728,0.11036 0.9289,0.115567066189624,0.113888152866242,0.112830993150685,0.11201 0.95157,0.119454321849106,0.117151688909342,0.115569047072331,0.11433 0.97862,0.123858310308183,0.121275916334661,0.119199029605263,0.11731 1.01337,0.129434558979809,0.126231870274572,0.123929902439024,0.12145 1.06261,0.137335982996812,0.133099606048548,0.12994278699187,0.12723 1.14631,0.150767120085016,0.144773641066454,0.140163713821138,0.13547


QuantLib Python source code, Gaussian1dModels.py (Gaussian1dModels.cpp in QuantLib Examples Folder)

Gaussian1dModels.py    Select all
#!python2 #!/usr/bin/env python #Gaussian1dModels.py import QuantLib as ql def printBasket(basket): print ("%-20s %-20s %-20s %-20s %-20s %-20s" % ("Expiry", "Maturity", "Nominal", "Rate", "MarketVol", "Pay/Rec")) print ("==================================================================================================================") for i in range(0, len(basket)): expiryDate = basket[i].swaptionExpiryDate() endDate = basket[i].swaptionMaturityDate() nominal = basket[i].swaptionNominal() vol = basket[i].volatility().value() rate = basket[i].swaptionStrike() #type = basket[i].swaption.type() print ("%-20s %-20s %-20f %-20f %-20f" % (str(expiryDate), str(endDate), nominal, rate, vol)) print("==================================================================================================================") def printModelCalibration(basket, volatility): print ("%-20s %-20s %-20s %-20s %-20s %-20s" % ("Expiry","Model sigma","ModelPrice","MarketPrice","Model impVol","Market impVol")) print ("=================================================================================================================") for i in range(0, len(basket)): expiryDate = basket[i].swaptionExpiryDate() modelValue = basket[i].modelValue() marketValue= basket[i].marketValue() impVol = basket[i].impliedVolatility(modelValue, 1e-6, 1000, 0.0, 2.0) vol = basket[i].volatility().value() print ("%-20s %-20f %-20f %-20f %-20f %-20f" % (str(expiryDate), volatility[i], modelValue, marketValue, impVol, vol)) print("==================================================================================================================") refDate = ql.Date(30, 4, 2014) # Date refDate(30, April, 2014); ql.Settings.instance().setEvaluationDate(refDate) # Settings::instance().evaluationDate() = refDate; forward6mQuote = ql.QuoteHandle(ql.SimpleQuote(0.025)) # Handle<Quote> forward6mQuote(boost::make_shared(0.025)); oisQuote = ql.QuoteHandle(ql.SimpleQuote(0.02)) # Handle<Quote> oisQuote(boost::make_shared(0.02)); volQuote = ql.QuoteHandle(ql.SimpleQuote(0.2)) # Handle<Quote> volQuote(boost::make_shared(0.2)); dc = ql.Actual365Fixed() yts6m = ql.FlatForward(refDate, forward6mQuote, dc) ytsOis= ql.FlatForward(refDate, oisQuote, dc) yts6m.enableExtrapolation() ytsOis.enableExtrapolation() hyts6m = ql.RelinkableYieldTermStructureHandle(yts6m) t0_curve = ql.YieldTermStructureHandle(yts6m) t0_Ois = ql.YieldTermStructureHandle(ytsOis) euribor6m = ql.Euribor6M(hyts6m) swaptionVol = ql.ConstantSwaptionVolatility(0, ql.TARGET(), ql.ModifiedFollowing, volQuote, ql.Actual365Fixed()) # Handle<SwaptionVolatilityStructure> swaptionVol(boost::make_shared(0, TARGET(), ModifiedFollowing, volQuote, Actual365Fixed())); effectiveDate = ql.TARGET().advance(refDate, ql.Period('2D')) # Date effectiveDate = TARGET().advance(refDate, 2 * Days); maturityDate = ql.TARGET().advance(effectiveDate, ql.Period('10Y')) # Date maturityDate = TARGET().advance(effectiveDate, 10 * Years); fixedSchedule = ql.Schedule(effectiveDate, maturityDate, ql.Period('1Y'), ql.TARGET(), ql.ModifiedFollowing, ql.ModifiedFollowing, ql.DateGeneration.Forward, False) # Schedule fixedSchedule(effectiveDate, maturityDate, 1 * Years, TARGET(), ModifiedFollowing, ModifiedFollowing, DateGeneration::Forward, false); floatSchedule = ql.Schedule(effectiveDate, maturityDate, ql.Period('6M'), ql.TARGET(), ql.ModifiedFollowing, ql.ModifiedFollowing, ql.DateGeneration.Forward, False) # Schedule floatingSchedule(effectiveDate, maturityDate, 6 * Months, TARGET(), ModifiedFollowing, ModifiedFollowing, DateGeneration::Forward, false); # Vector input for the NonstandardSwap obj fixedNominal = [1 for x in range(0,len(fixedSchedule)-1)] floatingNominal = [1 for x in range(0,len(floatSchedule)-1)] strike = [0.04 for x in range(0,len(fixedSchedule)-1)] spread = [0 for x in range(0,len(floatSchedule)-1)] gearing = [1 for x in range(0,len(floatSchedule)-1)] underlying = ql.NonstandardSwap(ql.VanillaSwap.Payer, fixedNominal, floatingNominal, fixedSchedule, strike, ql.Thirty360(), floatSchedule, euribor6m, gearing, spread, ql.Actual360(), False, False, ql.ModifiedFollowing) # boost::shared_ptr<NonstandardSwap> underlying = boost::make_shared<NonstandardSwap>(VanillaSwap(VanillaSwap::Payer, 1.0, fixedSchedule, strike, Thirty360(), floatingSchedule, euribor6m, 0.00, Actual360())); exerciseDates = [ql.TARGET().advance(x, -ql.Period('2D')) for x in fixedSchedule] exerciseDates = exerciseDates[1:-1] # std::vector<Date> exerciseDates; # for (Size i = 1; i < 10; ++i) # exerciseDates.push_back(TARGET().advance(fixedSchedule[i], -2 * Days)); exercise = ql.BermudanExercise(exerciseDates) # boost::shared_ptr<Exercise> exercise = boost::make_shared<BermudanExercise>(exerciseDates, false); swaption = ql.NonstandardSwaption(underlying,exercise,ql.Settlement.Physical) # boost::shared_ptr<NonstandardSwaption> swaption = boost::make_shared<NonstandardSwaption>(underlying, exercise); stepDates = exerciseDates[:-1] # std::vector<Date> stepDates(exerciseDates.begin(), exerciseDates.end() - 1); sigmas = [ql.QuoteHandle(ql.SimpleQuote(0.01)) for x in range(1, 10)] # std::vector<Real> sigmas(stepDates.size() + 1, 0.01); reversion = [ql.QuoteHandle(ql.SimpleQuote(0.01))] # Real reversion = 0.01; gsr = ql.Gsr(t0_curve, stepDates, sigmas, reversion) # boost::shared_ptr<Gsr> gsr = boost::make_shared<Gsr>(yts6m, stepDates, sigmas, reversion); swaptionEngine = ql.Gaussian1dSwaptionEngine(gsr, 64, 7.0, True, False, t0_Ois) # boost::shared_ptr<PricingEngine> swaptionEngine = boost::make_shared<Gaussian1dSwaptionEngine>(gsr, 64, 7.0, true, false, ytsOis); nonstandardSwaptionEngine = ql.Gaussian1dNonstandardSwaptionEngine(gsr, 64, 7.0, True, False, ql.QuoteHandle(ql.SimpleQuote(0)), t0_Ois) # boost::shared_ptr<PricingEngine> nonstandardSwaptionEngine = boost::make_shared<Gaussian1dNonstandardSwaptionEngine>(gsr, 64, 7.0, true, false, Handle<Quote>(), ytsOis); swaption.setPricingEngine(nonstandardSwaptionEngine) # swaption->setPricingEngine(nonstandardSwaptionEngine); swapBase = ql.EuriborSwapIsdaFixA(ql.Period('10Y'), t0_curve, t0_Ois) # boost::shared_ptr<SwapIndex> swapBase = boost::make_shared<EuriborSwapIsdaFixA>(10 * Years, yts6m, ytsOis); basket = swaption.calibrationBasket(swapBase, swaptionVol, 'Naive') # std::vector<boost::shared_ptr<CalibrationHelper> > basket = swaption->calibrationBasket(swapBase, *swaptionVol, BasketGeneratingEngine::Naive); for i in range(0, len(basket)): basket[i].setPricingEngine(swaptionEngine) # for (Size i = 0; i < basket.size(); ++i) basket[i]->setPricingEngine(swaptionEngine); method = ql.LevenbergMarquardt() # LevenbergMarquardt method; ec = ql.EndCriteria(1000, 10, 1e-8, 1e-8, 1e-8) # EndCriteria ec(1000, 10, 1E-8, 1E-8, 1E-8); gsr.calibrateVolatilitiesIterative(basket, method, ec) # gsr->calibrateVolatilitiesIterative(basket, method, ec); printBasket(basket) printModelCalibration(basket, gsr.volatility()) npv = swaption.NPV() print(npv)


Wednesday, March 29, 2017

How to install QuantLib Python for Windows 32 in offline installation

1. Download Python 2.7 Windows x86 MSI installer from

https://www.python.org/ftp/python/2.7.13/python-2.7.13.msi

2. Download required python packages and dependencies from

http://www.lfd.uci.edu/~gohlke/pythonlibs/#quantlib

QuantLib_Python‑1.9‑cp27‑cp27m‑win32.whl

Dependencies for matplotlib and others (win32)
six‑1.10.0‑py2.py3‑none‑any.whl
pyparsing‑2.2.0‑py2.py3‑none‑any.whl
packaging‑16.8‑py2.py3‑none‑any.whl
appdirs-1.4.3-py2.py3-none-any.whl
python_dateutil‑2.6.0‑py2.py3‑none‑any.whl
pytz‑2016.10‑py2.py3‑none‑any.whl
cycler‑0.10.0‑py2.py3‑none‑any.whl
setuptools‑34.3.3‑py2.py3‑none‑any.whl

numpy‑1.11.3+mkl‑cp27‑cp27m‑win32.whl
matplotlib‑1.5.3‑cp27‑cp27m‑win32.whl
xlrd-1.0.0-py2.py3-none-any.whl
pandas-0.19.2-cp27-cp27m-win32.whl
scipy‑0.19.0‑cp27‑cp27m‑win32.whl

3. Copy the above Installers and Packages to destination machine for offline installation

4. Install Python 2.7 and add Environment Variable PATH

SET PATH=C:\Python27;C:\Python27\Scripts;%PATH%

To be persistence, use sysdm.cpl to edit Advanced -> Environment Variables -> Path

or use py -2 to run python script under Windows OS without setting PATH
py -2 chap06.py

5. Install each and every the python packages above using pip

For example
pip install QuantLib_Python‑1.9‑cp27‑cp27m‑win32.whl

or if have python2 and python3 co-exist

py -2 -m pip install QuantLib_Python‑1.9‑cp27‑cp27m‑win32.whl

6. Microsoft Visual Studio not required

and no need to build your own QuantLib-Python library
However, a code editor like Microsoft VS Code is recommended.
https://code.visualstudio.com/download
(requirement : .NET Framework 4.5.2 for Windows 7)

Offline VS code extension for python can be downloaded from
https://donjayamanne.gallery.vsassets.io/_apis/public/gallery/publisher/donjayamanne/extension/python/0.6.0/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage
see stack overflow discussion here http://stackoverflow.com/questions/37071388/how-to-install-vscode-extensions-offline

or NotePad ++
https://notepad-plus-plus.org/download/


7. Test

The code is borrowed from QuantLib Python Cookbook chapter 06 (requires QuantLib-Python, matplotlib)
chap06.py    Select all
#! python2 #!/usr/bin/env python # pylint: disable-msg=C0103 # Interest-rate Curves # Chapter 6 EONIA curve bootstrapping # Everything You Always Wanted to Know About Multiple Interest Rate Curve Bootstrapping but Were Afraid to Ask # In[1] import math # In[2] from QuantLib import * print ("\nOut[1]:") print ("QuantLib version", QuantLib.__version__) # In[3] # setup evaluationDate today = Date(11, December,2012) Settings.instance().evaluationDate = today # In[4] # setup DepositRateHelper for 0-2 days helpers = [ DepositRateHelper(QuoteHandle(SimpleQuote(rate/100)), Period(1,Days), fixingDays, TARGET(), Following, False, Actual360()) for rate, fixingDays in [(0.04, 0), (0.04, 1), (0.04, 2)] ] # DepositRateHelper (const Handle< Quote > &rate, # const Period &tenor, # Natural fixingDays, # const Calendar &calendar, # BusinessDayConvention convention, # bool endOfMonth, # const DayCounter &dayCounter) # DepositRateHelper (Rate rate, # const Period &tenor, # Natural fixingDays, # const Calendar &calendar, # BusinessDayConvention convention, # bool endOfMonth, # const DayCounter &dayCounter) # In[5] """ Eonia(const Handle< YieldTermStructure > &h=Handle< YieldTermStructure >()) Eonia (Euro Overnight Index Average) rate fixed by the ECB HKDHibor(const Period &tenor, const Handle< YieldTermStructure > &h=Handle< YieldTermStructure >()) """ eonia = Eonia() """ http://quant.stackexchange.com/questions/32345/quantlib-python-dual-curve-bootstrapping-example swap-rate helpers used to bootstrap the LIBOR curve can take a discount curve to use. In the old single-curve examples, a SwapRateHelper instance would be created as helper = SwapRateHelper(quoted_rate, tenor, calendar, fixedLegFrequency, fixedLegAdjustment, fixedLegDayCounter, Euribor6M()) and use the curve being bootstrapped for both forecast and discounting. To use dual-curve bootstrapping, instead, you'll have to build it as helper = SwapRateHelper(quoted_rate, tenor, calendar, fixedLegFrequency, fixedLegAdjustment, fixedLegDayCounter, Euribor6M(), QuoteHandle(), Period(0,Days), # needed as default value discountCurve) # the discountCurve argument would be a handle to the OIS curve that you bootstrapped previously SwapRateHelper (Rate rate, const Period &tenor, const Calendar &calendar, Frequency fixedFrequency, BusinessDayConvention fixedConvention, const DayCounter &fixedDayCount, const boost::shared_ptr< IborIndex > &iborIndex, const Handle< Quote < &spread=Handle< Quote >(), const Period &fwdStart=0 *Days, const Handle< YieldTermStructure > &discountingCurve=Handle< YieldTermStructure >()) In the above, the additional QuoteHandle() and Period(0,Days) arguments are, unfortunately, needed because the SWIG wrappers don't support keyword arguments for this constructor; and the discountCurve argument would be a handle to the OIS curve that you bootstrapped previously. When the swap-rate helpers are instantiated as above, they will use the LIBOR curve being bootstrapped for forecast and the OIS curve for discounting. """ # In[6] # Overnight Index Swap rate # setup OISRateHelper for 1,2,3 weeks and 1 month helpers += [ OISRateHelper(2, Period(*tenor), QuoteHandle(SimpleQuote(rate/100)), eonia) for rate, tenor in [(0.070, (1,Weeks)), (0.069, (2,Weeks)), (0.078, (3,Weeks)), (0.074, (1,Months))] ] # In[7] """ DatedOISRateHelper(const Date &startDate, const Date &endDate, const Handle< Quote > &fixedRate, const boost::shared_ptr< OvernightIndex > &overnightIndex) """ # setup DatedOISRateHelper helpers += [ DatedOISRateHelper(start_date, end_date, QuoteHandle(SimpleQuote(rate/100)), eonia) for rate, start_date, end_date in [(0.046, Date(16,January,2013), Date(13,February,2013)), (0.016, Date(13,February,2013), Date(13,March,2013)), (-0.007, Date(13,March,2013), Date(10,April,2013)), (-0.013, Date(10,April,2013), Date(8,May,2013)), (-0.014, Date(8,May,2013), Date(12,June,2013))] ] # In[8] """ Overnight Index Swap rate OISRateHelper(Natural settlementDays, const Period &tenor, const Handle< Quote > &fixedRate, const boost::shared_ptr< OvernightIndex > &overnightIndex) """ # setup OISRateHelper from 15 months to 30 years helpers += [ OISRateHelper(2, Period(*tenor), QuoteHandle(SimpleQuote(rate/100)), eonia) for rate, tenor in [(0.002, (15,Months)), (0.008, (18,Months)), (0.021, (21,Months)), (0.036, (2,Years)), (0.127, (3,Years)), (0.274, (4,Years)), (0.456, (5,Years)), (0.647, (6,Years)), (0.827, (7,Years)), (0.996, (8,Years)), (1.147, (9,Years)), (1.280, (10,Years)), (1.404, (11,Years)), (1.516, (12,Years)), (1.764, (15,Years)), (1.939, (20,Years)), (2.003, (25,Years)), (2.038, (30,Years))] ] # In[9] eonia_curve_c = PiecewiseLogCubicDiscount(0, TARGET(), helpers, Actual365Fixed()) """ # QuantLib-SWIG/SWIG/piecewiseyieldcurve.i %define export_piecewise_curve(Name, Base, Interpolator) export_piecewise_curve(PiecewiseLogCubicDiscount, Discount, MonotonicLogCubic); PiecewiseYieldCurve<Base,Interpolator>( settlementDays, # Integer settlementDays, calendar, # const Calendar& calendar, instruments, # const std::vector<boost::shared_ptr<RateHelper> >& instruments, dayCounter, # const DayCounter& dayCounter, jumps, # const std::vector<Handle<Quote> >& jumps=std::vector<Handle<Quote> >(), jumpDates, # const std::vector<Date>& jumpDates = std::vector<Date>(), accuracy, # Real accuracy = 1.0e-12, i # const Interpolator& i = Interpolator() ) """ eonia_curve_c.enableExtrapolation() # In[10] today = eonia_curve_c.referenceDate() end = today+Period(2,Years) dates = [ Date(serial) for serial in range(today.serialNumber(), end.serialNumber()+1) ] rates_c = [ eonia_curve_c.forwardRate(d, TARGET().advance(d, 1, Days), Actual360(), Simple).rate()*100 for d in dates ] # In[11] import matplotlib.pyplot as plt plt.title("Multiple Interest Rate Curve Bootstrapping") plt.plot(rates_c, '-') plt.ylabel('Rates') plt.show() # get spot rates spots = [] tenors = [] today = eonia_curve_c.referenceDate() end = today+Period(2,Years) dates = [ Date(serial) for serial in range(today.serialNumber(), end.serialNumber()+1) ] #for d in eonia_curve_c.dates(): # return boost::dynamic_pointer_cast<Name>(*self)->dates(); for d in dates: day_count = Actual360() yrs = day_count.yearFraction(today, d) compounding = Simple freq = Annual zero_rate = eonia_curve_c.zeroRate(yrs, compounding, freq) tenors.append(yrs) eq_rate = zero_rate.equivalentRate(day_count, compounding, freq, today, d).rate() spots.append(100*eq_rate) plt.title('Discount Curve') plt.plot(tenors[1::], spots[1::], linewidth=2.0) plt.xlabel('tenor (Y)') plt.ylabel('spot (%)') plt.show()





8. Test2, requires QuantLib, numpy, scipy, matplotlib

The code is borrowed from QuantLib Python Cookbook chapter 13
chap13.py    Select all
#! python2 #!/usr/bin/env python # pylint: disable-msg=C0103 # Interest-rate Models # Chapter 13 Thoughts on the Convergence of Hull-White Model Monte-Carlo Simulations # In[1] import QuantLib as ql print ("\nOut[1]:") print ("QuantLib version", ql.__version__) import matplotlib.pyplot as plt import numpy as np from scipy.integrate import simps, cumtrapz, romb # % matplotlib inline import math todays_date = ql.Date(15, 1, 2015) ql.Settings.instance().evaluationDate = todays_date # In[2] # <!-- collapse=True --> def get_path_generator(timestep, hw_process, length, low_discrepancy=False, brownian_bridge=True): """ Returns a path generator The `get_path_generator` function creates the a path generator. This function takes various inputs such as """ if low_discrepancy: usg = ql.UniformLowDiscrepancySequenceGenerator(timestep) rng = ql.GaussianLowDiscrepancySequenceGenerator(usg) seq = ql.GaussianSobolPathGenerator( hw_process, length, timestep, rng,brownian_bridge) else: usg = ql.UniformRandomSequenceGenerator(timestep, ql.UniformRandomGenerator()) rng = ql.GaussianRandomSequenceGenerator(usg) seq = ql.GaussianPathGenerator( hw_process, length, timestep, rng, brownian_bridge) return seq # In[3] # <!-- collapse=True --> def generate_paths(num_paths, timestep, seq): """ The `generate_paths` function uses the generic path generator produced by the `get_path_generator` function to return a tuple of the array of the points in the time grid and a matrix of the short rates generated." """ arr = np.zeros((num_paths, timestep+1)) for i in range(num_paths): sample_path = seq.next() path = sample_path.value() time = [path.time(j) for j in range(len(path))] value = [path[j] for j in range(len(path))] arr[i, :] = np.array(value) return np.array(time), arr # In[4] # <!-- collapse=True --> def generate_paths_zero_price(spot_curve_handle, a, sigma, timestep, length, num_paths, avg_grid_array, low_discrepancy=False, brownian_bridge=True): """ This function returns a tuple (T_array, F_array), where T_array is the array of points in the time grid, and F_array is the array of the average of zero prices observed from the simulation. The `generate_paths_zero_price` essentially is a wrapper around `generate_path_generator` and `generate_paths` taking all the required raw inputs. This function returns the average of zero prices from all the paths for different points in time. I wrote this out so that I can conveniently change all the required inputs and easily plot the results." """ hw_process = ql.HullWhiteProcess(spot_curve_handle, a, sigma) seq = get_path_generator( timestep, hw_process, length, low_discrepancy, brownian_bridge ) time, paths = generate_paths(num_paths, timestep, seq) avgs = [(time[j], (np.mean([math.exp(-simps(paths[i][0:j], time[0:j])) for i in range(num_paths)]))) for j in avg_grid_array ] return zip(*avgs) def generate_paths_discount_factors(spot_curve_handle, a, sigma, timestep, length, num_paths, avg_grid_array, low_discrepancy=False, brownian_bridge=True): """ This function returns a tuple (T_array, S_matrix), where T_array is the array of points in the time grid, and S_matrix is the matrix of the spot rates for each path in the different points in the time grid. """ hw_process = ql.HullWhiteProcess(spot_curve_handle, a, sigma) seq = get_path_generator( timestep, hw_process, length, low_discrepancy, brownian_bridge ) time, paths = generate_paths(num_paths, timestep, seq) arr = np.zeros((num_paths, len(avg_grid_array))) for i in range(num_paths): arr[i, :] = [np.exp(-simps(paths[i][0:j], time[0:j])) for j in avg_grid_array ] t_array = [time[j] for j in avg_grid_array] return t_array, arr def V(t,T, a, sigma): """ Variance of the integral of short rates, used below """ return sigma*sigma/a/a*(T-t + 2.0/a*math.exp(-a*(T-t)) - 1.0/(2.0*a)*math.exp(-2.0*a*(T-t)) - 3.0/(2.0*a) ) # In[5] # <!-- collapse=True --> # Here we vary sigma with fixed a and observe the error epsilon # define constants num_paths = 500 sigma_array = np.arange(0.01,0.1,0.03) a = 0.1 timestep = 180 length = 15 # in years forward_rate = 0.05 day_count = ql.Thirty360() avg_grid_array = np.arange(12, timestep+1, 12) # generate spot curve spot_curve = ql.FlatForward( todays_date, ql.QuoteHandle(ql.SimpleQuote(forward_rate)), day_count ) spot_curve_handle = ql.YieldTermStructureHandle(spot_curve) #initialize plots figure, axis = plt.subplots() plots = [] zero_price_theory = np.array([spot_curve.discount(j*float(length)/float(timestep)) for j in avg_grid_array]) for sigma in sigma_array: term, zero_price_empirical = generate_paths_zero_price( spot_curve_handle, a, sigma, timestep, length, num_paths, avg_grid_array ) plots += axis.plot( term, np.abs(zero_price_theory - np.array(zero_price_empirical)), lw=2, alpha=0.6, label="$\sigma=$"+str(sigma) ) # plot legend labels = [p.get_label() for p in plots] legend =axis.legend(plots,labels, loc=0)#, loc=0, bbox_to_anchor=(1.1,0.4)) axis.set_xlabel("T (years)", size=12) axis.set_ylabel("|$\epsilon(T)$|", size=12) axis.set_title("Out[5]:Discount Factor Error for $a=$%0.2f and Varying $\sigma$"%a, size=14) plt.show() # In[6] # <!-- collapse=True --> # Here we vary a with fixed sigma and observe the error epsilon # define constants num_paths = 500 sigma = 0.1 a_array = np.arange(0.1, 0.51, 0.1) timestep = 180 length = 15 # in years forward_rate = 0.05 day_count = ql.Thirty360() avg_grid_array = np.arange(12, timestep+1, 12) # generate spot curve spot_curve = ql.FlatForward( todays_date, ql.QuoteHandle(ql.SimpleQuote(forward_rate)), day_count ) spot_curve_handle = ql.YieldTermStructureHandle(spot_curve) #initialize plots figure, axis = plt.subplots() plots = [] zero_price_theory = np.array([spot_curve.discount(j*float(length)/float(timestep)) for j in avg_grid_array]) for a in a_array: term, zero_price_empirical = generate_paths_zero_price( spot_curve_handle, a, sigma, timestep, length, num_paths, avg_grid_array ) plots += axis.plot( term,np.abs(zero_price_theory - np.array(zero_price_empirical)), lw=2, alpha=0.6, label="a="+str(a) ) # plot legend labels = [p.get_label() for p in plots] legend =axis.legend(plots,labels, loc=0)#, loc=0, bbox_to_anchor=(1.1,0.4)) axis.set_xlabel("T (years)", size=12) axis.set_ylabel("|$\\epsilon(T)$|", size=12) axis.set_title("Out[6]:Discount Factor Error for $\sigma$=%0.2f and Varying $a$"%sigma, size=14) plt.show() # In[7] # <!-- collapse=True --> #define constants num_paths = 500 sigma = 0.02 a = 0.1 timestep = 180 length = 15 # in years forward_rate = 0.05 day_count = ql.Thirty360() avg_grid_array = np.arange(1, timestep+1, 12) # generate spot curve spot_curve = ql.FlatForward( todays_date, ql.QuoteHandle(ql.SimpleQuote(forward_rate)), day_count ) spot_curve_handle = ql.YieldTermStructureHandle(spot_curve) term, discount_factor_matrix = generate_paths_discount_factors( spot_curve_handle, a, sigma, timestep, length, num_paths, avg_grid_array ) vol = [np.var(discount_factor_matrix[:, i]) for i in range(len(term))] l1 = plt.plot(term, 100*np.sqrt(vol),"b", lw=2, alpha=0.6, label="Empirical") vol_theory = [100*np.sqrt(math.exp(V(0,T,a, sigma))-1.0) * spot_curve_handle.discount(T) for T in term] l2 = plt.plot(term, vol_theory,"r--", lw=2, alpha=0.6, label="Theory") plots = l1+l2 labels = [p.get_label() for p in plots] legend =plt.legend(plots,labels, loc=0) plt.xlabel("Time (Years)", size=12) plt.ylabel("$\sigma_D(0,T)$ (%)", size=12) plt.title("Out[7]:Standard Deviation of Discount Factors " "(a=%0.2f, $\sigma$=%0.2f)"%(a, sigma), size=14) plt.show()




9. Test3, requires QuantLib, numpy, panda, xlrd

The code is using QuantLib, numpy, panda and xlrd to read xls data
testreadxls.py    Select all
#! python2 #!/usr/bin/env python # pylint: disable-msg=C0103 # pylint: disable-msg=C0301 # testreadxls.py import os import pandas import numpy as np import QuantLib as ql xls_file = os.path.dirname(os.path.realpath(__file__)) + '/usd_market_data_2016-07-13.xls' #alternate way to mount google drive and read xlsx file data #import os #from google.colab import drive #drive.mount('/content/drive') #xls_file = '/content/drive/My Drive/usd_market_data_2016-07-13.xlsx' # if the file is in csv format #csv_file = '/content/drive/My Drive/usd_market_data_2016-07-13.csv' #csv = pandas.read_csv(csv_file) #print("\nCSV data\n") #print(csv) #print (csv.loc[:, 'dates']) #print (csv.iloc[0:, 1]) #discounts_csv = np.array(csv.iloc[0:,1].tolist()) #print(discounts_csv) xl = pandas.ExcelFile(xls_file) print (xl.sheet_names) #df = xl.parse("usdstd") #df = xl.parse(0) # alternate way to read first worksheet filename = xls_file sheetname = 'usdois' sheet = pandas.read_excel(filename, sheetname) # Read an Excel table into a pandas DataFrame #sheet = pandas.read_excel(filename, 0) # alternate way to read first worksheet instead of name print (sheet.columns) #tenors = np.array([Date.from_timestamp(d).t for d in sheet['dates']]) today = ql.Date(21,3,2016) act365 = ql.Actual365Fixed() dates = np.array([ql.Date(d.day, d.month, d.year) for d in sheet['dates']]) #dates = np.array([ql.Date(d.day, d.month, d.year) for d in df.iloc[0:,0]]) # use iloc to read first column, all rows print ("\nusd_market_data_2016-07-13.xls dates column") print (dates) tenors = np.array([act365.yearFraction(today,ql.Date(d.day, d.month, d.year)) for d in sheet['dates']]) print ("\nusd_market_data_2016-07-13.xls dates column convert to tenor") print (tenors) print ("\nusd_market_data_2016-07-13.xls discounts column") discounts = np.array(sheet['discounts'].tolist()) #discounts = np.array(df.iloc[0:,1].tolist()) # use iloc to read second column, all rows print (discounts)


Assume the usd_market_data_2016-07-13.xls sheet usdois (first worksheet) has the following data
https://mega.nz/#!m4Bh2TJD!KVZbvAn4D_sSR8-FYJtNASkiWvY2TWZ1LokJ-vcw-u4


10. Test3, requires QuantLib, pandas, matplotlib

The code demonstrates the download of Interest Rate xml market data from markit.com and Bootstrapping IR Curve in QuantLib
test_xml_download.py    Select all
#!python2 #!/usr/bin/env python # pylint: disable-msg=C0103 # pylint: disable-msg=C0301 # test_xml_download.py from QuantLib import * print ("\nQuantLib version", QuantLib.__version__) import urllib import zipfile import xml.etree.ElementTree as ET import pandas as pd import datetime as dt from matplotlib.dates import YearLocator, MonthLocator, DateFormatter from matplotlib.ticker import FuncFormatter import sys if sys.version_info[0] >= 3: from urllib.request import urlretrieve else: # Not Python 3 - today, it is most likely to be Python 2 # But note that this might need an update when Python 4 # might be around one day from urllib import urlretrieve def to_datetime(d): """ to_datetime """ return dt.datetime(d.year(), d.month(), d.dayOfMonth()) def format_rate(r, p=2): """ format_rate """ return '{0:.{prec}f}%'.format(r*100.00, prec=p) period_dict = {str(k)+'M': (k, Months) for k in range(1, 12, 1)} d2 = {str(k)+'Y': (k, Years) for k in range(1, 50, 1)} period_dict.update(d2) (ir_currency, ir_date) = ('USD', '20170331') url = 'https://www.markit.com/news/InterestRates_%s_%s.zip' % (ir_currency, ir_date) #filehandle, _ = urllib.urlretrieve(url) filehandle, _ = urlretrieve(url) zip_file_object = zipfile.ZipFile(filehandle, 'r') interest_rate_file = zip_file_object.open(zip_file_object.namelist()[1]) content = interest_rate_file.read() #print (content) root = ET.fromstring(content) print ("\nInfo on InterestRates_%s_%s" % (ir_currency, ir_date)) for a in [root.find(b) for b in ['./currency', './effectiveasof', './deposits/daycountconvention', './deposits/snaptime', './deposits/spotdate', './swaps/fixeddaycountconvention', './swaps/floatingdaycountconvention', './swaps/snaptime', './swaps/spotdate']]: print (a.tag, a.text) effectiveasof = root.find('./effectiveasof').text currency = root.find('./currency').text today = DateParser.parseFormatted(effectiveasof, '%Y-%m-%d') Settings.instance().evaluationDate = today print ("\nDeposit Rates") deposits_maturitydates = [a.text for a in root.findall('.//deposits/curvepoint/maturitydate')] deposits_parrates_text = [a.text for a in root.findall('.//deposits/curvepoint/parrate')] deposits_tenors = [a.text for a in root.findall('.//deposits/curvepoint/tenor')] deposits_periods = [period_dict[a] for a in deposits_tenors] print (pd.DataFrame(zip(deposits_tenors, deposits_maturitydates, map(float, deposits_parrates_text)), columns=('Tenor', 'Maturity', 'Parrate'))) maturity_dict = {} for t, m in zip(deposits_tenors, deposits_maturitydates): d = {t: m} maturity_dict.update(d) print ("\nSwap Rates") swaps_maturitydates = [a.text for a in root.findall('.//swaps/curvepoint/maturitydate')] swaps_parrates_text = [a.text for a in root.findall('.//swaps/curvepoint/parrate')] swaps_tenors = [a.text for a in root.findall('.//swaps/curvepoint/tenor')] swaps_periods = [period_dict[a] for a in swaps_tenors] print (pd.DataFrame(zip(swaps_tenors, swaps_maturitydates, map(float, swaps_parrates_text)), columns=('Tenor', 'Maturity', 'Parrate'))) for t, m in zip(swaps_tenors, swaps_maturitydates): d = {t: m} maturity_dict.update(d) #print (maturity_dict) euribor6m = Euribor6M() helpers = [DepositRateHelper(rate, Period(*tenor), 2, TARGET(), Following, False, Actual360()) for tenor, rate in zip(deposits_periods, map(float, deposits_parrates_text))] helpers += [SwapRateHelper(rate, Period(*tenor), TARGET(), Semiannual, Unadjusted, Thirty360(), euribor6m) for tenor, rate in zip(swaps_periods, map(float, swaps_parrates_text))] curve = PiecewiseLogCubicDiscount(2, TARGET(), helpers, Actual360()) curve.enableExtrapolation() spot = curve.referenceDate() #dates = [spot+Period(i,Months) for i in range(0, 30*12+1)] dates = [spot+Period(i, Years) for i in range(0, 30)] rates = [curve.forwardRate(d, euribor6m.maturityDate(d), Actual360(), Simple).rate() for d in dates] valid_dates = [d for d in dates if d >= spot] import matplotlib.pyplot as plt fig, ax = plt.subplots() fig.autofmt_xdate() ax.plot_date([to_datetime(d) for d in valid_dates], rates, '-') ax.set_xlim(to_datetime(min(dates)), to_datetime(max(dates))) ax.xaxis.set_major_locator(YearLocator(2, month=today.month(), day=today.dayOfMonth())) ax.xaxis.set_major_formatter(DateFormatter("%Y")) ax.xaxis.grid(True, 'major') ax.xaxis.grid(False, 'minor') ax.yaxis.set_major_formatter(FuncFormatter(lambda r, pos: format_rate(r))) plt.title("%s Interest Rate Curve Bootstrapping, effective %s" % (currency, effectiveasof)) plt.xlabel('Year') plt.ylabel('Rates') plt.show()






11. Compile QuantLib Python 1.10 for Mac

script.sh    Select all
# install Xcode and HomeBrew # ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" # install boost brew install boost # Download QuantLib-1.10 cd $(HOME)/Downloads wget --no-check-certificate https://jaist.dl.sourceforge.net/project/quantlib/test/QuantLib-1.10.tar.gz tar xzvf QuantLib-1.10.tar.gz # Compile QuantLib 1.10 cd QuantLib-1.10 ./configure --prefix=/usr/local/ CXXFLAGS='-O2 -stdlib=libstdc++ -mmacosx-version-min=10.6' LDFLAGS='-stdlib=libstdc++ -mmacosx-version-min=10.6' make && sudo make install # test compile c++ g++ Bonds.cpp -std=c++11 -stdlib=libstdc++ -o Bonds -lQuantLib ./Bonds # Download QuantLib-SWIG 1.10 cd $(HOME)/Downloads wget --no-check-certificate https://jaist.dl.sourceforge.net/project/quantlib/test/QuantLib-SWIG-1.10.tar.gz tar xzvf QuantLib-SWIG-1.10.tar.gz # Compile QuantLib Python cd QuantLib-SWIG-1.10 ./configure CXXFLAGS='-O2 -stdlib=libstdc++ -mmacosx-version-min=10.6' make -C Python make -C Python check sudo make -C Python install # Package wheel file sudo -H python pip install setuptools wheel cd $(HOME)/Downloads/QuantLib-SWIG-1.10/Python # Modify setup.py and replace from distutils.core import setup, Extension # By try: from setuptools import setup, Extension except: from distutils.core import setup, Extension # python 2 wheel file python setup.py bdist_wheel ls dist/ # python 3 wheel file LDFLAGS="-arch x86_64 -bundle -flat_namespace -undefined suppress" CFLAGS="-fno-strict-aliasing -Wsign-compare -fno-common -static -arch x86_64 -Wno-shorten-64-to-32" python3 setup.py bdist_wheel ls dist/


QuantLib_Python-1.10-cp27-cp27m-macosx_10_10_intel.whl download

QuantLib_Python-1.10-cp36-cp36m-macosx_10_6_intel.whl download
For Python3, have to install libQuantLib to /usr/local/lib
cd /usr/local/lib
sudo tar xzvf ~/Download/libQuantLib.tgz
Download libQuantLib.tgz here https://mega.nz/#!rpJg0B6T!NlG3Ijgo0weNOi_CVOkCzpGCMRqHZkWSeF3S0sAR12o



12. For Windows 64-bit, Regeneration of python SWIG interface method
If you need to edit the SWIG interface file and add functionality in QuantLib Python, you need to regenerate.


script.cmd    Select all
# First, compile QuantLib using Visual Studio 2015. # Select 21 projects and right click select Property -> All Configurations Add C:\local\boost_1_59_0; to the Property Pages : VC++ Include directories to win32 platform and Add C:\local\boost_1_59_0\lib32-msvc-14.0; to the VC++ Libs directories to win32 platform # Select All Configurations Add C:\local\boost_1_59_0_64; to the Property Pages : VC++ Include directories to x64 platform and Add C:\local\boost_1_59_0_64\lib64-msvc-14.0; to the VC++ Libs directories to x64 platform # Add /wd4819 to Command Line : Additional Options to disable C4819 warnings when compiling Quantlib to both win32 and x64 platform # Build Release x64 Solution or Release win32 Solution. # setting of QuantLib Project directory, e.g. SET QL_DIR=C:\local\QuantLib-1.10\QuantLib-1.10 # or alternatively, edit the setup.py # QL_INSTALL_DIR = r'C:\local\QuantLib-1.10\QuantLib-1.10' # setting of compiled libraries location for QuantLib ('QuantLib-vc140-x64-mt.lib') and Boost, e.g. for x64 platform SET LIB=C:\local\boost_1_59_0_64\lib64-msvc-14.0 # setting of Boost Project directory, e.g. SET INCLUDE=C:\local\boost_1_59_0_64 # setting of SWIGWIN.exe PATH, e.g. SET PATH=C:\local\swigwin-3.0.12;%PATH% # setting of VISUAL STUDIO 2015 (Version 14) SET VS90COMNTOOLS=%VS140COMNTOOLS% # Edit SWIG interface file if any C:\local\QuantLib-1.10\QuantLib-SWIG-1.10\SWIG\*.i # e.g. edit piecewiseyieldcurve.i and add at the end # export_piecewise_curve(PiecewiseLogLinearDiscount,Discount,LogLinear); # Wrap the edited interface file again after edit py -2 setup.py wrap # compile using msvc # need to edit setup.py to add ,'/wd4819' to the extra_compile_args to disable warnings py -2 setup.py build --compiler=msvc # must use Administrator Command Prompt to install py -2 -m setup.py install --skip-build # generation of wheel file is same as above that is modify setup.py first # need to install setuptools and wheel py -2 -m pip install setuptools wheel py -2 setup.py test py -2 setup.py bdist_wheel dir dist


Visual Studio 2015 setup https://mega.nz/#!70ZwyARa!z4et3sKwguU16tEbCYTdwBC1VEkNJTTakryrDRBSKM8


Sunday, November 13, 2016

How to build C++ static libraries (boost and QuantLib) for Android Studio

(1) Create standalone toolchain for Android in Mac
shell script    Select all
#create standalone toolchain for x86, x86_64, arm and arm64 #assume ndk is installed in Mac at ~/Library/Android/sdk/ndk-bundle #API level will be set to the minimum supported level for the given architecture (currently 9 for 32-bit architectures and 21 for 64-bit architectures) ~/Library/Android/sdk/ndk-bundle/build/tools/make_standalone_toolchain.py --arch x86 --install-dir ~/Library/Android/sdk/ndk-bundle/sources/android-toolchain-x86 ~/Library/Android/sdk/ndk-bundle/build/tools/make_standalone_toolchain.py --arch x86_64 --install-dir ~/Library/Android/sdk/ndk-bundle/sources/android-toolchain-x86_64 ~/Library/Android/sdk/ndk-bundle/build/tools/make_standalone_toolchain.py --arch arm --install-dir ~/Library/Android/sdk/ndk-bundle/sources/android-toolchain-arm ~/Library/Android/sdk/ndk-bundle/build/tools/make_standalone_toolchain.py --arch arm64 --install-dir ~/Library/Android/sdk/ndk-bundle/sources/android-toolchain-arm64


(2) Download and build boost for Android
shell script    Select all
# download boost source to ndk-bundle cd ~/Library/Android/sdk/ndk-bundle/sources curl -O http://ncu.dl.sourceforge.net/project/boost/boost/1.62.0/boost_1_62_0.tar.bz2 tar xjvf boost_1_62_0.tar.bz2 cd boost_1_62_0 # create the following user-config.jam at ~/Library/Android/sdk/ndk-bundle/sources/boost_1_62_0/tools/build/src/ cat > tools/build/src/user-config.jam << 'EOF' # ------------------ # Android configurations. # ------------------ import os ; local NDK_ROOT = [ os.environ NDK_ROOT ] ; # -------------------------------------------------------------------- local ANDROID_TOOLCHAIN_x86 = /sources/android-toolchain-x86 ; using gcc : x86 : $(NDK_ROOT)$(ANDROID_TOOLCHAIN_x86)/bin/i686-linux-android-g++ : <archiver>$(NDK_ROOT)$(ANDROID_TOOLCHAIN_x86)/bin/i686-linux-android-ar <compileflags>-fexceptions <compileflags>-frtti <compileflags>-fpic <compileflags>-ffunction-sections <compileflags>-funwind-tables <compileflags>-Wno-psabi <compileflags>-Wno-missing-field-initializers <compileflags>-no-canonical-prefixes <linkflags>-no-canonical-prefixes <compileflags>-Os <compileflags>-fomit-frame-pointer <compileflags>-fno-strict-aliasing <compileflags>-funswitch-loops <compileflags>-finline-limit=300 <compileflags>-Wa,--noexecstack <compileflags>-DANDROID <compileflags>-D__ANDROID__ <compileflags>-DNDEBUG <compileflags>-O2 <compileflags>-g <root>$(NDK_ROOT)$(ANDROID_TOOLCHAIN_x86)/sysroot # @Moss - Above are the 'official' android flags <architecture>x86 <compileflags>-fvisibility=hidden <compileflags>-fvisibility-inlines-hidden <compileflags>-fdata-sections <cxxflags>-D_REENTRANT <cxxflags>-D_GLIBCXX__PTHREADS <compileflags>-Wno-long-long <compileflags>-Wno-missing-field-initializers <compileflags>-Wno-unused-variable ; # -------------------------------------------------------------------- local ANDROID_TOOLCHAIN_x86_64 = /sources/android-toolchain-x86_64 ; using gcc : x86_64 : $(NDK_ROOT)$(ANDROID_TOOLCHAIN_x86_64)/bin/x86_64-linux-android-g++ : <archiver>$(NDK_ROOT)$(ANDROID_TOOLCHAIN_x86_64)/bin/x86_64-linux-android-ar <compileflags>-fexceptions <compileflags>-frtti <compileflags>-fpic <compileflags>-ffunction-sections <compileflags>-funwind-tables <compileflags>-Wno-psabi <compileflags>-Wno-missing-field-initializers <compileflags>-no-canonical-prefixes <linkflags>-no-canonical-prefixes <compileflags>-Os <compileflags>-fomit-frame-pointer <compileflags>-fno-strict-aliasing <compileflags>-funswitch-loops <compileflags>-finline-limit=300 <compileflags>-Wa,--noexecstack <compileflags>-DANDROID <compileflags>-D__ANDROID__ <compileflags>-DNDEBUG <compileflags>-O2 <compileflags>-g <root>$(NDK_ROOT)$(ANDROID_TOOLCHAIN_x86_64)/sysroot # @Moss - Above are the 'official' android flags <architecture>x86 <compileflags>-fvisibility=hidden <compileflags>-fvisibility-inlines-hidden <compileflags>-fdata-sections <cxxflags>-D_REENTRANT <cxxflags>-D_GLIBCXX__PTHREADS <compileflags>-Wno-long-long <compileflags>-Wno-missing-field-initializers <compileflags>-Wno-unused-variable ; # -------------------------------------------------------------------- local ANDROID_TOOLCHAIN_ARM = /sources/android-toolchain-arm ; using gcc : armeabi : $(NDK_ROOT)$(ANDROID_TOOLCHAIN_ARM)/bin/arm-linux-androideabi-g++ : <archiver>$(NDK_ROOT)$(ANDROID_TOOLCHAIN_ARM)/bin/arm-linux-androideabi-ar <compileflags>-fexceptions <compileflags>-frtti <compileflags>-fpic <compileflags>-ffunction-sections <compileflags>-funwind-tables <compileflags>-D__ARM_ARCH_5__ <compileflags>-D__ARM_ARCH_5T__ <compileflags>-D__ARM_ARCH_5E__ <compileflags>-D__ARM_ARCH_5TE__ <compileflags>-Wno-psabi <compileflags>-march=armv5te <compileflags>-mtune=xscale <compileflags>-msoft-float <compileflags>-mthumb <linkflags>-march=armv5te <compileflags>-Os <compileflags>-fomit-frame-pointer <compileflags>-fno-strict-aliasing <compileflags>-finline-limit=64 <compileflags>-Wa,--noexecstack <compileflags>-DANDROID <compileflags>-D__ANDROID__ <compileflags>-DNDEBUG <compileflags>-O2 <compileflags>-g <root>$(NDK_ROOT)$(ANDROID_TOOLCHAIN_ARM)/sysroot # @Moss - Above are the 'official' android flags <architecture>arm <compileflags>-fvisibility=hidden <compileflags>-fvisibility-inlines-hidden <compileflags>-fdata-sections <cxxflags>-D_REENTRANT <cxxflags>-D_GLIBCXX__PTHREADS <compileflags>-Wno-long-long <compileflags>-Wno-missing-field-initializers <compileflags>-Wno-unused-variable ; # -------------------------------------------------------------------- using gcc : armeabi_v7a : $(NDK_ROOT)$(ANDROID_TOOLCHAIN_ARM)/bin/arm-linux-androideabi-g++ : <archiver>$(NDK_ROOT)$(ANDROID_TOOLCHAIN_ARM)/bin/arm-linux-androideabi-ar <compileflags>-fexceptions <compileflags>-frtti <compileflags>-fpic <compileflags>-ffunction-sections <compileflags>-funwind-tables <compileflags>-Wno-psabi <compileflags>-march=armv7-a <compileflags>-msoft-float <compileflags>-mfpu=neon <compileflags>-mthumb <linkflags>-march=armv7-a <linkflags>-Wl,--fix-cortex-a8 <compileflags>-Os <compileflags>-fomit-frame-pointer <compileflag>-fno-strict-aliasing <compileflags>-finline-limit=64 <compileflags>-Wa,--noexecstack <compileflags>-DANDROID <compileflags>-D__ANDROID__ <compileflags>-DNDEBUG <compileflags>-O2 <compileflags>-g <root>$(NDK_ROOT)$(ANDROID_TOOLCHAIN_ARM)/sysroot # @Moss - Above are the 'official' android flags <architecture>arm <compileflags>-fvisibility=hidden <compileflags>-fvisibility-inlines-hidden <compileflags>-fdata-sections <cxxflags>-D__arm__ <cxxflags>-D_REENTRANT <cxxflags>-D_GLIBCXX__PTHREADS <compileflags>-Wno-long-long <compileflags>-Wno-missing-field-initializers <compileflags>-Wno-unused-variable ; # -------------------------------------------------------------------- local ANDROID_TOOLCHAIN_ARM64 = /sources/android-toolchain-arm64 ; using gcc : arm64_v8a : $(NDK_ROOT)$(ANDROID_TOOLCHAIN_ARM64)/bin/aarch64-linux-android-g++ : <archiver>$(NDK_ROOT)$(ANDROID_TOOLCHAIN_ARM64)/bin/aarch64-linux-android-ar <compileflags>-fexceptions <compileflags>-frtti <compileflags>-fpic <compileflags>-ffunction-sections <compileflags>-funwind-tables <compileflags>-fstack-protector <compileflags>-Wno-psabi <compileflags>-march=armv8-a <compileflags>-mtune=cortex-a53 <linkflags>-march=armv8-a <compileflags>-Os <compileflags>-fno-short-enums <compileflags>-fomit-frame-pointer <compileflags>-fno-strict-aliasing <compileflags>-finline-limit=64 <compileflags>-DANDROID <compileflags>-D__ANDROID__ <compileflags>-DNDEBUG <compileflags>-O2 <compileflags>-g <root>$(NDK_ROOT)$(ANDROID_TOOLCHAIN_ARM64)/sysroot # @Moss - Above are the 'official' android flags <architecture>arm <compileflags>-fvisibility=hidden <compileflags>-fvisibility-inlines-hidden <compileflags>-fdata-sections <cxxflags>-D_REENTRANT <cxxflags>-D_GLIBCXX__PTHREADS <compileflags>-Wno-long-long <compileflags>-Wno-missing-field-initializers <compileflags>-Wno-unused-variable ; EOF # bootstrap ./bootstrap.sh --with-libraries=atomic,chrono,date_time,exception,filesystem,graph,iostreams,math,program_options,random,regex,serialization,signals,system,test,thread,wave # clean and build for Android, j option is num of cores x 1.5 rm -fr android-build ./b2 -j6 -sNDK_ROOT="$HOME/Library/Android/sdk/ndk-bundle" --build-dir=android-build --stagedir=android-build/x86 toolset=gcc-x86 threading=multi link=static stage ./b2 -j6 -sNDK_ROOT="$HOME/Library/Android/sdk/ndk-bundle" --build-dir=android-build --stagedir=android-build/x86_64 toolset=gcc-x86_64 threading=multi link=static stage ./b2 -j6 -sNDK_ROOT="$HOME/Library/Android/sdk/ndk-bundle" --build-dir=android-build --stagedir=android-build/armeabi toolset=gcc-armeabi threading=multi link=static stage ./b2 -j6 -sNDK_ROOT="$HOME/Library/Android/sdk/ndk-bundle" --build-dir=android-build --stagedir=android-build/armeabi-v7a toolset=gcc-armeabi_v7a threading=multi link=static stage ./b2 -j6 -sNDK_ROOT="$HOME/Library/Android/sdk/ndk-bundle" --build-dir=android-build --stagedir=android-build/arm64-v8a toolset=gcc-arm64_v8a threading=multi link=static stage # create link for include folder cd android-build mkdir -p include cd include ln -s ../../boost .


(3) Create Android.mk at ~/Library/Android/sdk/ndk-bundle/sources/boost_1_62_0/ for ndkBuild in Android Studio
~/Library/Android/sdk/ndk-bundle/sources/boost_1_62_0/Android.mk    Select all
# create the following Android.mk cat > ~/Library/Android/sdk/ndk-bundle/sources/boost_1_62_0/Android.mk << 'EOF' LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := libboost_atomic LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_atomic.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libboost_chrono LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_chrono.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libboost_date_time LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_date_time.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libboost_exception LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_exception.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libboost_filesystem LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_filesystem.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libboost_graph LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_graph.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libboost_iostreams LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_iostreams.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libboost_math_c99 LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_math_c99.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libboost_math_c99f LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_math_c99f.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libboost_math_c99l LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_math_c99l.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libboost_math_tr1 LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_math_tr1.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libboost_math_tr1f LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_math_tr1f.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libboost_math_tr1l LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_math_tr1l.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libboost_prg_exec_monitor LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_prg_exec_monitor.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libboost_program_options LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_program_options.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libboost_random LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_random.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libboost_regex LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_regex.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libboost_serialization LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_serialization.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libboost_signals LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_signals.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libboost_system LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_system.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libboost_test_exec_monitor LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_test_exec_monitor.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libboost_thread LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_thread.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libboost_timer LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_timer.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libboost_unit_test_framework LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_unit_test_framework.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libboost_wave LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_wave.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libboost_wserialization LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libboost_wserialization.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) EOF


(4) Download and build QuantLib for Android
shell script    Select all
# download quantlib source to ndk-bundle cd ~/Library/Android/sdk/ndk-bundle/sources curl -O http://nchc.dl.sourceforge.net/project/quantlib/QuantLib/1.9/QuantLib-1.9.tar.gz # for QuantLib-1.10 # curl -O http://nchc.dl.sourceforge.net/project/quantlib/QuantLib/1.10/QuantLib-1.10.tar.gz tar xzvf QuantLib-1.9.tar.gz cd QuantLib-1.9 #Create the following shell script for x86 cat > ~/Library/Android/sdk/ndk-bundle/sources/QuantLib-1.9/build-x86.sh << 'x86EOF' #!/bin/bash # build-x86.sh BUILD_DIR=android-build mkdir -p ${BUILD_DIR} INSTALL_DIR="`pwd`/${BUILD_DIR}" YOUR_PATH_TO_INSTALL_DIR="`cd "${INSTALL_DIR}";pwd`" NDK_DIR="${HOME}/Library/Android/sdk/ndk-bundle" YOUR_PATH_TO_NDK="`cd "${NDK_DIR}";pwd`" YOUR_TOOLCHAIN=${YOUR_PATH_TO_NDK}/sources/android-toolchain-x86 export CC=${YOUR_TOOLCHAIN}/bin/i686-linux-android-gcc export CXX=${YOUR_TOOLCHAIN}/bin/i686-linux-android-g++ export CPP=${YOUR_TOOLCHAIN}/bin/i686-linux-android-cpp export AR=${YOUR_TOOLCHAIN}/bin/i686-linux-android-ar export RANLIB=${YOUR_TOOLCHAIN}/bin/i686-linux-android-ranlib export LD=${YOUR_TOOLCHAIN}/bin/i686-linux-android-ld export CPPFLAGS="-fexceptions -frtti -fpic -ffunction-sections -funwind-tables -fvisibility=hidden -fvisibility-inlines-hidden -fdata-sections" export CXXFLAGS="-DANDROID -D__ANDROID__ -DNDEBUG -O2 -g -D_REENTRANT -D_GLIBCXX__PTHREADS" sysroot=${YOUR_TOOLCHAIN} boost_include="`cd "${YOUR_PATH_TO_NDK}/sources/boost_1_62_0/android-build/include";pwd`" boost_lib="`cd "${YOUR_PATH_TO_NDK}/sources/boost_1_62_0/android-build/x86/lib";pwd`" make distclean ./configure --prefix=/x86 --host=i686-linux-android --with-sysroot=${sysroot} --with-boost-include=${boost_include} --with-boost-lib=${boost_lib} --enable-static --enable-shared=no --enable-examples=no --enable-thread-safe-observer-pattern make -j6 make install DESTDIR=${YOUR_PATH_TO_INSTALL_DIR} x86EOF #Create the following shell script for x86_64 cat > ~/Library/Android/sdk/ndk-bundle/sources/QuantLib-1.9/build-x86_64.sh << 'x86_64EOF' #!/bin/bash # build-x86_64.sh BUILD_DIR=android-build mkdir -p ${BUILD_DIR} INSTALL_DIR="`pwd`/${BUILD_DIR}" YOUR_PATH_TO_INSTALL_DIR="`cd "${INSTALL_DIR}";pwd`" NDK_DIR="${HOME}/Library/Android/sdk/ndk-bundle" YOUR_PATH_TO_NDK="`cd "${NDK_DIR}";pwd`" YOUR_TOOLCHAIN=${YOUR_PATH_TO_NDK}/sources/android-toolchain-x86_64 export CC=${YOUR_TOOLCHAIN}/bin/x86_64-linux-android-gcc export CXX=${YOUR_TOOLCHAIN}/bin/x86_64-linux-android-g++ export CPP=${YOUR_TOOLCHAIN}/bin/x86_64-linux-android-cpp export AR=${YOUR_TOOLCHAIN}/bin/x86_64-linux-android-ar export RANLIB=${YOUR_TOOLCHAIN}/bin/x86_64-linux-android-ranlib export LD=${YOUR_TOOLCHAIN}/bin/x86_64-linux-android-ld export CPPFLAGS="-fexceptions -frtti -fpic -ffunction-sections -funwind-tables -fvisibility=hidden -fvisibility-inlines-hidden -fdata-sections" export CXXFLAGS="-D_REENTRANT -D_GLIBCXX__PTHREADS -DANDROID -D__ANDROID__ -DNDEBUG -O2 -g" sysroot=${YOUR_TOOLCHAIN} boost_include="`cd "${YOUR_PATH_TO_NDK}/sources/boost_1_62_0/android-build/include";pwd`" boost_lib="`cd "${YOUR_PATH_TO_NDK}/sources/boost_1_62_0/android-build/x86_64/lib";pwd`" make distclean ./configure --prefix=/x86_64 --host=x86_64-linux-android --with-sysroot=${sysroot} --with-boost-include=${boost_include} --with-boost-lib=${boost_lib} --enable-static --enable-shared=no --enable-examples=no --enable-thread-safe-observer-pattern make -j6 make install DESTDIR=${YOUR_PATH_TO_INSTALL_DIR} x86_64EOF #Create the following shell script for armeabi cat > ~/Library/Android/sdk/ndk-bundle/sources/QuantLib-1.9/build-armeabi.sh << 'armeabiEOF' #!/bin/bash # build-armeabi.sh BUILD_DIR=android-build mkdir -p ${BUILD_DIR} INSTALL_DIR="`pwd`/${BUILD_DIR}" YOUR_PATH_TO_INSTALL_DIR="`cd "${INSTALL_DIR}";pwd`" NDK_DIR="${HOME}/Library/Android/sdk/ndk-bundle" YOUR_PATH_TO_NDK="`cd "${NDK_DIR}";pwd`" YOUR_TOOLCHAIN=${YOUR_PATH_TO_NDK}/sources/android-toolchain-arm export CC=${YOUR_TOOLCHAIN}/bin/arm-linux-androideabi-gcc export CXX=${YOUR_TOOLCHAIN}/bin/arm-linux-androideabi-g++ export CPP=${YOUR_TOOLCHAIN}/bin/arm-linux-androideabi-cpp export AR=${YOUR_TOOLCHAIN}/bin/arm-linux-androideabi-ar export RANLIB=${YOUR_TOOLCHAIN}/bin/arm-linux-androideabi-ranlib export LD=${YOUR_TOOLCHAIN}/bin/arm-linux-androideabi-ld export CPPFLAGS="-fexceptions -frtti -fpic -ffunction-sections -funwind-tables -fvisibility=hidden -fvisibility-inlines-hidden -fdata-sections" export CXXFLAGS="-D_REENTRANT -D_GLIBCXX__PTHREADS -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -march=armv5te -mtune=xscale -msoft-float -mthumb -DANDROID -D__ANDROID__ -DNDEBUG -O2 -g" export LDFLAGS="-march=armv5te" sysroot=${YOUR_TOOLCHAIN} boost_include="`cd "${YOUR_PATH_TO_NDK}/sources/boost_1_62_0/android-build/include";pwd`" boost_lib="`cd "${YOUR_PATH_TO_NDK}/sources/boost_1_62_0/android-build/armeabi/lib";pwd`" make distclean ./configure --prefix=/armeabi --host=arm-linux-androideabi --with-sysroot=${sysroot} --with-boost-include=${boost_include} --with-boost-lib=${boost_lib} --enable-static --enable-shared=no --enable-examples=no --enable-thread-safe-observer-pattern make -j6 make install DESTDIR=${YOUR_PATH_TO_INSTALL_DIR} armeabiEOF #Create the following shell script for armeabi-v7a cat > ~/Library/Android/sdk/ndk-bundle/sources/QuantLib-1.9/build-armeabi-v7a.sh << 'armeabi-v7aEOF' #!/bin/bash # build-armeabi-v7a.sh BUILD_DIR=android-build mkdir -p ${BUILD_DIR} INSTALL_DIR="`pwd`/${BUILD_DIR}" YOUR_PATH_TO_INSTALL_DIR="`cd "${INSTALL_DIR}";pwd`" NDK_DIR="${HOME}/Library/Android/sdk/ndk-bundle" YOUR_PATH_TO_NDK="`cd "${NDK_DIR}";pwd`" YOUR_TOOLCHAIN=${YOUR_PATH_TO_NDK}/sources/android-toolchain-arm export CC=${YOUR_TOOLCHAIN}/bin/arm-linux-androideabi-gcc export CXX=${YOUR_TOOLCHAIN}/bin/arm-linux-androideabi-g++ export CPP=${YOUR_TOOLCHAIN}/bin/arm-linux-androideabi-cpp export AR=${YOUR_TOOLCHAIN}/bin/arm-linux-androideabi-ar export RANLIB=${YOUR_TOOLCHAIN}/bin/arm-linux-androideabi-ranlib export LD=${YOUR_TOOLCHAIN}/bin/arm-linux-androideabi-ld export CPPFLAGS="-fexceptions -frtti -fpic -ffunction-sections -funwind-tables -fvisibility=hidden -fvisibility-inlines-hidden -fdata-sections" export CXXFLAGS="-D_REENTRANT -D_GLIBCXX__PTHREADS -march=armv7-a -msoft-float -mfpu=neon -mthumb -DANDROID -D__ANDROID__ -DNDEBUG -O2 -g" export LDFLAGS="-march=armv7-a -Wl,--fix-cortex-a8" sysroot=${YOUR_TOOLCHAIN} boost_include="`cd "${YOUR_PATH_TO_NDK}/sources/boost_1_62_0/android-build/include";pwd`" boost_lib="`cd "${YOUR_PATH_TO_NDK}/sources/boost_1_62_0/android-build/armeabi-v7a/lib";pwd`" make distclean ./configure --prefix=/armeabi-v7a --host=arm-linux-androideabi --with-sysroot=${sysroot} --with-boost-include=${boost_include} --with-boost-lib=${boost_lib} --enable-static --enable-shared=no --enable-examples=no --enable-thread-safe-observer-pattern make -j6 make install DESTDIR=${YOUR_PATH_TO_INSTALL_DIR} armeabi-v7aEOF #Create the following shell script for arm64-v8a cat > ~/Library/Android/sdk/ndk-bundle/sources/QuantLib-1.9/build-arm64-v8a.sh << 'arm64-v8aEOF' #!/bin/bash # build-arm64-v8a.sh BUILD_DIR=android-build mkdir -p ${BUILD_DIR} INSTALL_DIR="`pwd`/${BUILD_DIR}" YOUR_PATH_TO_INSTALL_DIR="`cd "${INSTALL_DIR}";pwd`" NDK_DIR="${HOME}/Library/Android/sdk/ndk-bundle" YOUR_PATH_TO_NDK="`cd "${NDK_DIR}";pwd`" YOUR_TOOLCHAIN=${YOUR_PATH_TO_NDK}/sources/android-toolchain-arm64 export CC=${YOUR_TOOLCHAIN}/bin/aarch64-linux-android-gcc export CXX=${YOUR_TOOLCHAIN}/bin/aarch64-linux-android-g++ export CPP=${YOUR_TOOLCHAIN}/bin/aarch64-linux-android-cpp export AR=${YOUR_TOOLCHAIN}/bin/aarch64-linux-android-ar export RANLIB=${YOUR_TOOLCHAIN}/bin/aarch64-linux-android-ranlib export LD=${YOUR_TOOLCHAIN}/bin/aarch64-linux-android-ld export CPPFLAGS="-fexceptions -frtti -fpic -ffunction-sections -funwind-tables -fstack-protector -fvisibility=hidden -fvisibility-inlines-hidden -fdata-sections" export CXXFLAGS="-D_REENTRANT -D_GLIBCXX__PTHREADS -march=armv8-a -mtune=cortex-a53 -DANDROID -D__ANDROID__ -DNDEBUG -O2 -g" export LDFLAGS="-march=armv8-a" sysroot=${YOUR_TOOLCHAIN} boost_include="`cd "${YOUR_PATH_TO_NDK}/sources/boost_1_62_0/android-build/include";pwd`" boost_lib="`cd "${YOUR_PATH_TO_NDK}/sources/boost_1_62_0/android-build/arm64-v8a/lib";pwd`" make distclean ./configure --prefix=/arm64-v8a --host=aarch64-linux-android --with-sysroot=${sysroot} --with-boost-include=${boost_include} --with-boost-lib=${boost_lib} --enable-static --enable-shared=no --enable-examples=no --enable-thread-safe-observer-pattern make -j6 make install DESTDIR=${YOUR_PATH_TO_INSTALL_DIR} arm64-v8aEOF #run shell scripts to clean and build for Android cd ~/Library/Android/sdk/ndk-bundle/sources cd QuantLib-1.9 rm -fr android-build sh build-x86.sh sh build-x86_64.sh sh build-armeabi.sh sh build-armeabi-v7a.sh sh build-arm64-v8a.sh


(5) Create Android.mk at ~/Library/Android/sdk/ndk-bundle/sources/QuantLib-1.9/ for ndkBuild in Android Studio
~/Library/Android/sdk/ndk-bundle/sources/QuantLib-1.9/Android.mk    Select all
# create the following Android.mk cat > ~/Library/Android/sdk/ndk-bundle/sources/QuantLib-1.9/Android.mk << 'EOF' LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := libQuantLib LOCAL_SRC_FILES := android-build/$(TARGET_ARCH_ABI)/lib/libQuantLib.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android-build/$(TARGET_ARCH_ABI)/include LOCAL_CPP_FEATURES := rtti exceptions include $(PREBUILT_STATIC_LIBRARY) EOF


(6) Demo of using boost c++ libraries for ndkBuild in Android Studio 2.2.2
Assume prebuilt libraries are installed to ~/Library/Android/sdk/ndk-bundle/sources
app/build.gradle    Select all
apply plugin: 'com.android.application' Properties properties = new Properties() properties.load(project.rootProject.file('local.properties').newDataInputStream()) def sdkFolder = properties.getProperty('sdk.dir') def ndkFolder = properties.getProperty('ndk.dir') android { compileSdkVersion 23 buildToolsVersion "23.0.3" defaultConfig { applicationId "com.example.helloboost" minSdkVersion 9 targetSdkVersion 23 versionCode = 1 versionName = '1.0' archivesBaseName = 'HELLOBOOST_' + versionName ndk { moduleName "hello-boost" abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' } externalNativeBuild { ndkBuild { arguments "NDK_APPLICATION_MK=src/main/jni/Application.mk" // default module search path NDK_MODULE_PATH is at ${ndkFolder}/sources } } } buildTypes { debug { minifyEnabled false zipAlignEnabled true debuggable true useProguard false versionNameSuffix 'debug' } release { minifyEnabled false zipAlignEnabled true useProguard true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' } } externalNativeBuild { ndkBuild { path "src/main/jni/Android.mk" } } }


app/src/main/jni/Android.mk    Select all
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hello-boost LOCAL_SRC_FILES := hello-boost.cpp first.cpp LOCAL_STATIC_LIBRARIES := libboost_system libboost_thread libboost_program_options libQuantLib include $(BUILD_SHARED_LIBRARY) $(call import-module, boost_1_62_0) $(call import-module, QuantLib-1.9)


app/src/main/jni/Application.mk    Select all
APP_STL = gnustl_static APP_CPPFLAGS = -Wall


(7) HelloJNI, sample of using cmake CMakeLists.txt after adding Boost and QuantLib libraries
Assume prebuilt libraries are installed to ~/Library/Android/sdk/ndk-bundle/sources
app/src/main/cpp/CMakeLists.txt    Select all
cmake_minimum_required(VERSION 3.4.1) # build native_app_glue as a static lib add_library(app-glue STATIC ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c) # now build app's shared lib set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -frtti -fexceptions") add_library(hello-jni SHARED hello-jni.c) #BOOST set(Boost_INCLUDE_DIR ${ANDROID_NDK}/sources/boost_1_62_0/android-build/include) set(Boost_LIBRARY_DIR ${ANDROID_NDK}/sources/boost_1_62_0/android-build/${ANDROID_ABI}/lib) set(Boost_USE_STATIC_LIBS ON) # only find static libs set(Boost_USE_MULTITHREADED ON) set(Boost_USE_STATIC_RUNTIME OFF) set(Boost_COMPILER -gcc) find_package(Boost COMPONENTS system thread program_options REQUIRED) #BOOSTEND #QuantLib set(QuantLib_INCLUDE_DIR ${ANDROID_NDK}/sources/QuantLib-1.9/android-build/${ANDROID_ABI}/include) set(QuantLib_LIBRARY_DIR ${ANDROID_NDK}/sources/QuantLib-1.9/android-build/${ANDROID_ABI}/lib) add_library(QuantLib STATIC IMPORTED) set_property(TARGET QuantLib PROPERTY IMPORTED_LOCATION ${QuantLib_LIBRARY_DIR}/libQuantLib.a) #QuantLibEND # if have QuantLibJNI, uncomment below and add QuantLibJNI to target_link_libraries of hello-jni for c++ classes generated from QuantLib-SWIG-1.9 #add_library(QuantLibJNI SHARED quantlib_wrap.cpp) #target_link_libraries(QuantLibJNI ${Boost_LIBRARIES} QuantLib) if(Boost_FOUND) # Include libraries needed include_directories(${Boost_INCLUDE_DIR}) include_directories(${QuantLib_INCLUDE_DIR}) target_link_libraries(hello-jni android app-glue log ${Boost_LIBRARIES} QuantLib) endif()

app/build.gradle    Select all
apply plugin: 'com.android.application' android { compileSdkVersion 23 buildToolsVersion '23.0.3' defaultConfig { applicationId 'com.example.hellojni' minSdkVersion 15 targetSdkVersion 23 versionCode 1 versionName "1.0" archivesBaseName = 'HELLOJNI_' + versionName externalNativeBuild { cmake { arguments '-DANDROID_TOOLCHAIN=clang' cppFlags "" } } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debug { debuggable true jniDebuggable true versionNameSuffix 'debug' } } externalNativeBuild { cmake { path "src/main/cpp/CMakeLists.txt" } } productFlavors { arm { ndk { abiFilter 'armeabi' } } arm7 { ndk { abiFilter 'armeabi-v7a' } } arm64 { ndk { abiFilter 'arm64-v8a' } } x86 { ndk { abiFilter 'x86' } } x86_64 { ndk { abiFilter 'x86_64' } } universal { ndk { abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' } } } } dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') compile 'com.android.support:appcompat-v7:23.4.0' compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha7' }


(8) Download & Compile swig and generate java & c++ classes from QuantLib-SWIG-1.9 for Android project
shell scriptSelect all
#download and compile swig cd ~/Downloads curl -O http://nchc.dl.sourceforge.net/project/swig/swig/swig-3.0.10/swig-3.0.10.tar.gz tar xzvf swig-3.0.10.tar.gz curl -O http://nchc.dl.sourceforge.net/project/pcre/pcre/8.39/pcre-8.39.tar.gz tar xzvf pcre-8.39.tar.gz cd ~/Downloads/pcre-8.39 ./configure --enable-utf8 --enable-unicode-properties make sudo make install cd ~/Downloads/swig-3.0.10 ./configure make sudo make install # download QuantLib-SWIG-1.9 cd ~/Library/Android/sdk/ndk-bundle/sources curl -O http://jaist.dl.sourceforge.net/project/quantlib/QuantLib/1.9/other%20languages/QuantLib-SWIG-1.9.tar.gz tar xzvf QuantLib-SWIG-1.9.tar.gz # generate SWIG java & c++ classes to HelloJNI project cd ~/Projects cd HelloJNI/app/src/main mkdir -p cpp mkdir -p java/org/quantlib swig -java -c++ -module QuantLib -package org.quantlib -outdir java/org/quantlib -o cpp/quantlib_wrap.cpp ~/Library/Android/sdk/ndk-bundle/sources/QuantLib-SWIG-1.9/SWIG/quantlib.i