├── packages ├── optionPricer1 │ ├── .Rbuildignore │ ├── NAMESPACE │ ├── src │ │ ├── getOneGaussianByBoxMueller.h │ │ ├── runSimpleMonteCarlo1.h │ │ ├── rcpp_hello_world.cpp │ │ ├── getOneGaussianByBoxMueller.cpp │ │ ├── main.cpp │ │ ├── runSimpleMonteCarlo1.cpp │ │ └── RcppExports.cpp │ ├── man │ │ ├── rcpp_hello_world.Rd │ │ └── optionPricer1-package.Rd │ ├── DESCRIPTION │ ├── optionPricer1.Rproj │ ├── Read-and-delete-me │ └── R │ │ └── RcppExports.R └── optionPricer2 │ ├── .Rbuildignore │ ├── NAMESPACE │ ├── src │ ├── getVecMean.h │ ├── getVecStdDev.h │ ├── getOneGaussianByBoxMueller.h │ ├── rcpp_hello_world.cpp │ ├── getVecMean.cpp │ ├── getVecStdDev.cpp │ ├── getOneGaussianByBoxMueller.cpp │ ├── main.cpp │ ├── AsianOption.h │ ├── RcppExports.cpp │ └── AsianOption.cpp │ ├── man │ ├── rcpp_hello_world.Rd │ └── optionPricer2-package.Rd │ ├── DESCRIPTION │ ├── optionPricer2.Rproj │ ├── Read-and-delete-me │ └── R │ └── RcppExports.R ├── slides ├── slides.pdf ├── img │ ├── hull.jpg │ ├── logo.png │ ├── prata.jpg │ ├── seamless.jpg │ ├── WNE_UW_EN.pdf │ ├── stroustrup.jpg │ ├── logo_beamer.png │ └── wne_logo2017.png └── slides.Rmd ├── progs ├── prog2 │ ├── getVecMean.h │ ├── getVecStdDev.h │ ├── getOneGaussianByBoxMueller.h │ ├── getVecMean.cpp │ ├── getVecStdDev.cpp │ ├── getOneGaussianByBoxMueller.cpp │ ├── AsianOption.h │ ├── main.cpp │ └── AsianOption.cpp └── prog1 │ ├── getOneGaussianByBoxMueller.h │ ├── runSimpleMonteCarlo1.h │ ├── getOneGaussianByBoxMueller.cpp │ ├── main.cpp │ └── runSimpleMonteCarlo1.cpp ├── functions ├── getZeroCouponBondPrice2.cpp ├── getCouponBondPrice2.cpp ├── getCumSum.cpp └── getSpotLastPrices.R ├── AF-RCPP.Rproj ├── solutions ├── getEWMA.cpp ├── getBondPrice.R ├── getSMA.cpp ├── exercise02.R ├── exercise01.R └── exercise03.R ├── .gitignore ├── scripts ├── optionPricer2Application.R ├── intro2Rcpp.R └── pricingComparison.R ├── README.md └── LICENSE /packages/optionPricer1/.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | -------------------------------------------------------------------------------- /packages/optionPricer2/.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | -------------------------------------------------------------------------------- /slides/slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawelsakowski/AF-RCPP/HEAD/slides/slides.pdf -------------------------------------------------------------------------------- /slides/img/hull.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawelsakowski/AF-RCPP/HEAD/slides/img/hull.jpg -------------------------------------------------------------------------------- /slides/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawelsakowski/AF-RCPP/HEAD/slides/img/logo.png -------------------------------------------------------------------------------- /slides/img/prata.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawelsakowski/AF-RCPP/HEAD/slides/img/prata.jpg -------------------------------------------------------------------------------- /slides/img/seamless.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawelsakowski/AF-RCPP/HEAD/slides/img/seamless.jpg -------------------------------------------------------------------------------- /slides/img/WNE_UW_EN.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawelsakowski/AF-RCPP/HEAD/slides/img/WNE_UW_EN.pdf -------------------------------------------------------------------------------- /slides/img/stroustrup.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawelsakowski/AF-RCPP/HEAD/slides/img/stroustrup.jpg -------------------------------------------------------------------------------- /slides/img/logo_beamer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawelsakowski/AF-RCPP/HEAD/slides/img/logo_beamer.png -------------------------------------------------------------------------------- /slides/img/wne_logo2017.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pawelsakowski/AF-RCPP/HEAD/slides/img/wne_logo2017.png -------------------------------------------------------------------------------- /packages/optionPricer1/NAMESPACE: -------------------------------------------------------------------------------- 1 | useDynLib(optionPricer1, .registration=TRUE) 2 | importFrom(Rcpp, evalCpp) 3 | exportPattern("^[[:alpha:]]+") 4 | -------------------------------------------------------------------------------- /packages/optionPricer2/NAMESPACE: -------------------------------------------------------------------------------- 1 | useDynLib(optionPricer2, .registration=TRUE) 2 | importFrom(Rcpp, evalCpp) 3 | exportPattern("^[[:alpha:]]+") 4 | -------------------------------------------------------------------------------- /progs/prog2/getVecMean.h: -------------------------------------------------------------------------------- 1 | #ifndef GETVECMEAN_H 2 | #define GETVECMEAN_H 3 | 4 | double getVecMean(std::vector thisVec); 5 | 6 | #endif -------------------------------------------------------------------------------- /progs/prog2/getVecStdDev.h: -------------------------------------------------------------------------------- 1 | #ifndef GETVECSTDDEV_H 2 | #define GETVECSTDDEV_H 3 | 4 | double getVecStdDev (std::vector thisVec); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /packages/optionPricer2/src/getVecMean.h: -------------------------------------------------------------------------------- 1 | #ifndef GETVECMEAN_H 2 | #define GETVECMEAN_H 3 | 4 | double getVecMean(std::vector thisVec); 5 | 6 | #endif -------------------------------------------------------------------------------- /packages/optionPricer2/src/getVecStdDev.h: -------------------------------------------------------------------------------- 1 | #ifndef GETVECSTDDEV_H 2 | #define GETVECSTDDEV_H 3 | 4 | double getVecStdDev (std::vector thisVec); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /progs/prog2/getOneGaussianByBoxMueller.h: -------------------------------------------------------------------------------- 1 | #ifndef GETONEGAUSSIANBYBOXMUELLER_H 2 | #define GETONEGAUSSIANBYBOXMUELLER_H 3 | 4 | double getOneGaussianByBoxMueller(); 5 | 6 | #endif 7 | 8 | -------------------------------------------------------------------------------- /progs/prog1/getOneGaussianByBoxMueller.h: -------------------------------------------------------------------------------- 1 | #ifndef GETONEGAUSSIANBYBOXMUELLER_H 2 | #define GETONEGAUSSIANBYBOXMUELLER_H 3 | 4 | double getOneGaussianByBoxMueller(); 5 | 6 | #endif 7 | 8 | -------------------------------------------------------------------------------- /packages/optionPricer1/src/getOneGaussianByBoxMueller.h: -------------------------------------------------------------------------------- 1 | #ifndef GETONEGAUSSIANBYBOXMUELLER_H 2 | #define GETONEGAUSSIANBYBOXMUELLER_H 3 | 4 | double getOneGaussianByBoxMueller(); 5 | 6 | #endif 7 | 8 | -------------------------------------------------------------------------------- /packages/optionPricer2/src/getOneGaussianByBoxMueller.h: -------------------------------------------------------------------------------- 1 | #ifndef GETONEGAUSSIANBYBOXMUELLER_H 2 | #define GETONEGAUSSIANBYBOXMUELLER_H 3 | 4 | double getOneGaussianByBoxMueller(); 5 | 6 | #endif 7 | 8 | -------------------------------------------------------------------------------- /functions/getZeroCouponBondPrice2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace Rcpp; 3 | 4 | // [[Rcpp::export]] 5 | double getZeroCouponBondPrice2( 6 | int n, 7 | double ytm, 8 | double f){ 9 | double price = 0; 10 | price += f/pow(1+ytm, double(n)) ; 11 | return price; 12 | } -------------------------------------------------------------------------------- /packages/optionPricer1/man/rcpp_hello_world.Rd: -------------------------------------------------------------------------------- 1 | \name{rcpp_hello_world} 2 | \alias{rcpp_hello_world} 3 | \docType{package} 4 | \title{ 5 | Simple function using Rcpp 6 | } 7 | \description{ 8 | Simple function using Rcpp 9 | } 10 | \usage{ 11 | rcpp_hello_world() 12 | } 13 | \examples{ 14 | \dontrun{ 15 | rcpp_hello_world() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/optionPricer2/man/rcpp_hello_world.Rd: -------------------------------------------------------------------------------- 1 | \name{rcpp_hello_world} 2 | \alias{rcpp_hello_world} 3 | \docType{package} 4 | \title{ 5 | Simple function using Rcpp 6 | } 7 | \description{ 8 | Simple function using Rcpp 9 | } 10 | \usage{ 11 | rcpp_hello_world() 12 | } 13 | \examples{ 14 | \dontrun{ 15 | rcpp_hello_world() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/optionPricer1/src/runSimpleMonteCarlo1.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNSIMPLEMONTECARLO1_H 2 | #define RUNSIMPLEMONTECARLO1_H 3 | 4 | // prototype of the function 5 | double runSimpleMonteCarlo1(double Expiry, 6 | double Strike, 7 | double Spot, 8 | double Vol, 9 | double r, 10 | unsigned long int NumberOfPaths); 11 | 12 | #endif -------------------------------------------------------------------------------- /packages/optionPricer1/src/rcpp_hello_world.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | using namespace Rcpp; 4 | 5 | // [[Rcpp::export]] 6 | List rcpp_hello_world() { 7 | 8 | CharacterVector x = CharacterVector::create( "foo", "bar" ) ; 9 | NumericVector y = NumericVector::create( 0.0, 1.0 ) ; 10 | List z = List::create( x, y ) ; 11 | 12 | return z ; 13 | } 14 | -------------------------------------------------------------------------------- /packages/optionPricer2/src/rcpp_hello_world.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | using namespace Rcpp; 4 | 5 | // [[Rcpp::export]] 6 | List rcpp_hello_world() { 7 | 8 | CharacterVector x = CharacterVector::create( "foo", "bar" ) ; 9 | NumericVector y = NumericVector::create( 0.0, 1.0 ) ; 10 | List z = List::create( x, y ) ; 11 | 12 | return z ; 13 | } 14 | -------------------------------------------------------------------------------- /AF-RCPP.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | BuildType: Package 16 | PackageUseDevtools: Yes 17 | PackageInstallArgs: --no-multiarch --with-keep.source 18 | -------------------------------------------------------------------------------- /packages/optionPricer1/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: optionPricer1 2 | Type: Package 3 | Title: What the Package Does in One 'Title Case' Line 4 | Version: 1.0 5 | Date: 2020-11-02 6 | Author: Your Name 7 | Maintainer: Your Name 8 | Description: One paragraph description of what the package does as one or more full sentences. 9 | License: GPL (>= 2) 10 | Imports: Rcpp (>= 1.0.5) 11 | LinkingTo: Rcpp 12 | -------------------------------------------------------------------------------- /packages/optionPricer2/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: optionPricer2 2 | Type: Package 3 | Title: What the Package Does in One 'Title Case' Line 4 | Version: 1.0 5 | Date: 2020-11-02 6 | Author: Your Name 7 | Maintainer: Your Name 8 | Description: One paragraph description of what the package does as one or more full sentences. 9 | License: GPL (>= 2) 10 | Imports: Rcpp (>= 1.0.5) 11 | LinkingTo: Rcpp 12 | -------------------------------------------------------------------------------- /packages/optionPricer1/optionPricer1.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | BuildType: Package 16 | PackageUseDevtools: Yes 17 | PackageInstallArgs: --no-multiarch --with-keep.source 18 | -------------------------------------------------------------------------------- /packages/optionPricer2/optionPricer2.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | BuildType: Package 16 | PackageUseDevtools: Yes 17 | PackageInstallArgs: --no-multiarch --with-keep.source 18 | -------------------------------------------------------------------------------- /progs/prog2/getVecMean.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include"getVecMean.h" 4 | 5 | // general function for mean value of a vector 6 | double getVecMean(std::vector thisVec){ 7 | 8 | double runningSum = 0.0; 9 | int thisSize = thisVec.size(); 10 | 11 | for(int i = 0; i < thisSize; i++){ 12 | runningSum += thisVec[i]; 13 | } 14 | 15 | return runningSum/double(thisSize); 16 | } 17 | 18 | -------------------------------------------------------------------------------- /progs/prog1/runSimpleMonteCarlo1.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNSIMPLEMONTECARLO1_H 2 | #define RUNSIMPLEMONTECARLO1_H 3 | 4 | // prototype of the function 5 | double runSimpleMonteCarlo1(double Expiry, 6 | double Strike, 7 | double Spot, 8 | double Vol, 9 | double r, 10 | unsigned long int NumberOfPaths); 11 | 12 | #endif -------------------------------------------------------------------------------- /packages/optionPricer2/src/getVecMean.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include"getVecMean.h" 4 | 5 | // general function for mean value of a vector 6 | double getVecMean(std::vector thisVec){ 7 | 8 | double runningSum = 0.0; 9 | int thisSize = thisVec.size(); 10 | 11 | for(int i = 0; i < thisSize; i++){ 12 | runningSum += thisVec[i]; 13 | } 14 | 15 | return runningSum/double(thisSize); 16 | } 17 | 18 | -------------------------------------------------------------------------------- /packages/optionPricer1/Read-and-delete-me: -------------------------------------------------------------------------------- 1 | * Edit the help file skeletons in 'man', possibly combining help files for multiple functions. 2 | * Edit the exports in 'NAMESPACE', and add necessary imports. 3 | * Put any C/C++/Fortran code in 'src'. 4 | * If you have compiled code, add a useDynLib() directive to 'NAMESPACE'. 5 | * Run R CMD build to build the package tarball. 6 | * Run R CMD check to check the package tarball. 7 | 8 | Read "Writing R Extensions" for more information. 9 | -------------------------------------------------------------------------------- /packages/optionPricer2/Read-and-delete-me: -------------------------------------------------------------------------------- 1 | * Edit the help file skeletons in 'man', possibly combining help files for multiple functions. 2 | * Edit the exports in 'NAMESPACE', and add necessary imports. 3 | * Put any C/C++/Fortran code in 'src'. 4 | * If you have compiled code, add a useDynLib() directive to 'NAMESPACE'. 5 | * Run R CMD build to build the package tarball. 6 | * Run R CMD check to check the package tarball. 7 | 8 | Read "Writing R Extensions" for more information. 9 | -------------------------------------------------------------------------------- /functions/getCouponBondPrice2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace Rcpp; 3 | 4 | // [[Rcpp::export]] 5 | double getCouponBondPrice2( 6 | int n, 7 | double coupon, 8 | int m, 9 | double ytm, 10 | double f){ 11 | 12 | double price = 0; 13 | 14 | for (int i = 1; i <= (n*m); ++i){ 15 | price += (coupon*f/m)/pow((1+ytm/m), double(i)); 16 | } 17 | 18 | price += f/pow(1+ytm/m, double(n*m)) ; 19 | 20 | return price; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /packages/optionPricer1/R/RcppExports.R: -------------------------------------------------------------------------------- 1 | # Generated by using Rcpp::compileAttributes() -> do not edit by hand 2 | # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 3 | 4 | getCallPrice <- function(Expiry = 0.5, Strike = 100, Spot = 120, Vol = 0.2, r = 0.06, NumberOfPaths = 10000L) { 5 | .Call(`_optionPricer1_getCallPrice`, Expiry, Strike, Spot, Vol, r, NumberOfPaths) 6 | } 7 | 8 | rcpp_hello_world <- function() { 9 | .Call(`_optionPricer1_rcpp_hello_world`) 10 | } 11 | 12 | -------------------------------------------------------------------------------- /packages/optionPricer2/R/RcppExports.R: -------------------------------------------------------------------------------- 1 | # Generated by using Rcpp::compileAttributes() -> do not edit by hand 2 | # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 3 | 4 | getArithmeticAsianCallPrice <- function(nInt, Strike, Spot, Vol, Rfr, Expiry, nReps = 1000L) { 5 | .Call(`_optionPricer2_getArithmeticAsianCallPrice`, nInt, Strike, Spot, Vol, Rfr, Expiry, nReps) 6 | } 7 | 8 | rcpp_hello_world <- function() { 9 | .Call(`_optionPricer2_rcpp_hello_world`) 10 | } 11 | 12 | -------------------------------------------------------------------------------- /functions/getCumSum.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include // for std::partial_sum 3 | 4 | using namespace Rcpp; 5 | 6 | // [[Rcpp::export]] 7 | NumericVector getCumSum(NumericVector x){ 8 | // initialize an accumulator variable 9 | double acc = 0; 10 | 11 | // initialize the result vector 12 | NumericVector result(x.size()); 13 | 14 | for(int i = 0; i < x.size(); i++){ 15 | acc += x[i]; 16 | result[i] = acc; 17 | } 18 | 19 | return result; 20 | } -------------------------------------------------------------------------------- /packages/optionPricer2/src/getVecStdDev.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include"getVecMean.h" 4 | #include"getVecStdDev.h" 5 | 6 | // general function for standard deviation of a vector 7 | double getVecStdDev(std::vector thisVec){ 8 | 9 | double runningSum = 0.0; 10 | int thisSize = thisVec.size(); 11 | 12 | for ( int i = 0; i < thisSize; i++ ){ 13 | runningSum += pow((thisVec[i]- getVecMean(thisVec) ), 2); 14 | } 15 | 16 | return sqrt(runningSum/(thisSize - 1)); 17 | } 18 | -------------------------------------------------------------------------------- /progs/prog2/getVecStdDev.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include"getVecMean.h" 4 | #include"getVecStdDev.h" 5 | 6 | // general function for standard deviation of a vector 7 | double getVecStdDev(std::vector thisVec){ 8 | 9 | double runningSum = 0.0; 10 | int thisSize = thisVec.size(); 11 | double thisMean = getVecMean(thisVec); 12 | 13 | for ( int i = 0; i < thisSize; i++ ){ 14 | runningSum += pow((thisVec[i]- thisMean ), 2); 15 | } 16 | 17 | return sqrt(runningSum/(thisSize - 1)); 18 | } 19 | -------------------------------------------------------------------------------- /solutions/getEWMA.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include // for std::partial_sum 3 | 4 | using namespace Rcpp; 5 | 6 | // [[Rcpp::export]] 7 | NumericVector getEWMA(NumericVector x, double alpha = 0.05){ 8 | 9 | // initialize the result vector 10 | NumericVector ewma(x.size() + 1); 11 | 12 | // first smoothed value equals to first observed value 13 | ewma[0] = x[0]; 14 | 15 | // main loop 16 | for(int i = 1; i < ewma.size(); i++){ 17 | ewma[i] = alpha * x[i - 1] + (1 - alpha) * ewma[i - 1]; 18 | } 19 | 20 | return ewma; 21 | 22 | } -------------------------------------------------------------------------------- /progs/prog1/getOneGaussianByBoxMueller.cpp: -------------------------------------------------------------------------------- 1 | #include "getOneGaussianByBoxMueller.h" 2 | #include 3 | #include 4 | 5 | double getOneGaussianByBoxMueller(){ 6 | double result; 7 | 8 | double x; 9 | double y; 10 | 11 | double sizeSquared; 12 | do { 13 | x = 2.0 * rand()/static_cast(RAND_MAX)-1; 14 | y = 2.0 * rand()/static_cast(RAND_MAX)-1; 15 | sizeSquared = x * x + y * y; 16 | } 17 | while ( sizeSquared >= 1.0); 18 | 19 | result = x * sqrt(-2 * log(sizeSquared) / sizeSquared); 20 | 21 | return result; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /progs/prog2/getOneGaussianByBoxMueller.cpp: -------------------------------------------------------------------------------- 1 | #include "getOneGaussianByBoxMueller.h" 2 | #include 3 | #include 4 | 5 | double getOneGaussianByBoxMueller(){ 6 | double result; 7 | 8 | double x; 9 | double y; 10 | 11 | double sizeSquared; 12 | do { 13 | x = 2.0 * rand()/static_cast(RAND_MAX)-1; 14 | y = 2.0 * rand()/static_cast(RAND_MAX)-1; 15 | sizeSquared = x * x + y * y; 16 | } 17 | while ( sizeSquared >= 1.0); 18 | 19 | result = x * sqrt(-2 * log(sizeSquared) / sizeSquared); 20 | 21 | return result; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /packages/optionPricer1/src/getOneGaussianByBoxMueller.cpp: -------------------------------------------------------------------------------- 1 | #include "getOneGaussianByBoxMueller.h" 2 | #include 3 | #include 4 | 5 | double getOneGaussianByBoxMueller(){ 6 | double result; 7 | 8 | double x; 9 | double y; 10 | 11 | double sizeSquared; 12 | do { 13 | x = 2.0 * rand()/static_cast(RAND_MAX)-1; 14 | y = 2.0 * rand()/static_cast(RAND_MAX)-1; 15 | sizeSquared = x * x + y * y; 16 | } 17 | while ( sizeSquared >= 1.0); 18 | 19 | result = x * sqrt(-2 * log(sizeSquared) / sizeSquared); 20 | 21 | return result; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /packages/optionPricer2/src/getOneGaussianByBoxMueller.cpp: -------------------------------------------------------------------------------- 1 | #include "getOneGaussianByBoxMueller.h" 2 | #include 3 | #include 4 | 5 | double getOneGaussianByBoxMueller(){ 6 | double result; 7 | 8 | double x; 9 | double y; 10 | 11 | double sizeSquared; 12 | do { 13 | x = 2.0 * rand()/static_cast(RAND_MAX)-1; 14 | y = 2.0 * rand()/static_cast(RAND_MAX)-1; 15 | sizeSquared = x * x + y * y; 16 | } 17 | while ( sizeSquared >= 1.0); 18 | 19 | result = x * sqrt(-2 * log(sizeSquared) / sizeSquared); 20 | 21 | return result; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /solutions/getBondPrice.R: -------------------------------------------------------------------------------- 1 | cppFunction(" 2 | double getCouponBondPrice(int n, 3 | double coupon, 4 | int m, 5 | double ytm, 6 | double f){ 7 | 8 | double price = 0; 9 | 10 | for (int i = 1; i <= (n*m); ++i){ 11 | price += (coupon*f/m)/pow((1+ytm/m), double(i)); 12 | } 13 | 14 | price += f/pow(1+ytm/m, double(n*m)) ; 15 | 16 | return price; 17 | } 18 | ") 19 | -------------------------------------------------------------------------------- /solutions/getSMA.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include // for std::partial_sum 3 | 4 | using namespace Rcpp; 5 | 6 | // [[Rcpp::export]] 7 | NumericVector getSMA(NumericVector x, int k = 7){ 8 | // initialize an accumulator variable 9 | double runningSum = 0; 10 | int threshold = 0; 11 | 12 | // initialize the result vector 13 | NumericVector result(x.size()); 14 | 15 | for(int i = (x.size() - 1); i >= 0; i--){ 16 | runningSum = 0; 17 | if (i < k) threshold = i+1; 18 | else threshold = k; 19 | for(int j = 0; j < threshold; j++) { 20 | runningSum += x[i-j]; 21 | } 22 | result[i] = runningSum / threshold ; 23 | } 24 | return result; 25 | } -------------------------------------------------------------------------------- /packages/optionPricer1/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "runSimpleMonteCarlo1.h" 3 | 4 | using namespace Rcpp; 5 | using namespace std; 6 | 7 | // [[Rcpp::export]] 8 | double getCallPrice( 9 | double Expiry = 0.5, 10 | double Strike = 100, 11 | double Spot = 120, 12 | double Vol = 0.2, 13 | double r = 0.06, 14 | unsigned long NumberOfPaths = 10000){ 15 | double result = runSimpleMonteCarlo1(Expiry, 16 | Strike, 17 | Spot, 18 | Vol, 19 | r, 20 | NumberOfPaths); 21 | 22 | return result; 23 | } 24 | 25 | 26 | -------------------------------------------------------------------------------- /solutions/exercise02.R: -------------------------------------------------------------------------------- 1 | sourceCpp("solutions/getSMA.cpp") 2 | 3 | nObs <- 1000 4 | k <- 30 5 | smaData <- 6 | tibble( 7 | obs = 1:nObs, 8 | r = rnorm(nObs) 9 | ) %>% 10 | mutate(rw = getCumSum(r), 11 | sma = getSMA(x = rw, k = k)) 12 | 13 | smaData %>% 14 | select(-r) %>% 15 | pivot_longer(cols = !obs) %>% 16 | ggplot(aes(x = obs, y = value, col = as_factor(name))) + 17 | geom_line() + 18 | labs( 19 | x = "observations", 20 | y = "value", 21 | title = "Random walk simulation and its Simple Moving Average", 22 | subtitle = paste0("cumulative sum of ~N(0,1) simulated increments and their SMA with k = ", 23 | k), 24 | caption = "source: own calculations", 25 | colour = "variable" 26 | ) 27 | 28 | -------------------------------------------------------------------------------- /solutions/exercise01.R: -------------------------------------------------------------------------------- 1 | # define the function 2 | source("solutions/getBondPrice.R") 3 | 4 | # call the function 5 | getCouponBondPrice(10, 0.1, 12, 0.11, 1000) 6 | 7 | # build an R function 8 | getCouponBondPrice1 <- function (r) { 9 | return(getCouponBondPrice(10, 0.05, 12, r, 1000)) 10 | } 11 | 12 | ytm <- seq(0.001, 0.1, by = 0.001) 13 | getCouponBondPrice1(0.05) 14 | couponBondPrices <- sapply(ytm, getCouponBondPrice1) 15 | 16 | # plot 17 | tibble( 18 | ytm = ytm, 19 | prices = couponBondPrices 20 | ) %>% 21 | ggplot(aes(x = ytm, y = couponBondPrices)) + 22 | geom_point(col = "red") + 23 | labs( 24 | x = "yield to maturity", 25 | y = "price of coupon bond", 26 | title = "Coupon bond price vs. yield to maturity", 27 | caption = "source: own calculations" 28 | ) 29 | 30 | -------------------------------------------------------------------------------- /packages/optionPricer2/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include"AsianOption.h" 6 | #include"getVecMean.h" 7 | #include"getVecStdDev.h" 8 | 9 | using namespace Rcpp; 10 | using std::vector; 11 | 12 | // [[Rcpp::export]] 13 | double getArithmeticAsianCallPrice( 14 | int nInt, 15 | double Strike, 16 | double Spot, 17 | double Vol, 18 | double Rfr, 19 | double Expiry, 20 | int nReps = 1000){ 21 | 22 | // set the seed 23 | srand( time(NULL) ); 24 | 25 | // create a new instance of a class 26 | AsianOption myAsian(nInt, Strike, Spot, Vol, Rfr, Expiry); 27 | 28 | // call the method to get option price 29 | double price = myAsian.getArithmeticAsianCallPrice(nReps); 30 | 31 | // return option price 32 | return price; 33 | } 34 | -------------------------------------------------------------------------------- /solutions/exercise03.R: -------------------------------------------------------------------------------- 1 | sourceCpp("solutions/getEWMA.cpp") 2 | 3 | nObs <- 1000 4 | alpha <- 0.03 5 | 6 | ewmaData <- 7 | tibble( 8 | obs = 1:nObs, 9 | r = rnorm(nObs) 10 | ) %>% 11 | mutate(rw = getCumSum(r), 12 | ewma = getEWMA(x = rw, alpha = alpha) %>% head(-1)) 13 | 14 | ewmaData %>% 15 | select(-r) %>% 16 | pivot_longer(cols = !obs) %>% 17 | ggplot(aes(x = obs, y = value, col = as_factor(name))) + 18 | geom_line() + 19 | labs( 20 | x = "observations", 21 | y = "value", 22 | title = "Random walk simulation and its Exponentially Weighted Moving Average", 23 | subtitle = paste0("cumulative sum of ~N(0,1) simulated increments and their EWMA with alpha = ", 24 | alpha), 25 | caption = "source: own calculations", 26 | colour = "variable" 27 | ) 28 | -------------------------------------------------------------------------------- /packages/optionPricer2/src/AsianOption.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class AsianOption{ 4 | public: 5 | 6 | //constructor 7 | AsianOption( 8 | int nInt_, 9 | double strike_, 10 | double spot_, 11 | double vol_, 12 | double r_, 13 | double expiry_ 14 | ); 15 | 16 | //destructor 17 | ~AsianOption(){}; 18 | 19 | //methods 20 | void generatePath(); 21 | double getArithmeticMean(); 22 | double getGeometricMean(); 23 | void printPath(); 24 | double getArithmeticAsianCallPrice(int nReps); 25 | double getArithmeticAsianPutPrice(int nReps); 26 | double getGeometricAsianCallPrice(int nReps); 27 | double getGeometricAsianPutPrice(int nReps); 28 | double operator()(char char1, char char2, int nReps); 29 | 30 | //members 31 | std::vector thisPath; 32 | int nInt; 33 | double strike; 34 | double spot; 35 | double vol; 36 | double r; 37 | double expiry; 38 | 39 | }; 40 | -------------------------------------------------------------------------------- /progs/prog2/AsianOption.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class AsianOption{ 4 | public: 5 | 6 | //constructor 7 | AsianOption( 8 | int nInt_, 9 | double strike_, 10 | double spot_, 11 | double vol_, 12 | double r_, 13 | double expiry_ 14 | ); 15 | 16 | //destructor 17 | ~AsianOption(){}; 18 | 19 | //methods 20 | void generatePath(); 21 | double getArithmeticMean(); 22 | double getGeometricMean(); 23 | void printPath(); 24 | double getArithmeticAsianCallPrice(int nReps); 25 | double getArithmeticAsianPutPrice(int nReps); 26 | double getGeometricAsianCallPrice(int nReps); 27 | double getGeometricAsianPutPrice(int nReps); 28 | double operator()(char char1, char char2, int nReps); 29 | 30 | //members 31 | std::vector thisPath; 32 | int nInt; 33 | double strike; 34 | double spot; 35 | double vol; 36 | double r; 37 | double expiry; 38 | 39 | }; 40 | -------------------------------------------------------------------------------- /packages/optionPricer1/man/optionPricer1-package.Rd: -------------------------------------------------------------------------------- 1 | \name{optionPricer1-package} 2 | \alias{optionPricer1-package} 3 | \alias{optionPricer1} 4 | \docType{package} 5 | \title{ 6 | A short title line describing what the package does 7 | } 8 | \description{ 9 | A more detailed description of what the package does. A length 10 | of about one to five lines is recommended. 11 | } 12 | \details{ 13 | This section should provide a more detailed overview of how to use the 14 | package, including the most important functions. 15 | } 16 | \author{ 17 | Your Name, email optional. 18 | 19 | Maintainer: Your Name 20 | } 21 | \references{ 22 | This optional section can contain literature or other references for 23 | background information. 24 | } 25 | \keyword{ package } 26 | \seealso{ 27 | Optional links to other man pages 28 | } 29 | \examples{ 30 | \dontrun{ 31 | ## Optional simple examples of the most important functions 32 | ## These can be in \dontrun{} and \donttest{} blocks. 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/optionPricer2/man/optionPricer2-package.Rd: -------------------------------------------------------------------------------- 1 | \name{optionPricer2-package} 2 | \alias{optionPricer2-package} 3 | \alias{optionPricer2} 4 | \docType{package} 5 | \title{ 6 | A short title line describing what the package does 7 | } 8 | \description{ 9 | A more detailed description of what the package does. A length 10 | of about one to five lines is recommended. 11 | } 12 | \details{ 13 | This section should provide a more detailed overview of how to use the 14 | package, including the most important functions. 15 | } 16 | \author{ 17 | Your Name, email optional. 18 | 19 | Maintainer: Your Name 20 | } 21 | \references{ 22 | This optional section can contain literature or other references for 23 | background information. 24 | } 25 | \keyword{ package } 26 | \seealso{ 27 | Optional links to other man pages 28 | } 29 | \examples{ 30 | \dontrun{ 31 | ## Optional simple examples of the most important functions 32 | ## These can be in \dontrun{} and \donttest{} blocks. 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /progs/prog1/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "runSimpleMonteCarlo1.h" 3 | 4 | using namespace std; 5 | 6 | // main function 7 | int main(){ 8 | 9 | double Expiry; 10 | double Strike; 11 | double Spot; 12 | double Vol; 13 | double r; 14 | unsigned long NumberOfPaths; 15 | 16 | cout << "\nEnter expiry\n"; 17 | cin >> Expiry; 18 | 19 | cout << "\nEnter strike\n"; 20 | cin >> Strike; 21 | 22 | cout << "\nEnter spot\n"; 23 | cin >> Spot; 24 | 25 | cout << "\nEnter volatility\n"; 26 | cin >> Vol; 27 | 28 | cout << "\nEnter risk-free rate\n"; 29 | cin >> r; 30 | 31 | cout << "\nNumber of paths\n"; 32 | cin >> NumberOfPaths; 33 | 34 | double result = runSimpleMonteCarlo1(Expiry, 35 | Strike, 36 | Spot, 37 | Vol, 38 | r, 39 | NumberOfPaths); 40 | 41 | cout << "The price of European call is " << result << "\n"; 42 | 43 | return 0; 44 | } 45 | 46 | 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # History files 2 | .Rhistory 3 | .Rapp.history 4 | 5 | # Session Data files 6 | .RData 7 | 8 | # User-specific files 9 | .Ruserdata 10 | 11 | # Example code in package build process 12 | *-Ex.R 13 | 14 | # Output files from R CMD build 15 | /*.tar.gz 16 | 17 | # Output files from R CMD check 18 | /*.Rcheck/ 19 | 20 | # RStudio files 21 | .Rproj.user/ 22 | 23 | # produced vignettes 24 | vignettes/*.html 25 | vignettes/*.pdf 26 | 27 | # OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3 28 | .httr-oauth 29 | 30 | # knitr and R markdown default cache directories 31 | *_cache/ 32 | /cache/ 33 | 34 | # Temporary files created by R markdown 35 | *.utf8.md 36 | *.knit.md 37 | 38 | # R Environment Variables 39 | .Renviron 40 | 41 | # additional entries 42 | slides/*.md 43 | slides/*.aux 44 | slides/*.vrb 45 | *.tar.gz 46 | *.zip 47 | slides/*_cache 48 | slides/*_files 49 | README.html 50 | packages/*.zip 51 | packages/*.tar.gz 52 | packages/*/src/*.o 53 | packages/*/src/*.so 54 | progs/prog1/main 55 | progs/prog2/main 56 | 57 | # macOS specific 58 | .DS_Store 59 | 60 | -------------------------------------------------------------------------------- /packages/optionPricer1/src/runSimpleMonteCarlo1.cpp: -------------------------------------------------------------------------------- 1 | #include "runSimpleMonteCarlo1.h" 2 | #include "getOneGaussianByBoxMueller.h" 3 | #include 4 | 5 | // definition of the function 6 | double runSimpleMonteCarlo1(double Expiry, 7 | double Strike, 8 | double Spot, 9 | double Vol, 10 | double r, 11 | unsigned long int NumberOfPaths){ 12 | 13 | double variance = Vol * Vol * Expiry; 14 | double rootVariance = sqrt(variance); 15 | double itoCorrection = -0.5 * variance; 16 | 17 | double movedSpot = Spot * exp(r * Expiry + itoCorrection); 18 | double thisSpot; 19 | double runningSum = 0; 20 | 21 | for (unsigned long i = 0; i < NumberOfPaths; i++) { 22 | double thisGaussian = getOneGaussianByBoxMueller(); 23 | thisSpot = movedSpot * exp(rootVariance * thisGaussian); 24 | double thisPayoff = thisSpot - Strike; 25 | // thisPayoff = thisPayoff > 0 ? thisPayoff : 0; 26 | if (thisPayoff>0) runningSum += thisPayoff; 27 | } 28 | 29 | double mean = runningSum / NumberOfPaths; 30 | // mean *= exp(-r * Expiry); 31 | mean = mean * exp(-r * Expiry); 32 | return mean; 33 | } 34 | -------------------------------------------------------------------------------- /functions/getSpotLastPrices.R: -------------------------------------------------------------------------------- 1 | library(tidyverse) 2 | 3 | getSpotLastPrices <- function(Spot = 95, 4 | Strike = 100, 5 | r = 0.06, 6 | Vol = 0.2, 7 | Expiry = 0.5, 8 | nReps = 100) { 9 | 10 | variance <- Vol * Vol * Expiry 11 | rootVariance <- sqrt(variance) 12 | itoCorrection <- -0.5 * variance 13 | movedSpot <- Spot * exp(r * Expiry + itoCorrection) 14 | 15 | thisGaussian <- rnorm(nReps) 16 | thisSpot <- movedSpot * exp(rootVariance * thisGaussian) 17 | thisPayoff <- thisSpot - Strike 18 | thisPayoff[thisPayoff < 0] <- 0 19 | 20 | price <- mean(thisPayoff) * exp(-r * Expiry); 21 | # return(price) 22 | return(thisSpot) 23 | # return(movedSpot) 24 | } 25 | 26 | p <- getSpotLastPrices(nReps = 100000) 27 | 28 | p %>% 29 | enframe() %>% 30 | ggplot(aes(x = value)) + 31 | geom_histogram(binwidth = 1, 32 | fill = "pink", 33 | col = "black") 34 | 35 | mean(p) 36 | (exp(rootVariance^2) - 1)*exp(rootVariance^2) 37 | var(p - mean(p)) 38 | 39 | 40 | 41 | 95*1.03 42 | 96.91913 -------------------------------------------------------------------------------- /progs/prog1/runSimpleMonteCarlo1.cpp: -------------------------------------------------------------------------------- 1 | #include "runSimpleMonteCarlo1.h" 2 | #include "getOneGaussianByBoxMueller.h" 3 | #include 4 | 5 | // definition of the function 6 | double runSimpleMonteCarlo1(double Expiry, 7 | double Strike, 8 | double Spot, 9 | double Vol, 10 | double r, 11 | unsigned long int NumberOfPaths){ 12 | 13 | double variance = Vol * Vol * Expiry; 14 | double rootVariance = sqrt(variance); 15 | double itoCorrection = -0.5 * variance; 16 | 17 | double movedSpot = Spot * exp(r * Expiry + itoCorrection); 18 | double thisSpot; 19 | double runningSum = 0; 20 | 21 | for (unsigned long i = 0; i < NumberOfPaths; i++) { 22 | double thisGaussian = getOneGaussianByBoxMueller(); 23 | thisSpot = movedSpot * exp(rootVariance * thisGaussian); 24 | double thisPayoff = thisSpot - Strike; 25 | // thisPayoff = thisPayoff > 0 ? thisPayoff : 0; 26 | if (thisPayoff>0) runningSum += thisPayoff; 27 | } 28 | 29 | double mean = runningSum / NumberOfPaths; 30 | // mean *= exp(-r * Expiry); 31 | mean = mean * exp(-r * Expiry); 32 | return mean; 33 | } 34 | -------------------------------------------------------------------------------- /packages/optionPricer1/src/RcppExports.cpp: -------------------------------------------------------------------------------- 1 | // Generated by using Rcpp::compileAttributes() -> do not edit by hand 2 | // Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 3 | 4 | #include 5 | 6 | using namespace Rcpp; 7 | 8 | // getCallPrice 9 | double getCallPrice(double Expiry, double Strike, double Spot, double Vol, double r, unsigned long NumberOfPaths); 10 | RcppExport SEXP _optionPricer1_getCallPrice(SEXP ExpirySEXP, SEXP StrikeSEXP, SEXP SpotSEXP, SEXP VolSEXP, SEXP rSEXP, SEXP NumberOfPathsSEXP) { 11 | BEGIN_RCPP 12 | Rcpp::RObject rcpp_result_gen; 13 | Rcpp::RNGScope rcpp_rngScope_gen; 14 | Rcpp::traits::input_parameter< double >::type Expiry(ExpirySEXP); 15 | Rcpp::traits::input_parameter< double >::type Strike(StrikeSEXP); 16 | Rcpp::traits::input_parameter< double >::type Spot(SpotSEXP); 17 | Rcpp::traits::input_parameter< double >::type Vol(VolSEXP); 18 | Rcpp::traits::input_parameter< double >::type r(rSEXP); 19 | Rcpp::traits::input_parameter< unsigned long >::type NumberOfPaths(NumberOfPathsSEXP); 20 | rcpp_result_gen = Rcpp::wrap(getCallPrice(Expiry, Strike, Spot, Vol, r, NumberOfPaths)); 21 | return rcpp_result_gen; 22 | END_RCPP 23 | } 24 | // rcpp_hello_world 25 | List rcpp_hello_world(); 26 | RcppExport SEXP _optionPricer1_rcpp_hello_world() { 27 | BEGIN_RCPP 28 | Rcpp::RObject rcpp_result_gen; 29 | Rcpp::RNGScope rcpp_rngScope_gen; 30 | rcpp_result_gen = Rcpp::wrap(rcpp_hello_world()); 31 | return rcpp_result_gen; 32 | END_RCPP 33 | } 34 | 35 | static const R_CallMethodDef CallEntries[] = { 36 | {"_optionPricer1_getCallPrice", (DL_FUNC) &_optionPricer1_getCallPrice, 6}, 37 | {"_optionPricer1_rcpp_hello_world", (DL_FUNC) &_optionPricer1_rcpp_hello_world, 0}, 38 | {NULL, NULL, 0} 39 | }; 40 | 41 | RcppExport void R_init_optionPricer1(DllInfo *dll) { 42 | R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); 43 | R_useDynamicSymbols(dll, FALSE); 44 | } 45 | -------------------------------------------------------------------------------- /packages/optionPricer2/src/RcppExports.cpp: -------------------------------------------------------------------------------- 1 | // Generated by using Rcpp::compileAttributes() -> do not edit by hand 2 | // Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 3 | 4 | #include 5 | 6 | using namespace Rcpp; 7 | 8 | // getArithmeticAsianCallPrice 9 | double getArithmeticAsianCallPrice(int nInt, double Strike, double Spot, double Vol, double Rfr, double Expiry, int nReps); 10 | RcppExport SEXP _optionPricer2_getArithmeticAsianCallPrice(SEXP nIntSEXP, SEXP StrikeSEXP, SEXP SpotSEXP, SEXP VolSEXP, SEXP RfrSEXP, SEXP ExpirySEXP, SEXP nRepsSEXP) { 11 | BEGIN_RCPP 12 | Rcpp::RObject rcpp_result_gen; 13 | Rcpp::RNGScope rcpp_rngScope_gen; 14 | Rcpp::traits::input_parameter< int >::type nInt(nIntSEXP); 15 | Rcpp::traits::input_parameter< double >::type Strike(StrikeSEXP); 16 | Rcpp::traits::input_parameter< double >::type Spot(SpotSEXP); 17 | Rcpp::traits::input_parameter< double >::type Vol(VolSEXP); 18 | Rcpp::traits::input_parameter< double >::type Rfr(RfrSEXP); 19 | Rcpp::traits::input_parameter< double >::type Expiry(ExpirySEXP); 20 | Rcpp::traits::input_parameter< int >::type nReps(nRepsSEXP); 21 | rcpp_result_gen = Rcpp::wrap(getArithmeticAsianCallPrice(nInt, Strike, Spot, Vol, Rfr, Expiry, nReps)); 22 | return rcpp_result_gen; 23 | END_RCPP 24 | } 25 | // rcpp_hello_world 26 | List rcpp_hello_world(); 27 | RcppExport SEXP _optionPricer2_rcpp_hello_world() { 28 | BEGIN_RCPP 29 | Rcpp::RObject rcpp_result_gen; 30 | Rcpp::RNGScope rcpp_rngScope_gen; 31 | rcpp_result_gen = Rcpp::wrap(rcpp_hello_world()); 32 | return rcpp_result_gen; 33 | END_RCPP 34 | } 35 | 36 | static const R_CallMethodDef CallEntries[] = { 37 | {"_optionPricer2_getArithmeticAsianCallPrice", (DL_FUNC) &_optionPricer2_getArithmeticAsianCallPrice, 7}, 38 | {"_optionPricer2_rcpp_hello_world", (DL_FUNC) &_optionPricer2_rcpp_hello_world, 0}, 39 | {NULL, NULL, 0} 40 | }; 41 | 42 | RcppExport void R_init_optionPricer2(DllInfo *dll) { 43 | R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); 44 | R_useDynamicSymbols(dll, FALSE); 45 | } 46 | -------------------------------------------------------------------------------- /progs/prog2/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include"AsianOption.h" 6 | #include"getVecMean.h" 7 | #include"getVecStdDev.h" 8 | 9 | using std::vector; 10 | using std::cout; 11 | using std::cin; 12 | 13 | int main(){ 14 | 15 | // set the seed 16 | srand( time(NULL) ); 17 | 18 | //create a new instance of class 19 | AsianOption myAsian(126, 100, 95, 0.2, 0.06, 0.5); 20 | 21 | // Iterate over all the elements. 22 | // myAsian.printPath(); 23 | 24 | //get arithmetic means 25 | cout << "arithmetic mean = " << myAsian.getArithmeticMean() <<"\n"; 26 | cout << "geometric mean = " << myAsian.getGeometricMean() <<"\n"; 27 | 28 | //get last price of underlying 29 | cout << "Last price of underlying = " << myAsian.thisPath.back() << "\n"; 30 | 31 | //run Monte Carlo to obtain theoretical price of Asian options 32 | cout << "Price of arithmetic Asian Call = " << myAsian.getArithmeticAsianCallPrice(10000) << "\n"; 33 | cout << "Price of arithmetic Asian Put = " << myAsian.getArithmeticAsianPutPrice(10000) << "\n"; 34 | cout << "Price of geometric Asian Call = " << myAsian.getGeometricAsianCallPrice(10000) << "\n"; 35 | cout << "Price of geometric Asian Put = " << myAsian.getGeometricAsianPutPrice(10000) << "\n"; 36 | 37 | //call Monte Carlo via overloaded () operator 38 | cout << "calling functions via operator() \n"; 39 | cout << "Price of arithmetic Asian Call = " << myAsian('A', 'C', 10000) << "\n"; 40 | cout << "Price of arithmetic Asian Put = " << myAsian('A', 'P', 10000) << "\n"; 41 | cout << "Price of geometric Asian Call = " << myAsian('G', 'C', 10000) << "\n"; 42 | cout << "Price of geometric Asian Put = " << myAsian('G', 'P', 10000) << "\n"; 43 | 44 | //check whether the Data Generating Process runs correctly 45 | //(is the expected price and volatility of underlying close to option parameters?) 46 | vector myVec2; 47 | for(int i = 0; i < 1000000; i++){ 48 | myAsian.generatePath(); 49 | myVec2.push_back(myAsian.thisPath.back()); 50 | } 51 | 52 | cout << "mean of last underlying prices is " << getVecMean(myVec2) << "\n"; 53 | cout << "stddev of last underlying prices is " << getVecStdDev(myVec2) << "\n"; 54 | 55 | //cout << "\nPress Enter to continue..."; 56 | //cin.get(); 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /progs/prog2/AsianOption.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include"getOneGaussianByBoxMueller.h" 4 | #include"AsianOption.h" 5 | 6 | 7 | //definition of constructor 8 | AsianOption::AsianOption( 9 | int nInt_, 10 | double strike_, 11 | double spot_, 12 | double vol_, 13 | double r_, 14 | double expiry_){ 15 | nInt = nInt_; 16 | strike = strike_; 17 | spot = spot_; 18 | vol = vol_; 19 | r = r_; 20 | expiry = expiry_; 21 | generatePath(); 22 | } 23 | 24 | //method definition 25 | void AsianOption::generatePath(){ 26 | double thisDrift = (r * expiry - 0.5 * vol * vol * expiry) / double(nInt); 27 | double cumShocks = 0; 28 | thisPath.clear(); 29 | 30 | for(int i = 0; i < nInt; i++){ 31 | cumShocks += (thisDrift + vol * sqrt(expiry / double(nInt)) * getOneGaussianByBoxMueller()); 32 | thisPath.push_back(spot * exp(cumShocks)); 33 | } 34 | } 35 | 36 | //method definition 37 | double AsianOption::getArithmeticMean(){ 38 | 39 | double runningSum = 0.0; 40 | 41 | for(int i = 0; i < nInt; i++){ 42 | runningSum += thisPath[i]; 43 | } 44 | 45 | return runningSum/double(nInt); 46 | } 47 | 48 | 49 | //method definition 50 | double AsianOption::getGeometricMean(){ 51 | 52 | double runningSum = 0.0; 53 | 54 | for(int i = 0; i < nInt ; i++){ 55 | runningSum += log(thisPath[i]); 56 | } 57 | 58 | return exp(runningSum/double(nInt)); 59 | } 60 | 61 | //method definition 62 | void AsianOption::printPath(){ 63 | 64 | for(int i = 0; i < nInt; i++){ 65 | 66 | std::cout << thisPath[i] << "\n"; 67 | 68 | } 69 | 70 | } 71 | 72 | //method definition 73 | double AsianOption::getArithmeticAsianCallPrice(int nReps){ 74 | 75 | double rollingSum = 0.0; 76 | double thisMean = 0.0; 77 | 78 | for(int i = 0; i < nReps; i++){ 79 | generatePath(); 80 | thisMean=getArithmeticMean(); 81 | rollingSum += (thisMean > strike) ? (thisMean-strike) : 0; 82 | } 83 | 84 | return exp(-r*expiry)*rollingSum/double(nReps); 85 | 86 | } 87 | 88 | //method definition 89 | double AsianOption::getArithmeticAsianPutPrice(int nReps){ 90 | 91 | double rollingSum = 0.0; 92 | double thisMean = 0.0; 93 | 94 | for(int i = 0; i < nReps; i++){ 95 | generatePath(); 96 | thisMean=getArithmeticMean(); 97 | rollingSum += (thisMean < strike) ? (strike - thisMean) : 0; 98 | } 99 | 100 | return exp(-r*expiry)*rollingSum/double(nReps); 101 | 102 | } 103 | 104 | //method definition 105 | double AsianOption::getGeometricAsianCallPrice(int nReps){ 106 | 107 | double rollingSum = 0.0; 108 | double thisMean = 0.0; 109 | 110 | for(int i = 0; i < nReps; i++){ 111 | generatePath(); 112 | thisMean=getGeometricMean(); 113 | rollingSum += (thisMean > strike)? (thisMean-strike) : 0; 114 | } 115 | 116 | return exp(-r*expiry)*rollingSum/double(nReps); 117 | 118 | } 119 | 120 | //method definition 121 | double AsianOption::getGeometricAsianPutPrice(int nReps){ 122 | 123 | double rollingSum = 0.0; 124 | double thisMean = 0.0; 125 | 126 | for(int i = 0; i < nReps; i++){ 127 | generatePath(); 128 | thisMean=getGeometricMean(); 129 | rollingSum += (thisMean < strike)? (strike - thisMean) : 0; 130 | } 131 | 132 | return exp(-r*expiry)*rollingSum/double(nReps); 133 | 134 | } 135 | 136 | //overloaded operator (); 137 | double AsianOption::operator()(char char1, char char2, int nReps){ 138 | if ((char1 == 'A') & (char2 =='C')) return getArithmeticAsianCallPrice(nReps); 139 | else if ((char1 == 'A') & (char2 =='P')) return getArithmeticAsianPutPrice(nReps); 140 | else if ((char1 == 'G') & (char2 =='C')) return getGeometricAsianCallPrice(nReps); 141 | else if ((char1 == 'G') & (char2 =='P')) return getGeometricAsianPutPrice(nReps); 142 | else return -99; 143 | } 144 | -------------------------------------------------------------------------------- /packages/optionPricer2/src/AsianOption.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include"getOneGaussianByBoxMueller.h" 4 | #include"AsianOption.h" 5 | 6 | 7 | //definition of constructor 8 | AsianOption::AsianOption( 9 | int nInt_, 10 | double strike_, 11 | double spot_, 12 | double vol_, 13 | double r_, 14 | double expiry_){ 15 | nInt = nInt_; 16 | strike = strike_; 17 | spot = spot_; 18 | vol = vol_; 19 | r = r_; 20 | expiry = expiry_; 21 | generatePath(); 22 | } 23 | 24 | //method definition 25 | void AsianOption::generatePath(){ 26 | double thisDrift = (r * expiry - 0.5 * vol * vol * expiry) / double(nInt); 27 | double cumShocks = 0; 28 | thisPath.clear(); 29 | 30 | for(int i = 0; i < nInt; i++){ 31 | cumShocks += (thisDrift + vol * sqrt(expiry / double(nInt)) * getOneGaussianByBoxMueller()); 32 | thisPath.push_back(spot * exp(cumShocks)); 33 | } 34 | } 35 | 36 | //method definition 37 | double AsianOption::getArithmeticMean(){ 38 | 39 | double runningSum = 0.0; 40 | 41 | for(int i = 0; i < nInt; i++){ 42 | runningSum += thisPath[i]; 43 | } 44 | 45 | return runningSum/double(nInt); 46 | } 47 | 48 | 49 | //method definition 50 | double AsianOption::getGeometricMean(){ 51 | 52 | double runningSum = 0.0; 53 | 54 | for(int i = 0; i < nInt ; i++){ 55 | runningSum += log(thisPath[i]); 56 | } 57 | 58 | return exp(runningSum/double(nInt)); 59 | } 60 | 61 | //method definition 62 | void AsianOption::printPath(){ 63 | 64 | for(int i = 0; i < nInt; i++){ 65 | 66 | std::cout << thisPath[i] << "\n"; 67 | 68 | } 69 | 70 | } 71 | 72 | //method definition 73 | double AsianOption::getArithmeticAsianCallPrice(int nReps){ 74 | 75 | double rollingSum = 0.0; 76 | double thisMean = 0.0; 77 | 78 | for(int i = 0; i < nReps; i++){ 79 | generatePath(); 80 | thisMean=getArithmeticMean(); 81 | rollingSum += (thisMean > strike) ? (thisMean-strike) : 0; 82 | } 83 | 84 | return exp(-r*expiry)*rollingSum/double(nReps); 85 | 86 | } 87 | 88 | //method definition 89 | double AsianOption::getArithmeticAsianPutPrice(int nReps){ 90 | 91 | double rollingSum = 0.0; 92 | double thisMean = 0.0; 93 | 94 | for(int i = 0; i < nReps; i++){ 95 | generatePath(); 96 | thisMean=getArithmeticMean(); 97 | rollingSum += (thisMean < strike) ? (strike - thisMean) : 0; 98 | } 99 | 100 | return exp(-r*expiry)*rollingSum/double(nReps); 101 | 102 | } 103 | 104 | //method definition 105 | double AsianOption::getGeometricAsianCallPrice(int nReps){ 106 | 107 | double rollingSum = 0.0; 108 | double thisMean = 0.0; 109 | 110 | for(int i = 0; i < nReps; i++){ 111 | generatePath(); 112 | thisMean=getGeometricMean(); 113 | rollingSum += (thisMean > strike)? (thisMean-strike) : 0; 114 | } 115 | 116 | return exp(-r*expiry)*rollingSum/double(nReps); 117 | 118 | } 119 | 120 | //method definition 121 | double AsianOption::getGeometricAsianPutPrice(int nReps){ 122 | 123 | double rollingSum = 0.0; 124 | double thisMean = 0.0; 125 | 126 | for(int i = 0; i < nReps; i++){ 127 | generatePath(); 128 | thisMean=getGeometricMean(); 129 | rollingSum += (thisMean < strike)? (strike - thisMean) : 0; 130 | } 131 | 132 | return exp(-r*expiry)*rollingSum/double(nReps); 133 | 134 | } 135 | 136 | //overloaded operator (); 137 | double AsianOption::operator()(char char1, char char2, int nReps){ 138 | if ((char1 == 'A') & (char2 =='C')) return getArithmeticAsianCallPrice(nReps); 139 | else if ((char1 == 'A') & (char2 =='P')) return getArithmeticAsianPutPrice(nReps); 140 | else if ((char1 == 'G') & (char2 =='C')) return getGeometricAsianCallPrice(nReps); 141 | else if ((char1 == 'G') & (char2 =='P')) return getGeometricAsianPutPrice(nReps); 142 | else return -99; 143 | } 144 | -------------------------------------------------------------------------------- /scripts/optionPricer2Application.R: -------------------------------------------------------------------------------- 1 | #################################################################### 2 | # APPLIED FINANCE # 3 | # Path-dependent option pricing with Monte Carlo and Rcpp package # 4 | # labs02: application of the Rcpp package # 5 | # Paweł Sakowski # 6 | # University of Warsaw # 7 | #################################################################### 8 | 9 | # loading packages 10 | library(tidyverse) 11 | 12 | # 1. remove package if it exists =============================================== 13 | remove.packages("optionPricer2") 14 | detach("package:optionPricer2", unload = TRUE) # if it still is in memory 15 | 16 | # 2. install package and load to memory ======================================== 17 | # (adjust file names and/or paths, if necessary) 18 | 19 | # from binaries (no need to rebuild) 20 | install.packages("packages/optionPricer2_1.0_R_x86_64-pc-linux-gnu.tar.gz", 21 | type = "binaries", 22 | repos = NULL) 23 | 24 | # or from source (rebuilt automatically) 25 | install.packages("packages/optionPricer2_1.0.tar.gz", 26 | type = "source", 27 | repos = NULL) 28 | 29 | # 3. call the function from the package ======================================== 30 | optionPricer2::getArithmeticAsianCallPrice(126, 100, 95, 0.2, 0.06, 0.5, 10000) 31 | 32 | # 4. build an R wrapping function: option price vs. time to maturity =========== 33 | getMCAsianCallPriceWithExpiry <- function (expiry) { 34 | return( 35 | optionPricer2::getArithmeticAsianCallPrice(126, 100, 95, 0.2, 0.06, expiry, 10000) 36 | ) 37 | } 38 | 39 | # call the wrapping function 40 | getMCAsianCallPriceWithExpiry(0.5) 41 | 42 | # arguments values of values of function 43 | expiry <- seq(0.01, 1, by = 0.01) 44 | prices <- sapply(expiry, getMCAsianCallPriceWithExpiry) 45 | 46 | # visualization: options price vs. expiry 47 | tibble( expiry, prices) %>% 48 | ggplot(aes(expiry, prices)) + 49 | geom_point(col = "red") + 50 | labs( 51 | x = "time to maturity", 52 | y = "option price", 53 | title = "price of arithmetic Asian call option vs. time to maturity", 54 | caption = "source: own calculations with the optionPricer2 package") 55 | 56 | # 5. build an R wrapping function: option price vs. number of loops ============ 57 | getMCAsianCallPriceWithLoops <- function (loops) { 58 | return( 59 | optionPricer2::getArithmeticAsianCallPrice(126, 100, 95, 0.2, 0.06, 0.5, loops) 60 | ) 61 | } 62 | 63 | # call the wrapping function 64 | getMCAsianCallPriceWithLoops(500) 65 | 66 | # arguments values of values of function 67 | loops <- seq(100, 10000, by = 100) 68 | prices <- sapply(loops, getMCAsianCallPriceWithLoops) 69 | 70 | # visualization: options price vs. numbers of loops 71 | tibble(expiry, prices) %>% 72 | ggplot(aes(expiry, prices)) + 73 | geom_point(col = "blue") + 74 | labs( 75 | x = "number of loops", 76 | y = "option price", 77 | title = "price of arithmetic Asian call option vs. number of loops", 78 | caption = "source: own calculations with the optionPricer2 package") 79 | 80 | # note the same seed within one second! 81 | 82 | # 6. build an R wrapping function: option price vs. spot and volatility ======= 83 | getMCAsianCallPriceWithSpotAndVol <- function (spot, vol) { 84 | return( 85 | optionPricer2::getArithmeticAsianCallPrice(126, 100, spot, vol, 0.06, 0.5, 500)) 86 | } 87 | 88 | # call function once 89 | getMCAsianCallPriceWithSpotAndVol(100, 0.2) 90 | 91 | # sequences of argument values 92 | spot <- seq(90, 105, by = 0.5) 93 | vol <- c(0.001, 0.01, 0.02, 0.05, 0.1, 0.15, 0.2, 0.3, 0.5, 1) 94 | 95 | grid <- expand.grid(spot = spot, vol = vol) 96 | prices <- mapply(getMCAsianCallPriceWithSpotAndVol, 97 | spot = grid$spot, vol = grid$vol) 98 | result.df <- data.frame(grid, result) 99 | head(result.df) 100 | 101 | # visualization: options price vs. spot price and volatility 102 | grid %>% 103 | as_tibble() %>% 104 | bind_cols(price = prices) %>% 105 | ggplot(aes(x = spot, y = price, group = vol, colour = vol)) + 106 | geom_line() + 107 | geom_point(size = 1, shape = 21, fill = "white") + 108 | labs( 109 | x = "spot price", 110 | y = "option price", 111 | title = "price of arithmetic Asian call option vs. spot price and volatility", 112 | caption = "source: own calculations with the optionPricer2 package") 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AF-RCPP 2 | 3 | This repository contains materials to the "Applied Finance" course at the University of Warsaw, Faculty of Economic Sciences. Materials refer to the part "Path dependent option pricing with Monte Carlo simulations and Rcpp package". 4 | 5 | The aim of this short course is to provide techniques of incorporating `c++` code into `R` environment. Three techniques will be discussed: 6 | 7 | * `cppFunction()` function - for short inline `c++` code chunks 8 | * `sourceCpp()` function - for longer `c++` code chunks located in separate `*.cpp` files 9 | * `Rcpp` package - for a project that consist of 2 or more files 10 | 11 | The `Rcpp` package will be used to provide functions defined in `c++` which will be responsible for providing valuations of path-dependent option of European style using the Monte Carlo simulation technique. 12 | 13 | To earn credits for this part of the curse, students will have to provide solutions to their individual home projects which will concentrate on valuation of a specific path-dependent option. 14 | 15 | ## Schedule 16 | 17 | ### Lecture #1 18 | 19 | Slides with: 20 | 21 | * introduction to options, 22 | * option payoff profiles, 23 | * factors which influence option price 24 | * Black-Scholes-Merton (BSM) pricing formula for European options 25 | * elements of Monte Carlo simulations for valuation of path-depending options 26 | 27 | To create `slides/slides.pdf` open `slides/slides.Rmd` and run **knit to PDF (Beamer)** by pressing `Ctrl+K`. 28 | 29 | ### Labs #1 30 | 31 | We will use the script `scripts/intro2Rcpp.R`. Following elements will be discussed: 32 | 33 | * introduction to the `Rcpp` package 34 | * "importing" `c++` code to `R` using two functions: `cppFunction()` and `sourceCpp()` * simple implementations in `R` of functions defined in `c++` code. 35 | 36 | ### Lecture #2 37 | 38 | The aim is to compare of efficiency of Monte Carlo European Call option pricing techniques. The script `scripts/pricingComparison.R` will be used. We will compare following techniques: 39 | 40 | * using loops in R 41 | * using vectors in R 42 | * using loops in C++, via Rcpp 43 | * using vectors in R with antithetic sampling 44 | 45 | We also introduce a simple `c++` application which runs in Command Line (Windows) or terminal (Linux/MacOS). To compile its source code into executable file you can use one of the popular IDEs. I recommend [VS Code](https://code.visualstudio.com/) for this. Below you will useful information how to set up VS Code for work with c++ code using the GCC compiler. Its very simple and shouldn't take your more than 5 minutes. 46 | 47 | * getting started with C/C++ for Visual Studio Code: https://code.visualstudio.com/docs/languages/cpp 48 | * using GCC on Linux: https://code.visualstudio.com/docs/cpp/config-linux 49 | * using GCC with MinGW on Windows: https://code.visualstudio.com/docs/cpp/config-mingw 50 | * Please change the `"${file}"` element of the `tasks.json` file into `"${fileDirname}/*.cpp"` (under Linux/MacOS) or `"${fileDirname}\\**.cpp"` (under Windows). This will allow to build projects which consist of more then one `*.cpp` file. 51 | 52 | ### Labs #2 53 | 54 | The task is to build the `optionPricer2` package on the basis of code of the `programs/prog2` application. Once we do this, we will then use function/functions of this package in the little playground provided inside the script `scripts/optionPricer2Application.R`. 55 | 56 | ### Creating an R package 57 | 58 | Below you will find steps to create an Rcpp package named `optionPricer2`, where code from `progs/prog2` is used. 59 | 60 | 1. In RStudio: 61 | 62 | * `File` -> `New Project` -> `New Directory` -> `R Package` -> 63 | * Type: package `w/ Rcpp` 64 | * Package name: `optionPricer2` 65 | * give appropriate path 66 | 67 | 2. Copy your source files (`*.cpp`) and header files (`*.h`) from `progs/prog2` to `projects/optionsPricer2/src/` folder. 68 | 69 | Although you may safely delete `RcppExports.cpp` and `rcpp_hello.cpp`, I would recommend to keep them, as they may serve in the next steps as hints in terms of syntax. 70 | 71 | 3. Include necessary changes `projects/optionsPricer2/src/main.cpp`: 72 | 73 | * add before definition of your function: `using namespace Rcpp;` 74 | * add before definition of your function: `#include ` 75 | * add directly before definition of your function: `// [[Rcpp::export]]` 76 | * change the name of the `main()` function and type of returned value according to your needs 77 | * include necessary arguments for this function 78 | * double check the returned object at the end of the function 79 | 80 | Repeat these actions for any other function you would like to include in the package. 81 | 82 | 4. Fill free to edit DESCRIPTION file. However be careful! You must not change names of fields or change the inner structure of the file. 83 | 84 | 5. Build your package: either source package or binary package, or both of them: 85 | 86 | * `menu Build` -> `Build Source Package` 87 | * `menu Build` -> `Build Binary Package` 88 | 89 | This will create `zip` and/or `tar.gz` files with your package. By default, they will be located next to the folder with the package. 90 | 91 | 6. This archive file (`*.zip` or `*.tar.gz`) could be then installed with: 92 | 93 | * `install.packages("binary-package-filename.zip", type = "binaries", repos = NULL)` 94 | * `install.packages("source-package-filename.tar.gz", type = "source", repos = NULL)` 95 | 96 | See `scripts/optionPricer2Application.R` to examine the example. 97 | 98 | 99 | 100 | ## Grading Policy 101 | 102 | * Each participant will get an assignment with an individual home project. 103 | * The aim of the project will be to apply Monte Carlo techniques to provide an approximation of the path-dependent option. 104 | * The solution should be delivered in a form of a Rcpp-package, along with a short implementation of the function/functions which are provided by this package. 105 | * All codes from the lectures and labs can be used in the solutions. 106 | * A short report will be required. 107 | * Solutions in a form of a private Github/GitLab/Bitbucket repository will get premium points! 108 | 109 | ## Happy learning! :-) 110 | 111 | * If you need any sort of help, feel free to message me. 112 | * Do not be afraid to ask question! Asking question is super important to your growth! 113 | * No question is a stupid question! 114 | * I'm available on p.sakowski@uw.edu.pl 115 | -------------------------------------------------------------------------------- /scripts/intro2Rcpp.R: -------------------------------------------------------------------------------- 1 | #################################################################### 2 | # APPLIED FINANCE # 3 | # Path-dependent option pricing with Monte Carlo and Rcpp package # 4 | # labs01: Introduction to the Rcpp package # 5 | # Paweł Sakowski # 6 | # University of Warsaw # 7 | #################################################################### 8 | 9 | 10 | # loading packages 11 | library(inline) # allows to use C++ inline - within R code 12 | library(Rcpp) # Rccp package by Dirk Eddelbuettel 13 | library(tidyverse) 14 | library(xts) 15 | library(dygraphs) 16 | 17 | # 1. USING cppFunction() FUNCTION ============================================== 18 | cppFunction(" 19 | double getZeroCouponBondPrice(int n, 20 | double ytm, 21 | double f){ 22 | double price = 0; 23 | price += f/pow(1+ytm, double(n)) ; 24 | return price; 25 | } 26 | ") 27 | 28 | # call the function 29 | getZeroCouponBondPrice(10, 0.1, 1000) 30 | 31 | # build an R function 32 | getZeroCouponBondPrice1 <- function (r) { 33 | return(getZeroCouponBondPrice(10, r, 1000)) 34 | } 35 | 36 | ytm <- seq(0.001, 0.1, by = 0.001) 37 | getZeroCouponBondPrice1(0.05) 38 | zeroCouponBondPrices <- sapply(ytm, getZeroCouponBondPrice1) 39 | 40 | # a simple plot 41 | plot(ytm, zeroCouponBondPrices) 42 | 43 | # same plot using ggplot2 package 44 | tibble( 45 | ytm = ytm, 46 | prices = zeroCouponBondPrices 47 | ) %>% 48 | ggplot(aes(x = ytm, y = zeroCouponBondPrices)) + 49 | geom_point(col = "red") + 50 | labs( 51 | x = "yield to maturity", 52 | y = "price of zero-coupon bond", 53 | title = "Zero-coupon bond price vs. yield to maturity", 54 | caption = "source: own calculations" 55 | ) 56 | 57 | 58 | 59 | # EXERCISE 1 =================================================================== 60 | 61 | # Write and implement in R a similar function for coupon bonds. 62 | # Build an R function based on that function and 63 | # give it a name "getBondPrice1', as it will be used in the next steps. 64 | 65 | source("solutions/exercise01.R") 66 | 67 | 68 | # 2. VISUALISATION OF TWO RELATIONSHIPS ======================================== 69 | tibble( 70 | ytm = ytm, 71 | zeroCouponBondPrices = zeroCouponBondPrices, 72 | couponBondPrices = couponBondPrices 73 | ) %>% 74 | pivot_longer(cols = !ytm) %>% 75 | ggplot(aes(ytm, value, col = name)) + 76 | geom_point() + 77 | labs( 78 | x = "yield to maturity", 79 | y = "price of a bond", 80 | title = "Bond price vs. yield to maturity", 81 | caption = "source: own calculations", 82 | colour = "type of a bond" 83 | ) 84 | 85 | 86 | 87 | # 3. USING sourceCpp() FUNCTION ================================================ 88 | 89 | # compile c++ functions from external source file using sourceCpp() 90 | sourceCpp("functions/getZeroCouponBondPrice2.cpp") 91 | sourceCpp("functions/getCouponBondPrice2.cpp") 92 | 93 | # call the functions 94 | getZeroCouponBondPrice2(10, 0.06, 1000) 95 | getCouponBondPrice2(10, 0.05, 12, 0.06, 1000) 96 | 97 | 98 | # 4. MEASURING EFFICIENCY OF MONTE CARLO SIMULATIONS =========================== 99 | # Example: finding approximation of the Pi value 100 | 101 | # first, let's make a visualization of the task 102 | N <- 10000 103 | tibble( 104 | x = runif(N), 105 | y = runif(N) 106 | ) %>% 107 | mutate(d = sqrt(x ^ 2 + y ^ 2), 108 | d = as_factor(d < 1)) %>% 109 | ggplot(aes(x, y, col = d)) + 110 | geom_point(size = 0.5) + 111 | coord_fixed(ratio = 1) + 112 | labs( 113 | x = "", 114 | y = "", 115 | title = paste0(N, " points with random cooridnates"), 116 | subtitle = "x ~ U(0,1), y ~ U(0,1)", 117 | caption = "source: own calculations", 118 | colour = "d < 1" 119 | ) + 120 | theme_bw() 121 | 122 | 123 | # 4a. An R function based on loop 124 | getPiR1 <- function(N) { 125 | counter = 0; 126 | for (i in 1:N){ 127 | x <- runif(1) 128 | y <- runif(1) 129 | d <- sqrt(x^2 + y^2) 130 | if (d <= 1) counter = counter + 1; 131 | } 132 | return(4 * counter / N) 133 | } 134 | 135 | # 4b. An R function based on vectors 136 | getPiR2 <- function(N) { 137 | x <- runif(N) 138 | y <- runif(N) 139 | d <- sqrt(x ^ 2 + y ^ 2) 140 | return(4 * sum(d <= 1.0) / N) 141 | } 142 | 143 | # 4c. A C++ function based on loop 144 | cppFunction(" 145 | double getPiCpp1(const int N) { 146 | //RNGScope scope; // ensure RNG gets set/reset 147 | 148 | double x; 149 | double y; 150 | double d; 151 | 152 | int long counter = 0; 153 | 154 | for(int i = 0; i < N; i++){ 155 | x = ((double)rand()/RAND_MAX); 156 | y = ((double)rand()/RAND_MAX); 157 | d = sqrt(x * x + y * y); 158 | if (d <= 1) counter++; 159 | } 160 | 161 | return (4.0 * counter) / N; 162 | 163 | } 164 | ") 165 | 166 | # verification 167 | getPiCpp1(N = 1000000) 168 | 169 | # 4d. A C++ function based on vector 170 | cppFunction(" 171 | double getPiCpp2(const int N) { 172 | RNGScope scope; // ensure RNG gets set/reset 173 | NumericVector x = runif(N); 174 | NumericVector y = runif(N); 175 | NumericVector d = sqrt(x * x + y * y); 176 | 177 | return 4.0 * sum(d <= 1.0) / N; 178 | }") 179 | 180 | # verification 181 | getPiCpp2(N = 1000000) 182 | 183 | 184 | # comparison 185 | library(rbenchmark) 186 | N <- 10000 187 | set.seed(123) 188 | benchmark(getPiR1(N), getPiR2(N), getPiCpp1(N), getPiCpp2(N))[, 1:4] 189 | 190 | 191 | # 5. SIMPLE FUNCTION with rolling windows ====================================== 192 | # compile c++ code with a function definition 193 | sourceCpp("functions/getCumSum.cpp") 194 | 195 | nObs <- 1000 196 | randomWalkData <- 197 | tibble( 198 | obs = 1:nObs, 199 | r = rnorm(nObs) 200 | ) %>% 201 | mutate(rw = getCumSum(r)) 202 | 203 | randomWalkData %>% 204 | pivot_longer(cols = !obs) %>% 205 | ggplot(aes(x = obs, y = value, col = as_factor(name))) + 206 | geom_line() + 207 | facet_grid(name ~ ., scales = "free") + 208 | labs( 209 | x = "observations", 210 | y = "value", 211 | title = "Random walk simulation", 212 | subtitle = " ~N(0,1) simulated increments and their cumulative sum", 213 | caption = "source: own calculations", 214 | colour = "variable" 215 | ) 216 | 217 | # the same plot using the dygraphs package 218 | xts(randomWalkData$rw, 219 | order.by = as.Date(Sys.Date() - nObs + randomWalkData$obs) 220 | ) %>% 221 | dygraph( 222 | main = "Random walk simulation" 223 | ) %>% 224 | dyRangeSelector(height = 40) 225 | 226 | # EXERCISE 2 =================================================================== 227 | # On basis of the example above (6.) create a function which calculates 228 | # simple moving average with given memory: getSMA(x, k). 229 | 230 | source("solutions/exercise02.R") 231 | 232 | # EXERCISE 3 =================================================================== 233 | # On basis of the example above (6.) create a function which calculates 234 | # exponentially weighted moving average with given memory: getEWMA(x, k). 235 | 236 | source("solutions/exercise03.R") 237 | 238 | # EXERCISE 4 =================================================================== 239 | # On basis of the example above (6.) create a function which calculates 240 | # moving window standard deviation with given memory: getRunningSD(x, k). 241 | 242 | # EXERCISE 5 =================================================================== 243 | # On basis of the example above (6.) create a function which calculates 244 | # moving window median with given memory: getRunningMedian(x, k). 245 | 246 | # EXERCISE 6 =================================================================== 247 | # On basis of the example above (6.) create a function which calculates 248 | # moving window quartile with given memory: getRunningQuartile(x, k, alpha). 249 | 250 | 251 | 252 | -------------------------------------------------------------------------------- /scripts/pricingComparison.R: -------------------------------------------------------------------------------- 1 | #################################################################### 2 | # APPLIED FINANCE # 3 | # Path-dependent option pricing with Monte Carlo and Rcpp package # 4 | # lecture02: comparison of option pricing techniques # 5 | # Paweł Sakowski # 6 | # University of Warsaw # 7 | #################################################################### 8 | 9 | # loading packages 10 | library(tidyverse) 11 | 12 | 13 | # 1. European Call pricing using loops in R ==================================== 14 | 15 | # define option parameters 16 | Spot <- 95 17 | Strike <- 100 18 | r <- 0.06 19 | Vol <- 0.2 20 | Expiry <- 0.5 21 | nReps <- 100 22 | 23 | runningSum <- 0 24 | 25 | variance <- Vol * Vol * Expiry; 26 | rootVariance <- sqrt(variance); 27 | itoCorrection <- -0.5 * variance; 28 | movedSpot <- Spot * exp(r * Expiry + itoCorrection); 29 | 30 | for (i in 1:nReps) { 31 | thisGaussian = rnorm(1); 32 | thisSpot = movedSpot * exp(rootVariance * thisGaussian); 33 | thisPayoff = thisSpot - Strike; 34 | if (thisPayoff > 0) { 35 | runningSum = runningSum + thisPayoff 36 | } 37 | } 38 | 39 | price <- runningSum / nReps * exp(-r * Expiry); 40 | price 41 | 42 | 43 | # the same as above in a single function 44 | getCallPrice <- function(Spot = 95, 45 | Strike = 100, 46 | r = 0.06, 47 | Vol = 0.2, 48 | Expiry = 0.5, 49 | nReps = 100) { 50 | runningSum <- 0 51 | 52 | variance <- Vol * Vol * Expiry; 53 | rootVariance <- sqrt(variance); 54 | itoCorrection <- -0.5 * variance; 55 | movedSpot <- Spot * exp(r * Expiry + itoCorrection); 56 | 57 | for (i in 1:nReps) { 58 | thisGaussian = rnorm(1); 59 | thisSpot = movedSpot * exp(rootVariance * thisGaussian); 60 | thisPayoff = thisSpot - Strike; 61 | if (thisPayoff > 0) { 62 | runningSum = runningSum + thisPayoff 63 | } 64 | } 65 | 66 | price <- runningSum / nReps * exp(-r * Expiry); 67 | return(price) 68 | } 69 | 70 | time0 <- Sys.time() 71 | getCallPrice(nReps = 1000000) 72 | time1 <- Sys.time() 73 | time1 - time0 74 | 75 | 76 | 77 | # 2. European Call pricing using vectors in R ================================== 78 | 79 | getCallPrice2 <- function(Spot = 95, 80 | Strike = 100, 81 | r = 0.06, 82 | Vol = 0.2, 83 | Expiry = 0.5, 84 | nReps = 100) { 85 | 86 | variance <- Vol * Vol * Expiry 87 | rootVariance <- sqrt(variance) 88 | itoCorrection <- -0.5 * variance 89 | movedSpot <- Spot * exp(r * Expiry + itoCorrection) 90 | 91 | thisGaussian <- rnorm(nReps) 92 | thisSpot <- movedSpot * exp(rootVariance * thisGaussian) 93 | thisPayoff <- thisSpot - Strike 94 | thisPayoff[thisPayoff < 0] <- 0 95 | 96 | price <- mean(thisPayoff) * exp(-r * Expiry); 97 | return(price) 98 | } 99 | 100 | time0 <- Sys.time() 101 | getCallPrice2(nReps = 1000000) 102 | time1 <- Sys.time() 103 | time1 - time0 104 | 105 | 106 | # 3. European Call pricing using loops in C++, via Rcpp ======================== 107 | # (see other project in optionPricing folder) 108 | 109 | # install from binary package 110 | # (please correct filename if necessary!) 111 | install.packages("packages/optionPricer1_1.0_R_x86_64-pc-linux-gnu.tar.gz", 112 | type = "binaries", repos = NULL) 113 | 114 | # install from source package 115 | # (please correct filename if necessary!) 116 | install.packages("packages/optionPricer1_1.0.tar.gz", 117 | type = "source", repos = NULL) 118 | 119 | # Call the function 120 | time0 <- Sys.time() 121 | optionPricer1::getCallPrice(NumberOfPaths = 1000000) 122 | time1 <- Sys.time() 123 | time1 - time0 124 | 125 | # build an R function: option price vs. time to maturity 126 | getCallPrice3 <- function(expiry) { 127 | return(optionPricer1::getCallPrice(Expiry = expiry, 128 | Strike = Strike, 129 | Spot = Spot, 130 | Vol = Vol, 131 | r = r, 132 | NumberOfPaths = 1000000)) 133 | } 134 | 135 | # call the function 136 | getCallPrice3(0.5) 137 | 138 | # arguments values of values of function 139 | expiry <- seq(0.01, 0.1, by = 0.001) 140 | prices <- sapply(expiry, getCallPrice3) 141 | 142 | # relationship between expiry and option price 143 | tibble( 144 | expiry = expiry, 145 | prices = prices 146 | ) %>% 147 | ggplot(aes(expiry, prices)) + 148 | geom_point(col = "red") + 149 | labs( 150 | x = "time to maturity", 151 | y = "price of European call option", 152 | title = "price of European call option vs. time to maturity", 153 | caption = "source: own calculations with the optionPricer1 package") 154 | 155 | detach("package:optionPricer1") 156 | remove.packages("optionPricer1") 157 | 158 | 159 | # 4. vectors in R with antithetic sampling ===================================== 160 | getCallPrice4 <- function(Spot = 95, 161 | Strike = 100, 162 | r = 0.06, 163 | Vol = 0.2, 164 | Expiry = 0.5, 165 | nReps = 100, 166 | antithetic = T) { 167 | 168 | variance <- Vol * Vol * Expiry 169 | rootVariance <- sqrt(variance) 170 | itoCorrection <- -0.5 * variance 171 | movedSpot <- Spot * exp(r * Expiry + itoCorrection) 172 | 173 | thisGaussian <- rnorm(nReps) 174 | thisSpot <- movedSpot * exp(rootVariance * thisGaussian) 175 | thisPayoff <- thisSpot - Strike 176 | thisPayoff[thisPayoff < 0] <- 0 177 | 178 | if (antithetic) { 179 | thisAntitheticGaussian <- -thisGaussian 180 | thisAntitheticSpot <- 181 | movedSpot * exp(rootVariance * thisAntitheticGaussian) 182 | thisAntitheticPayoff <- thisAntitheticSpot - Strike 183 | thisAntitheticPayoff[thisAntitheticPayoff < 0] <- 0 184 | price <- mean((thisAntitheticPayoff + thisPayoff) / 2) * exp(-r * Expiry) 185 | } else { 186 | price <- mean(thisPayoff) * exp(-r * Expiry) 187 | } 188 | 189 | return(price) 190 | } 191 | 192 | time0 <- Sys.time() 193 | getCallPrice4(nReps = 10000, antithetic = T) 194 | time1 <- Sys.time() 195 | time1 - time0 196 | 197 | 198 | # 5. comparison of standard deviation of option prices approximations ========== 199 | 200 | nReplications <- 1000 201 | 202 | # 5.1 no antithetic sampling, 1000 paths 203 | prices1 <- replicate(nReplications, 204 | getCallPrice2(nReps = 1000)) 205 | mean(prices1) 206 | sd(prices1) 207 | 208 | prices1a <- replicate(nReplications, 209 | getCallPrice4(nReps = 1000, antithetic = F)) 210 | mean(prices1a) 211 | sd(prices1a) 212 | 213 | # 5.2 no antithetic sampling, 100000 paths 214 | prices2 <- replicate(nReplications, 215 | getCallPrice2(nReps = 100000)) 216 | mean(prices2) 217 | sd(prices2) 218 | 219 | prices2a <- replicate(nReplications, 220 | getCallPrice4(nReps = 100000, antithetic = F)) 221 | mean(prices2a) 222 | sd(prices2a) 223 | 224 | # 5.3 with antithetic sampling, 500 paths 225 | prices3 <- replicate(nReplications, 226 | getCallPrice4(nReps = 500, antithetic = T)) 227 | mean(prices3) 228 | sd(prices3) 229 | 230 | # 5.4 with antithetic sampling, 50000 paths 231 | prices4 <- replicate(nReplications, 232 | getCallPrice4(nReps = 50000, antithetic = T)) 233 | mean(prices4) 234 | sd(prices4) 235 | 236 | 237 | pricesData <- 238 | tibble( 239 | prices = prices1, 240 | group = "prices1" 241 | ) %>% 242 | bind_rows( 243 | tibble( 244 | prices = prices1a, 245 | group = "prices1a" 246 | ) 247 | ) %>% 248 | bind_rows( 249 | tibble( 250 | prices = prices2, 251 | group = "prices2" 252 | ) 253 | ) %>% 254 | bind_rows( 255 | tibble( 256 | prices = prices2a, 257 | group = "prices2a" 258 | ) 259 | ) %>% 260 | bind_rows( 261 | tibble( 262 | prices = prices3, 263 | group = "prices3" 264 | ) 265 | ) %>% 266 | bind_rows( 267 | tibble( 268 | prices = prices4, 269 | group = "prices4" 270 | ) 271 | ) 272 | 273 | pricesData %>% 274 | group_by(group) %>% 275 | summarize(n = n(), 276 | mean = mean(prices), 277 | sd = sd(prices)) 278 | 279 | pricesData%>% 280 | ggplot(aes(prices, group)) + 281 | geom_boxplot() + 282 | labs( 283 | title = "Dispersion of option prices approximations", 284 | caption = "source: own calculations with the optionPricer1 package") 285 | 286 | 287 | 288 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /slides/slides.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Applied Finance" 3 | subtitle: | 4 | | Path-dependent option pricing with 5 | | Monte Carlo and the `Rcpp` package 6 | author: | 7 | | Paweł Sakowski 8 | | Department of Quantitative Finance 9 | date: | 10 | | academic year 2025/2026 11 | | ![](img/WNE_UW_EN.pdf) 12 | fontsize: 10pt 13 | output: 14 | beamer_presentation: 15 | theme: "default" 16 | colortheme: "dolphin" 17 | #includes: 18 | # in_header: style_beamer.tex 19 | toc: false 20 | fig_caption: false 21 | highlight: tango 22 | editor_options: 23 | chunk_output_type: console 24 | --- 25 | 26 | ```{r setup, include = FALSE} 27 | knitr::opts_chunk$set(echo = TRUE, cache = TRUE) 28 | ``` 29 | 30 | ```{r eval = F, echo = F} 31 | # to install fOptions packages, please use: 32 | # install.packages("http://cran.nexr.com/src/contrib/Archive/fOptions/fOptions_3022.85.tar.gz", 33 | # repos = NULL) 34 | ``` 35 | 36 | 37 | ```{r, echo = FALSE , warning = FALSE, message = FALSE, cache = FALSE} 38 | library(knitr) 39 | library(tidyverse) 40 | library(RQuantLib) 41 | library(here) 42 | ``` 43 | 44 | 45 | # Options 46 | 47 | In finance, an **option** is: 48 | 49 | * an agreement, which gives the holder a **right** 50 | * to **buy** or to **sell** 51 | * a certain underlying instrument 52 | * for a given price (*exercise price*) 53 | * at a given moment in futures (*expiry date*). 54 | 55 | Since the option offers a right, not an obligation, the holder can decide whether to exercise the option or not. 56 | 57 | That right has its price - the price of the option, also called **option premium**. 58 | 59 | # Underlying instruments 60 | 61 | * **commodity options** -- the underlying instrument is various commodities: 62 | * precious metals (gold, silver, platinum), 63 | * industrial commodities (copper, steel) 64 | * agricultural commodities (wheat, corn, livestock), 65 | 66 | * **financial options** -- the underlying is a financial instrument 67 | * equity options (stock options) -- stocks of companies quoted on stock exchange, 68 | * index options -- written on equity indices, 69 | * currency options -- underlying is currency (exchange rate) 70 | * interest rate options -- underlying is a security: bond, bill, 71 | * futures options -- underlying is a futures contract written on other index/security/currency/commodity 72 | 73 | # Types of options 74 | 75 | We can distinguish two basic option types: 76 | 77 | * **CALL** option -- gives the holder right to **buy** a given amount of underlying instrument for a given price at the given moment in future 78 | 79 | * **PUT** option -- gives the holder right to **sell** a given amount of underlying instrument for a given price at the given moment in future 80 | 81 | # Option characteristics 82 | 83 | * **exercise price** (**strike price**) -- price at which option is exercised, it is determined at the moment of option writing and remains constant 84 | 85 | * **option price** (**option premium**) -- price of the right which is acquired by the option holder (buyer), it is a market value of the option which is time varying 86 | 87 | * **underlying price** -- market value of the underlying instrument for which option is written 88 | 89 | * **time to maturity** (**time to expiration**, **expiry**) -- time after which option cannot be exercised and becomes void. 90 | 91 | * **exercise dat**e – moment in time (or interval) when option can be exercised. We can distinguish two types: **American option** and **European option**. Holder of an American option can exercise it at any moment until exercise date. Holder of an European option can exercise only at exercise date. 92 | 93 | # Right vs. obligation 94 | 95 | * Contrary to futures contracts, option is **a right**, not an obligation. 96 | 97 | * When holder wants to make use of that right, it means that the option is exercised (executed). 98 | 99 | * Option is a contract where there are to participants: 100 | * **Holder** of the option, who posses the right to exercise the call/put option. Hence he can buy/sell the underlying instrument for the given strike price at a given moment in future. Holder takes long position in option contract. 101 | * **Writer** of the option, who posses the obligation to exercise the call/put option. Hence for call option he has to sell the underlying instrument, and for put option he has to buy underlying instrument (for the given strike price at a given moment in future). Writer takes short position in option contract. 102 | 103 | # Four basic payoff profiles 104 | 105 | * Hence, we can distinguish four basic positions in option contracts: 106 | 107 | * **Long Call** -- long position in call option 108 | * **Long Put** -- long position in put option 109 | * **Short Call** -- short position in call option 110 | * **Short Put** -- short position in put option 111 | 112 | * Decision, whether to exercise the option is based on comparison of the strike price with current market price of underlying instrument. 113 | 114 | * Holder of the call option will make use of that right if the current market price of underlying instrument $(S)$ is higher than the strike price $(X)$. 115 | 116 | * Holder of the put option will make use of that right if the current market price of underlying instrument $(S)$ is less than the strike price $(X)$. 117 | 118 | # Four basic payoff profiles 119 | \small 120 | To illustrate the payoff profiles, we take (arbitrarily) following assumptions: 121 | 122 | ```{r} 123 | X <- 110 # strike price 124 | Time <- 0.5 # time to maturity 125 | r <- 0.06 # risk-free rate 126 | q <- 0 # dividend rate 127 | sigma <- 0.2 # volatility 128 | b <- r - q 129 | ``` 130 | 131 | Price of the European call is: 132 | ```{r} 133 | library(RQuantLib) 134 | (price <- 135 | EuropeanOption(type = "call", underlying = 110, strike = X, 136 | dividendYield = q, riskFreeRate = r, 137 | maturity = Time, volatility = sigma)$value) 138 | ``` 139 | (see next slides for the Black-Scholes formula) 140 | 141 | # Four basic payoff profiles 142 | 143 | We will use the following code: 144 | \small 145 | ```{r, eval = F} 146 | library(tidyverse); library(ggthemes) 147 | S <- seq(90, 140, 1) 148 | longCallPayoffs <- map_dbl(S, \(S) max(S - X, 0)) 149 | tibble(x = S, y = longCallPayoffs - price) |> 150 | ggplot(aes(x = x, y = y)) + 151 | geom_line(linewidth = 1, col = "red") + 152 | ylim(-10, 20) + theme_minimal() + 153 | labs(subtitle = paste0("Black-Scholes premium, X = ", X, 154 | ", ttm = ", Time, 155 | ", r = ", r, 156 | ", q = ", q, 157 | ", sigma = ", sigma), 158 | y = "payoffs", 159 | x = "underlying price at maturity date", 160 | title = "payoff profile for long European call option", 161 | caption = "Source: own calculations") + 162 | geom_hline(yintercept = 0, linetype = "solid", 163 | color = "black", linewidth = 0.25) 164 | ``` 165 | 166 | # Long Call 167 | 168 | ```{r, echo = F, warning=F} 169 | library(tidyverse); library(ggthemes) 170 | S <- seq(90, 140, 1) 171 | longCallPayoffs <- map_dbl(S, \(S) max(S - X, 0)) 172 | tibble(x = S, y = longCallPayoffs - price) |> 173 | ggplot(aes(x = x, y = y)) + 174 | geom_line(linewidth = 1, col = "red") + 175 | ylim(-10, 20) + theme_minimal() + 176 | labs(subtitle = paste0("Black-Scholes premium, X = ", X, 177 | ", ttm = ", Time, 178 | ", r = ", r, 179 | ", q = ", q, 180 | ", sigma = ", sigma), 181 | y = "payoffs", 182 | x = "underlying price at maturity date", 183 | title = "payoff profile for long European call option", 184 | caption = "Source: own calculations") + 185 | geom_hline(yintercept = 0, linetype = "solid", 186 | color = "black", linewidth = 0.25) 187 | ``` 188 | 189 | # Short Call 190 | 191 | ```{r, echo = F, warning=F} 192 | data.frame(x = S, y = price - longCallPayoffs) |> 193 | ggplot(aes(x = x, y = y)) + 194 | geom_line(linewidth = 1, col = "red") + 195 | ylim(-20, 10) + theme_minimal() + 196 | labs(subtitle = paste0("Black-Scholes premium, X = ", X, 197 | ", ttm = ", Time, 198 | ", r = ", r, 199 | ", q = ", q, 200 | ", sigma = ", sigma), 201 | y = "payoffs", 202 | x = "underlying price at maturity date", 203 | title = "payoff profile for short European call option", 204 | caption = "Source: own calculations") + 205 | geom_hline(yintercept = 0, linetype = "solid", 206 | color = "black", linewidth = 0.25) 207 | ``` 208 | 209 | # Long Put 210 | 211 | ```{r, echo = F, warning=F} 212 | S <- seq(80, 130, 1) 213 | longPutPayoffs <- map_dbl(S, \(S) max(X - S, 0)) 214 | tibble(x = S, y = longPutPayoffs - price) |> 215 | ggplot(aes(x = x, y = y)) + 216 | geom_line(linewidth = 1, col = "red") + 217 | ylim(-10, 20) + theme_minimal() + 218 | labs(subtitle = paste0("Black-Scholes premium, X = ", X, 219 | ", ttm = ", Time, 220 | ", r = ", r, 221 | ", q = ", q, 222 | ", sigma = ", sigma), 223 | y = "payoffs", 224 | x = "underlying price at maturity date", 225 | title = "payoff profile for long European put option", 226 | caption = "Source: own calculations") + 227 | geom_hline(yintercept = 0, linetype = "solid", 228 | color = "black", linewidth = 0.25) 229 | ``` 230 | 231 | # Short Put 232 | 233 | ```{r, echo = F, warning=F} 234 | tibble(x = S, y = price - longPutPayoffs) |> 235 | ggplot(aes(x = x, y = y)) + 236 | geom_line(linewidth = 1, col = "red") + 237 | ylim(-20, 10) + theme_minimal() + 238 | labs(subtitle = paste0("Black-Scholes premium, X = ", X, 239 | ", ttm = ", Time, 240 | ", r = ", r, 241 | ", q = ", q, 242 | ", sigma = ", sigma), 243 | y = "payoffs", 244 | x = "underlying price at maturity date", 245 | title = "payoff profile for short European put option", 246 | caption = "Source: own calculations") + 247 | geom_hline(yintercept = 0, linetype = "solid", 248 | color = "black", linewidth = 0.25) 249 | ``` 250 | 251 | # Exercising the option contract 252 | 253 | There could be three scenarios when taking decision whether to exercise the option or not: 254 | 255 | * option is **in-the-money**, if it is worth exercising it. For a call option it means that $S > K$, while for a put option $S < K$ 256 | 257 | * option is **out-of-the-money**, if it is worth exercising it. For a call option it means that $S < K$, while for a put option $S > K$ 258 | 259 | * option is **at-the-money**, if the strike price is equal to current market price of underlying: $S = K$ 260 | 261 | # Value of the option 262 | 263 | Value of the option can be decomposed into to parts: 264 | 265 | * **intrinsic value** -- is positive when option is **in-the-money**. If the option is at-the-money or out-of-the-money then its intrinsic value is zero. Generally, for call option instrinsic value is defined as $\max(S - K, 0)$, while for the put option $\max(K - S, 0)$. 266 | 267 | * **time value** -- is positive since price of underlying instrument changes over time. Time value converges to zero until option maturity. 268 | 269 | Hence, we can write: 270 | 271 | * value of the option = intrinsic value + time value 272 | 273 | # Properties of option contract 274 | 275 | For a call option: 276 | 277 | * Option value is non-negative, as the option itself is a right, rather than obligation. The holder of the option will make use of that right only if it makes profit for him. 278 | 279 | * Option value cannot be lower than its intrinsic value -- otherwise risk-free arbitrage could be possible. 280 | 281 | * Option value is at least equal to (absolute) difference between its strike price and current price of underlying instrument. 282 | 283 | * Value of American option is not less than value of European option as the American option gives the holder the same rights as European plus additionally the right to exercise the option at any moment until option maturity. 284 | 285 | # Factors influencing option premium #1 286 | 287 | 1. **strike price** -- influences negatively call option value, positively put option value. 288 | 289 | 2. **underlying price** -- its increase results in higher value of call option and lower value of put option, while its decrease results in lower value of call option and higher value of put option. 290 | 291 | 3. **time to maturity** -- influences positively both call and put option values. The longer time to maturity, the higher probability that the option becomes in-the-money. 292 | 293 | # Factors influencing option premium #2 294 | 295 | 4. **volatility of underlying prices** -- influences positively both call and put option values. The higher the volatility, the higher probability that the option becomes in-the-money. 296 | 297 | 5. **risk-free rate** -- influences positively price of call option and negatively price of put option. Result of increasing the risk-free rate is similar to effect of decrease of strike price, as for higher risk-free rate the present value of strike price is lower. 298 | 299 | 6. **dividend rate** -- influences negatively value of call option and positively value of put option. Dividend payoffs decreases value of the underlying instrument, hence the effect is similar when the current price of underlying instruments declines. 300 | 301 | 302 | # Market prices 303 | ```{r, eval = T, echo = F, message = F} 304 | dt <- read_csv(here("data/quotes_2025-12-01.csv")) 305 | dt |> 306 | filter(expiration == "2025-12-19") |> 307 | filter(option_type == "C") |> 308 | mutate(strike = strike |> as.factor()) |> 309 | ggplot(aes(quote_datetime, mid, color = strike)) + 310 | geom_line() + 311 | labs(title = "Mid-quotes of call options for S&P 500", 312 | subtitle = "quotes for 2025-12-01, expiration = 2025-12-29", 313 | x = "", y = "") + 314 | theme_minimal() 315 | ``` 316 | 317 | # Market prices 318 | ```{r, eval = T, echo = F} 319 | dt |> 320 | filter(expiration == "2025-12-19") |> 321 | filter(option_type == "P") |> 322 | mutate(strike = strike |> as.factor()) |> 323 | ggplot(aes(quote_datetime, mid, color = strike)) + 324 | geom_line() + 325 | labs(title = "Mid-quotes of put options for S&P 500", 326 | subtitle = "quotes for 2025-12-01, expiration = 2025-12-29", 327 | x = "", y = "") + 328 | theme_minimal() 329 | ``` 330 | 331 | # Market prices 332 | ```{r, eval = T, echo = F} 333 | dt |> 334 | filter(strike == 6800) |> 335 | filter(option_type == "C") |> 336 | filter(between(expiration, as.Date("2025-12-02"), as.Date("2026-06-30"))) |> 337 | mutate(expiration = expiration |> as.factor()) |> 338 | ggplot(aes(quote_datetime, mid, color = expiration)) + 339 | geom_line() + 340 | labs(title = "Mid-quotes of call options for S&P 500", 341 | subtitle = "quotes for 2025-12-01, strike = 6800", 342 | x = "", y = "") + 343 | theme_minimal() 344 | ``` 345 | 346 | # Market prices 347 | ```{r, eval = T, echo = F} 348 | dt |> 349 | filter(strike == 6800) |> 350 | filter(option_type == "P") |> 351 | filter(between(expiration, as.Date("2025-12-02"), as.Date("2026-06-30"))) |> 352 | mutate(expiration = expiration |> as.factor()) |> 353 | ggplot(aes(quote_datetime, mid, color = expiration)) + 354 | geom_line() + 355 | labs(title = "Mid-quotes of put options for S&P 500", 356 | subtitle = "quotes for 2025-12-01, strike = 6800", 357 | x = "", y = "") + 358 | theme_minimal() 359 | ``` 360 | 361 | 362 | # Black-Scholes-Merton (BSM) Model 363 | 364 | The most popular model for pricing options for underlying instruments not paying dividend has been proposed in 70's by Fischer Black and Myron Scholes, and modified by Robert Merton. 365 | 366 | Assumptions of the model are following: 367 | 368 | * prices of the underlying instrument follow the log-normal distribution 369 | * distribution parameters $\mu$ and $\sigma$ are constant, 370 | * no transaction costs and no taxes, 371 | * it is possible to purchase or sell any amount of stock or options or their fractions at any given time 372 | * underlying instrument does not pay dividend 373 | * risk-free arbitrage is not possible 374 | * trading is continuous 375 | * traders can borrow and invest their capital at the risk-free interest rate 376 | * risk-free interest rate $r$ is constant 377 | 378 | # Black-Scholes-Merton (BSM) Model 379 | 380 | Closed-form formula for prices of European call and put option for stocks paying no dividend: 381 | \begin{tabular}{rl}\\ 382 | CALL: & $BSC=SN(d_1)-Xe^{-rT}N(d_2)$\\ 383 | PUT: & $BSP=-SN(-d_1)+Xe^{-rT}N(-d_2)$\\ 384 | \end{tabular} 385 | where: 386 | \begin{tabular}{rl}\\ 387 | $S$ & -- price of stocks at the moment of writing\\ 388 | $X$ & -- strike price\\ 389 | $r$ & -- risk-free rate\\ 390 | $T$ & -- time to maturity\\ 391 | $\sigma$ & -- volatility of underlying prices\\ 392 | $N(\cdot)$ & -- cumulative distribution function of $N(0,1)$ 393 | \end{tabular} 394 | $$d_1=\frac{\ln(\frac{S}{X})+(r+\frac{\sigma^2}{2})T}{\sigma\sqrt{T}} \hspace{2cm} d_2=\frac{\ln(\frac{S}{X})+(r-\frac{\sigma^2}{2})T}{\sigma\sqrt{T}}=d_1-\sigma\sqrt{T}$$ 395 | 396 | # Black-Scholes-Merton (BSM) Model 397 | 398 | Prices of European call and put options for stocks which pay dividend at the continuous $g$ rate: 399 | \begin{tabular}{rl}\\ 400 | CALL: & $\mathit{BSC}=Se^{-gT}N(d_1)-Xe^{-rT}N(d_2)$\\ 401 | PUT: & $\mathit{BSP}=-Se^{-gT}N(-d_1)+Xe^{-rT}N(-d_2)$\\ 402 | \end{tabular} 403 | where: 404 | $$d_1=\frac{\ln(\frac{S}{X})+(r-g)T}{\sigma\sqrt{T}}+\frac{\sigma\sqrt{T}}{2}$$ 405 | $$d_2=\frac{\ln(\frac{S}{X})+(r-g)T}{\sigma\sqrt{T}}-\frac{\sigma\sqrt{T}}{2}=d_1-\sigma\sqrt{T}$$ 406 | 407 | # Stock price motion in Monte Carlo methods 408 | 409 | Price of the underlying asset is described by: 410 | \begin{equation} 411 | dS_t=\mu S_tdt+\sigma S_t dW_t 412 | \end{equation} 413 | and a continuously compounding risk-free rate $r$. 414 | 415 | From the BS we know that the price of a vanilla option, with expiry $T$ 416 | and pay-off $f$, is equal to 417 | \begin{equation} 418 | e^{-rT}\mathbb{E}(f(S_T)) 419 | \end{equation} 420 | where the expectation is calculated with respect to the risk-neutral process 421 | \begin{equation} 422 | \label{eq:ds} 423 | dS_t = rS_tdt + \sigma S_tdW_t 424 | \end{equation} 425 | 426 | # Stock price motion in Monte Carlo methods 427 | 428 | By passing to the log and using Ito's lemma we can solve Eq. (\ref{eq:ds}) 429 | \begin{equation} 430 | d \log S_t = \biggl(r - \frac{1}{2}\sigma^2\biggl) dt + \sigma dW_t 431 | \end{equation} 432 | which has the solution 433 | \begin{equation} 434 | \log S_t = \log S_0 + \biggl(r - \frac{1}{2}\sigma^2\biggl) t + \sigma W_t 435 | \end{equation} 436 | 437 | # Stock price motion in Monte Carlo methods 438 | 439 | Since $W_t$ is a Brownian motion, $W_T$ is distributed as $N(0,T)$ and we can write 440 | \begin{equation} 441 | W_T = \sqrt{T} N(0,1) 442 | \end{equation} 443 | which results in 444 | \begin{equation} 445 | \log S_T = \log S_0 + \Big(r - \frac{1}{2}\sigma^2\Big) T + \sigma\sqrt{T} N(0,1) 446 | \end{equation} 447 | or equivalently 448 | \begin{equation} 449 | S_T = S_0e^{(r - \frac{1}{2}\sigma^2)T + \sigma\sqrt{T} N(0,1)} 450 | \end{equation} 451 | The price of a vanilla option is therefore given by 452 | \begin{equation} 453 | e^{-rT}\mathbb{E}\big(f(S_0e^{(r - \frac{1}{2}\sigma^2)T + \sigma\sqrt{T} N(0,1)})\big) 454 | \end{equation} 455 | 456 | # Stock price motion in Monte Carlo methods 457 | This expectation is approximated by Monte Carlo simulation. 458 | 459 | From the law of large numbers we know that if $Y_j$ are a sequence of identically distributed independent random variables, then with probability 1 the sequence 460 | \begin{equation} 461 | \frac{1}{N}\sum_{j=1}^NY_j 462 | \end{equation} 463 | converges to $\mathbb{E}(Y)$. 464 | 465 | # Stock price motion in Monte Carlo methods 466 | 467 | The price $S_t$ at time $t$ starts from $S_0$ and follows 468 | 469 | $$S_t = S_0 \exp\left( \left( \mu - \frac{\sigma^2}{2} \right) t + \sigma W_t \right)$$ 470 | where $W_t$ is standard Brownian motion, $\mu$ is drift, and $\sigma$ is volatility. 471 | 472 | Thus, $$\ln(S_t / S_0) \sim \mathcal{N} \left( \left( \mu - \frac{\sigma^2}{2} \right) t, \sigma^2 t \right)$$ 473 | 474 | # Stock price motion in Monte Carlo methods 475 | 476 | The probability density function: 477 | 478 | $$f_{S_t}(s) = \frac{1}{s \sigma \sqrt{2 \pi t}} \exp \left( -\frac{ \left( \ln(s / S_0) - \left( \mu - \frac{\sigma^2}{2} \right) t \right)^2 }{ 2 \sigma^2 t } \right)$$ 479 | 480 | for $s > 0$. 481 | 482 | Expected value: $$\mathbb{E}[S_t] = S_0 e^{\mu t}$$ 483 | 484 | Variance: $$\mathrm{Var}(S_t) = S_0^2 e^{2 \mu t} (e^{\sigma^2 t} - 1)$$. 485 | 486 | 487 | # The algorithm of Monte Carlo method 488 | \begin{enumerate} 489 | \item Draw a random variable $x \sim N(0,1)$ and compute 490 | \begin{equation} 491 | f(S_0e^{(r - \frac{1}{2}\sigma^2)T + \sigma\sqrt{T}x}) 492 | \end{equation} 493 | where for European call $f (S) = (S - K)_{+}$. 494 | \item Repeat this possibly many times and calculate the average. 495 | \item Multiply this average by $e^{-rT}$. 496 | \end{enumerate} 497 | 498 | 499 | # Monte Carlo simulations 500 | 501 | ```{r, eval = F} 502 | set.seed(123) 503 | tibble( 504 | t = 1:1000, 505 | y1 = exp(cumsum(rnorm(1000, 0, 0.02))), 506 | y2 = exp(cumsum(rnorm(1000, 0, 0.02))), 507 | # ... some code removed here ... 508 | y10 = exp(cumsum(rnorm(1000, 0, 0.02))) 509 | ) |> 510 | pivot_longer(-t) |> 511 | ggplot(aes(x = t, y = value)) + 512 | geom_line(linewidth = 0.25, aes(col = name)) + 513 | theme_minimal() + 514 | labs(title = "simulated paths of underlying prices", 515 | y = "price", x = "intervals (time)", 516 | caption = "Source: own calculations") + 517 | geom_hline(yintercept = 0, linetype = "solid", 518 | color = "black", linewidth = 0.1) 519 | ``` 520 | 521 | # Monte Carlo simulations 522 | 523 | ```{r, eval = T, echo = F} 524 | set.seed(123) 525 | tibble( 526 | t = 1:1000, 527 | y1 = exp(cumsum(rnorm(1000, 0 , 0.02))), 528 | y2 = exp(cumsum(rnorm(1000, 0 , 0.02))), 529 | y3 = exp(cumsum(rnorm(1000, 0 , 0.02))), 530 | y4 = exp(cumsum(rnorm(1000, 0 , 0.02))), 531 | y5 = exp(cumsum(rnorm(1000, 0 , 0.02))), 532 | y6 = exp(cumsum(rnorm(1000, 0 , 0.02))), 533 | y7 = exp(cumsum(rnorm(1000, 0 , 0.02))), 534 | y8 = exp(cumsum(rnorm(1000, 0 , 0.02))), 535 | y9 = exp(cumsum(rnorm(1000, 0 , 0.02))), 536 | y10 = exp(cumsum(rnorm(1000, 0 , 0.02))) 537 | ) |> 538 | pivot_longer(-t) |> 539 | ggplot(aes(x = t, y = value)) + 540 | geom_line(linewidth = 0.25, aes(col = name)) + 541 | theme_minimal() + 542 | labs(title = "simulated paths of underlying prices", 543 | y = "price", x = "intervals (time)", 544 | caption = "Source: own calculations") + 545 | geom_hline(yintercept = 0, linetype = "solid", 546 | color = "black", linewidth = 0.1) 547 | ``` 548 | 549 | # Accuracy of results in the MC experiments 550 | 551 | * When estimating the result using MC methods we usually calculate the average value of possibly many single results. 552 | 553 | * The error of such approximation depends on both: 554 | 1. the number of simulations and 555 | 2. standard error of results in a single MC simulation. 556 | 557 | * The problem of accuracy of results is strictly linked with Central Limit Theorem. 558 | 559 | # Central Limit Theorem 560 | 561 | * Central Limit Theorem states that if $X_i$ are identically and independently distributed random variables with constant expected values $\mu$ and constant and finite variances $\sigma^2$ then a random variable defined as: 562 | \begin{equation} 563 | \frac{\sum_{i=1}^{n}X_i-n\mu}{\sigma\sqrt{n}} \nonumber 564 | \end{equation} 565 | converges in distribution to standard normal distribution for $n \rightarrow \infty$. 566 | 567 | * In other words, we can say that the mean from $n$-elements sample has a normal distribution: 568 | 569 | \begin{equation} 570 | \bar{X}_n \sim N\Big(\mu,\frac{\sigma}{\sqrt{n}}\Big) \nonumber 571 | \end{equation} 572 | 573 | # Central Limit Theorem 574 | 575 | * As a result, we can find $(1-\alpha)$\% confidence limits for the mean $\bar{X}_n$: 576 | \begin{equation} 577 | \Bigg [\bar{X}_n - z_{\alpha/2}\frac{\sigma}{\sqrt{n}}, \bar{X}_n + z_{1-\alpha/2}\frac{\sigma}{\sqrt{n}} \Bigg ] \nonumber 578 | \end{equation} 579 | where: 580 | 581 | * $n$ is the number of simulations in Monte Carlo experiment, 582 | * $\sigma$ is standard deviation of the result in a single MC simulation, 583 | * $z_{\alpha/2}$ is a $(\alpha/2)$\% quantile of $N(0,1)$. 584 | * $z_{1-\alpha/2}$ is a $(1-\alpha/2)$\% quantile of $N(0,1)$. 585 | 586 | # Increasing number of simulations 587 | 588 | * The easiest way to raise accuracy of MC results is to increase the number of simulations $n$. 589 | * However, this approach is not efficient since reduction of results error is proportional to $1/\sqrt{n}$ rather than $1/n$. 590 | * Consequently, this requires relatively high number of simulations which can result in unacceptable long duration time of the MC experiment. 591 | * An alternative solution is to reduce standard deviation $\sigma$ of the result in the single MC simulation. 592 | 593 | # Variance reduction techniques 594 | \begin{itemize} 595 | \item There are many ways to reduce variance of MC results: 596 | \begin{enumerate} 597 | \item \textbf{antithetic variates} 598 | \item control variates 599 | \item stratified sampling 600 | \item moment-matching 601 | \item low-discrepancy sequencing, quasi-random sequences 602 | \item importance sampling 603 | \item random number re-usage across experiments 604 | \end{enumerate} 605 | \item One of the most popular is \textbf{antithetic variates} method. 606 | \end{itemize} 607 | 608 | # Antithetic variates 609 | 610 | * Assume, that the result of a single MC simulation is calculated as the average from some two MC simulations. Therefore, we can write: 611 | \begin{equation} 612 | \bar Y = \frac{Y_1+Y_2}{2} \nonumber 613 | \end{equation} 614 | and 615 | \begin{equation} 616 | var(\bar Y) = \frac{var(Y_1)+var(Y_2)+2cov(Y_1,Y_2)}{4} \nonumber 617 | \end{equation} 618 | 619 | * If $Y_1$ and $Y_2$ are independent from each other then: 620 | \begin{equation} 621 | var(\bar Y)=\frac{var(Y_1)}{2}=\frac{var(Y_2)}{2} \nonumber 622 | \end{equation} 623 | 624 | # Antithetic variates 625 | 626 | * However, $var(\bar Y)$ can be additionally reduced if 627 | \begin{equation} 628 | cov(Y_1,Y_2)<0 \nonumber \nonumber 629 | \end{equation} 630 | 631 | * The solution is to apply antithetic variates: 632 | \begin{eqnarray} 633 | X_i \sim N(0,1) &\longrightarrow& \textrm{--} X_i \sim N(0,1) \nonumber\\ 634 | Z_i \sim U(0,1) &\longrightarrow& \textrm{1 -- } Z_i \sim U(0,1) \nonumber 635 | \end{eqnarray} 636 | 637 | * Hence, we can easily double the sample size and additionally reduce variance of results due to to negative covariance between the results from two simultaneous simulations. 638 | 639 | # Recommended readings -- options 640 | 641 | John C. Hull, *Options, Futures, and Other Derivatives* 642 | 643 | \includegraphics[height=0.6\textheight]{img/hull.jpg} 644 | 645 | # Recommended readings -- C++ #1 646 | 647 | Stephen Prata, *C++ Primer Plus (6th Edition)* 648 | 649 | \includegraphics[height=0.6\textheight]{img/prata.jpg} 650 | 651 | # Recommended readings -- C++ #2 652 | 653 | Bjarne Stroustrup, *The C++ Programming Language* 654 | 655 | \includegraphics[height=0.6\textheight]{img/stroustrup.jpg} 656 | 657 | # Recommended readings -- Rcpp #1 658 | 659 | Dirk Eddelbuettel, *Seamless R and C++ Integration with Rcpp* 660 | 661 | \includegraphics[height=0.6\textheight]{img/seamless.jpg} 662 | 663 | * comprehensive introduction to Rcpp 664 | * with very few lines of C++ code, we have R's data structures readily at hand for further computations in C++ 665 | 666 | # Recommended readings -- Rcpp #2 667 | 668 | * http://www.rcpp.org/ 669 | * https://cran.r-project.org/web/packages/Rcpp/index.html 670 | * https://teuder.github.io/rcpp4everyone_en/ 671 | * http://adv-r.had.co.nz/Rcpp.html 672 | * http://gallery.rcpp.org/ 673 | * https://support.rstudio.com/hc/en-us/articles/200486088-Using-Rcpp-with-RStudio 674 | 675 | # Recommended readings -- Rcpp #3 676 | 684 | 685 | * http://dirk.eddelbuettel.com/code/rcpp.html 686 | * http://dirk.eddelbuettel.com/code/rcpp/Rcpp-quickref.pdf 687 | * http://dirk.eddelbuettel.com/papers/rcpp_ku_nov2013-part1.pdf 688 | * http://dirk.eddelbuettel.com/papers/rcpp_ku_nov2013-part2.pdf 689 | * http://dirk.eddelbuettel.com/papers/rcpp_ku_nov2013-part3.pdf 690 | * http://dirk.eddelbuettel.com/papers/uofc_cs_apr2013.pdf 691 | * http://dirk.eddelbuettel.com/papers/rcpp_sydney-rug_jul2013.pdf 692 | * http://dirk.eddelbuettel.com/papers/rcpp_workshop_introduction_user2012.pdf 693 | * http://dirk.eddelbuettel.com/papers/rcpp_workshop_advanced_user2012.pdf 694 | 695 | # Recommended readings -- Rcpp #4 696 | 697 | * http://cran.r-project.org/web/packages/Rcpp/vignettes/Rcpp-quickref.pdf 698 | * http://cran.rstudio.com/web/packages/Rcpp/vignettes/Rcpp-attributes.pdf 699 | * Integrating R with C++: Rcpp, RInside, and RProtobuf: http://www.youtube.com/watch?v=UZkaZhsOfT4 700 | * http://blog.rstudio.org/2012/11/29/rstudio-and-rcpp/ 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | --------------------------------------------------------------------------------