From fdaa472888e88db80d3688f5bb2b9a311bbb0b3c Mon Sep 17 00:00:00 2001 From: Kevin Keogh Date: Sun, 13 Aug 2017 23:16:01 -0400 Subject: [PATCH] Cleanup, updated README --- Makefile | 6 ++---- README | 28 ++++++++++++++++++---------- build/opt-pricer | Bin 20056 -> 0 bytes src/gbm_mc.c | 37 ++++++++----------------------------- 4 files changed, 28 insertions(+), 43 deletions(-) delete mode 100755 build/opt-pricer diff --git a/Makefile b/Makefile index 3b220df..08ecee7 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,7 @@ CFLAGS=-Wall -g -fPIC -O3 -pthread CPPFLAGS=-pedantic -std=c++11 LDFLAGS=-lm -lstdc++ PREFIX=/usr/local +THIS_DIR=$(dir $(abspath $(lastword $(MAKEFILE_LIST)))) WINDOWS_CC=x86_64-w64-mingw32-gcc WINDOWS_CFLAGS= -Wall -O3 -ansi -pedantic-errors -pthread @@ -55,8 +56,7 @@ windows: build/opt-pricer.exe .PHONY: install install : build/opt-pricer @mkdir -p $(DESTDIR)$(PREFIX)/bin - @cp $< $(DESTDIR)$(PREFIX)/bin/opt-pricer - @rm -f $< + @ln -sf $(THIS_DIR)$< $(DESTDIR)$(PREFIX)/bin/opt-pricer .PHONY: uninstall uninstall : @@ -65,5 +65,3 @@ uninstall : .PHONY: clean clean : @rm -rf build - @mkdir build - @mkdir build/depends diff --git a/README b/README index 36ac377..bbdfe56 100644 --- a/README +++ b/README @@ -2,7 +2,7 @@ Demonstration of a Black-Scholes Model in C Note that there are two models, a pure Monte Carlo implementation and the closed form Black-Scholes equation. Note that the code runs -multi-threaded. +multi-threaded and the random numbers are a sobol sequence. To install: $ git clone https://github.com/kevindkeogh/opt-pricer.git @@ -29,12 +29,12 @@ To install: |Risk-free: | 3.00% | 3.00% | |Implied Vol:| 20.00% | 20.00% | --------------------------------------------- - |Fair value: | 11.8866 | 11.8941 | - |Delta: | 0.6202 | 0.6206 | - |Gamma: | 0.0253 | 0.0134 | - |Vega: | 0.4660 | 0.4668 | - |Theta: | -4.6138 | -4.6235 | - |Rho: | 0.7513 | 0.7699 | + |Fair value: | 11.8866 | 11.8866 | + |Delta: | 0.6202 | 0.6202 | + |Gamma: | 0.0253 | 0.0157 | + |Vega: | 0.4660 | 0.4660 | + |Theta: | -4.6138 | -4.6154 | + |Rho: | 0.7513 | 0.7630 | |Simulations:| | 100,000,000 | --------------------------------------------- @@ -42,7 +42,15 @@ To install: Recommended number of simulations is 100,000,000 for Gamma convergence, the other Greeks converge by 1,000,000. +LICENSE: + My code, which comprises most of the routine functionality, is MIT. + There are two functions, + i8_sobol_generate - generate sobol sequence + r8_normal_01_cdf_inverse - calculate inverse normal cdf + which are LGPL. The Makefile compiles them as a separate shared object + and dynamically links them. The files are included (with minor + adjustments to make it compile) in src. + TODO: - 1. Find a C implementation for Sobol sequence so that Gamma convergence - is faster - 2. Tests... + 1. Tests... + 2. Update windows cross-compilation, currently broken diff --git a/build/opt-pricer b/build/opt-pricer deleted file mode 100755 index afda6e7cc95c08db53a1dca59070988b03a40f5b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20056 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 BHMsx) diff --git a/src/gbm_mc.c b/src/gbm_mc.c index 93d82b3..5b87530 100644 --- a/src/gbm_mc.c +++ b/src/gbm_mc.c @@ -38,7 +38,6 @@ void *run_simulations(void *opt_ptr) double gamma_shift = 0, base_gamma = 0, upper_gamma = 0, lower_gamma = 0; double price, delta, gamma, vega, theta, rho; double base = 0; - double max_rand = 0; struct Option *opt = (struct Option *) opt_ptr; @@ -52,7 +51,7 @@ void *run_simulations(void *opt_ptr) for (i = 0; i < opt->sims; i++) { rand = opt->randoms[i]; - max_rand = rand > max_rand ? rand : max_rand; + /* Base scenario */ level = gbm_simulation(opt->spot, opt->rfr, opt->vol, tte, rand); base += max((level - opt->strike) * opt->type, 0); @@ -83,13 +82,13 @@ void *run_simulations(void *opt_ptr) rho_shift += max((level - opt->strike) * opt->type, 0); } - df = 1 / pow((1 + opt->rfr), tte); + df = exp(-opt->rfr * tte); price = base / opt->sims * df; delta = delta_shift / opt->sims * df; gamma = gamma_shift / opt->sims * df; vega = vega_shift / opt->sims * df; - theta = theta_shift / opt->sims * 1 / pow((1 + opt->rfr), tte - 1./365.); - rho = rho_shift / opt->sims * 1 / pow((1 + opt->rfr + 0.01), tte); + theta = theta_shift / opt->sims * exp(-opt->rfr * theta_tte); + rho = rho_shift / opt->sims * exp(-1 * (opt->rfr + 0.01) * tte); opt->fv = price; opt->delta = (delta - price) / 0.0001; @@ -125,39 +124,20 @@ void gbm(struct Option *opt) } } - /* Fill 2D array with normal randoms - * The purpose is to give the Option structs the random - * numbers they will need for simulations, as opposed to - * having the individual threads do so (rand() is not thread-safe) - j = 0; - i = 0; - for(i = 0; i < NUM_THREADS;){ - randoms[i][j] = gaussrand(); - if (j >= (opt->sims / NUM_THREADS)) { - j = 0; - i += 1; - } - j++; - } - */ - /* Set the number of simulations on a per-thread basis - */ + /* Set the number of simulations on a per-thread basis */ opt->sims = opt->sims / NUM_THREADS; + threads = malloc(sizeof(pthread_t) * NUM_THREADS); for(i=0; iexpiry_date; options[i].value_date = opt->value_date; options[i].randoms = randoms[i]; - } - threads = malloc(sizeof(pthread_t) * NUM_THREADS); - - for(i=0; isims += result->sims; } - free(threads); for(i=0; i