Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fdaa472888 | ||
|
|
095d6643d8 | ||
|
|
9092e65d6b | ||
|
|
560dccfb4f | ||
|
|
61be7cce04 |
15
Makefile
15
Makefile
@@ -3,6 +3,7 @@ CFLAGS=-Wall -g -fPIC -O3 -pthread
|
|||||||
CPPFLAGS=-pedantic -std=c++11
|
CPPFLAGS=-pedantic -std=c++11
|
||||||
LDFLAGS=-lm -lstdc++
|
LDFLAGS=-lm -lstdc++
|
||||||
PREFIX=/usr/local
|
PREFIX=/usr/local
|
||||||
|
THIS_DIR=$(dir $(abspath $(lastword $(MAKEFILE_LIST))))
|
||||||
|
|
||||||
WINDOWS_CC=x86_64-w64-mingw32-gcc
|
WINDOWS_CC=x86_64-w64-mingw32-gcc
|
||||||
WINDOWS_CFLAGS= -Wall -O3 -ansi -pedantic-errors -pthread
|
WINDOWS_CFLAGS= -Wall -O3 -ansi -pedantic-errors -pthread
|
||||||
@@ -10,8 +11,9 @@ WINDOWS_PLATFORM= windows
|
|||||||
|
|
||||||
.DEFAULT_GOAL := build/opt-pricer
|
.DEFAULT_GOAL := build/opt-pricer
|
||||||
|
|
||||||
build/opt-pricer : src/opt-pricer.c build/depends/linux/gbm.o build/depends/linux/black_scholes.o build/depends/linux/utils.o build/depends/linux/sobol.o build/depends/linux/asa241.o
|
build/opt-pricer : src/opt-pricer.c build/depends/linux/gbm.o build/depends/linux/black_scholes.o build/depends/linux/utils.o
|
||||||
@$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@
|
@$(MAKE) -s build/libs/libstats.so
|
||||||
|
@$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/libs' -Lbuild/libs -lstats
|
||||||
|
|
||||||
build/depends/%/gbm.o : src/gbm_mc.c | folders
|
build/depends/%/gbm.o : src/gbm_mc.c | folders
|
||||||
@$(CC) $(CFLAGS) -c $^ $(LDFLAGS) -o $@
|
@$(CC) $(CFLAGS) -c $^ $(LDFLAGS) -o $@
|
||||||
@@ -31,8 +33,12 @@ build/depends/%/asa241.o : src/asa241.c | folders
|
|||||||
build/depends/%/sobol.o : src/sobol.cpp | folders
|
build/depends/%/sobol.o : src/sobol.cpp | folders
|
||||||
@$(CC) $(CFLAGS) $(CPPFLAGS) -c $^ $(LDFLAGS) -o $@
|
@$(CC) $(CFLAGS) $(CPPFLAGS) -c $^ $(LDFLAGS) -o $@
|
||||||
|
|
||||||
|
build/libs/libstats.so : build/depends/linux/sobol.o build/depends/linux/asa241.o | folders
|
||||||
|
@$(CC) -fPIC -shared -o $@ $^ -lstdc++
|
||||||
|
|
||||||
folders:
|
folders:
|
||||||
@mkdir -p build
|
@mkdir -p build
|
||||||
|
@mkdir -p build/libs
|
||||||
@mkdir -p build/depends
|
@mkdir -p build/depends
|
||||||
@mkdir -p build/depends/linux
|
@mkdir -p build/depends/linux
|
||||||
@mkdir -p build/depends/windows
|
@mkdir -p build/depends/windows
|
||||||
@@ -50,8 +56,7 @@ windows: build/opt-pricer.exe
|
|||||||
.PHONY: install
|
.PHONY: install
|
||||||
install : build/opt-pricer
|
install : build/opt-pricer
|
||||||
@mkdir -p $(DESTDIR)$(PREFIX)/bin
|
@mkdir -p $(DESTDIR)$(PREFIX)/bin
|
||||||
@cp $< $(DESTDIR)$(PREFIX)/bin/opt-pricer
|
@ln -sf $(THIS_DIR)$< $(DESTDIR)$(PREFIX)/bin/opt-pricer
|
||||||
@rm -f $<
|
|
||||||
|
|
||||||
.PHONY: uninstall
|
.PHONY: uninstall
|
||||||
uninstall :
|
uninstall :
|
||||||
@@ -60,5 +65,3 @@ uninstall :
|
|||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean :
|
clean :
|
||||||
@rm -rf build
|
@rm -rf build
|
||||||
@mkdir build
|
|
||||||
@mkdir build/depends
|
|
||||||
|
|||||||
30
README
30
README
@@ -1,7 +1,8 @@
|
|||||||
Demonstration of a Black-Scholes Model in C
|
Demonstration of a Black-Scholes Model in C
|
||||||
|
|
||||||
Note that there are two models, a pure Monte Carlo implementation
|
Note that there are two models, a pure Monte Carlo implementation
|
||||||
and the closed form Black-Scholes equation.
|
and the closed form Black-Scholes equation. Note that the code runs
|
||||||
|
multi-threaded and the random numbers are a sobol sequence.
|
||||||
|
|
||||||
To install:
|
To install:
|
||||||
$ git clone https://github.com/kevindkeogh/opt-pricer.git
|
$ git clone https://github.com/kevindkeogh/opt-pricer.git
|
||||||
@@ -28,12 +29,12 @@ To install:
|
|||||||
|Risk-free: | 3.00% | 3.00% |
|
|Risk-free: | 3.00% | 3.00% |
|
||||||
|Implied Vol:| 20.00% | 20.00% |
|
|Implied Vol:| 20.00% | 20.00% |
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|Fair value: | 11.8866 | 11.8941 |
|
|Fair value: | 11.8866 | 11.8866 |
|
||||||
|Delta: | 0.6202 | 0.6206 |
|
|Delta: | 0.6202 | 0.6202 |
|
||||||
|Gamma: | 0.0253 | 0.0134 |
|
|Gamma: | 0.0253 | 0.0157 |
|
||||||
|Vega: | 0.4660 | 0.4668 |
|
|Vega: | 0.4660 | 0.4660 |
|
||||||
|Theta: | -4.6138 | -4.6235 |
|
|Theta: | -4.6138 | -4.6154 |
|
||||||
|Rho: | 0.7513 | 0.7699 |
|
|Rho: | 0.7513 | 0.7630 |
|
||||||
|Simulations:| | 100,000,000 |
|
|Simulations:| | 100,000,000 |
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
|
||||||
@@ -41,8 +42,15 @@ To install:
|
|||||||
Recommended number of simulations is 100,000,000 for Gamma convergence, the
|
Recommended number of simulations is 100,000,000 for Gamma convergence, the
|
||||||
other Greeks converge by 1,000,000.
|
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:
|
TODO:
|
||||||
1. Find a C implementation for Sobol sequence so that Gamma convergence
|
1. Tests...
|
||||||
is faster
|
2. Update windows cross-compilation, currently broken
|
||||||
2. Tests...
|
|
||||||
3. Parallelize code
|
|
||||||
|
|||||||
BIN
build/opt-pricer
BIN
build/opt-pricer
Binary file not shown.
37
src/gbm_mc.c
37
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 gamma_shift = 0, base_gamma = 0, upper_gamma = 0, lower_gamma = 0;
|
||||||
double price, delta, gamma, vega, theta, rho;
|
double price, delta, gamma, vega, theta, rho;
|
||||||
double base = 0;
|
double base = 0;
|
||||||
double max_rand = 0;
|
|
||||||
|
|
||||||
struct Option *opt = (struct Option *) opt_ptr;
|
struct Option *opt = (struct Option *) opt_ptr;
|
||||||
|
|
||||||
@@ -52,7 +51,7 @@ void *run_simulations(void *opt_ptr)
|
|||||||
|
|
||||||
for (i = 0; i < opt->sims; i++) {
|
for (i = 0; i < opt->sims; i++) {
|
||||||
rand = opt->randoms[i];
|
rand = opt->randoms[i];
|
||||||
max_rand = rand > max_rand ? rand : max_rand;
|
|
||||||
/* Base scenario */
|
/* Base scenario */
|
||||||
level = gbm_simulation(opt->spot, opt->rfr, opt->vol, tte, rand);
|
level = gbm_simulation(opt->spot, opt->rfr, opt->vol, tte, rand);
|
||||||
base += max((level - opt->strike) * opt->type, 0);
|
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);
|
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;
|
price = base / opt->sims * df;
|
||||||
delta = delta_shift / opt->sims * df;
|
delta = delta_shift / opt->sims * df;
|
||||||
gamma = gamma_shift / opt->sims * df;
|
gamma = gamma_shift / opt->sims * df;
|
||||||
vega = vega_shift / opt->sims * df;
|
vega = vega_shift / opt->sims * df;
|
||||||
theta = theta_shift / opt->sims * 1 / pow((1 + opt->rfr), tte - 1./365.);
|
theta = theta_shift / opt->sims * exp(-opt->rfr * theta_tte);
|
||||||
rho = rho_shift / opt->sims * 1 / pow((1 + opt->rfr + 0.01), tte);
|
rho = rho_shift / opt->sims * exp(-1 * (opt->rfr + 0.01) * tte);
|
||||||
|
|
||||||
opt->fv = price;
|
opt->fv = price;
|
||||||
opt->delta = (delta - price) / 0.0001;
|
opt->delta = (delta - price) / 0.0001;
|
||||||
@@ -125,39 +124,20 @@ void gbm(struct Option *opt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill 2D array with normal randoms
|
/* Set the number of simulations on a per-thread basis */
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
opt->sims = opt->sims / NUM_THREADS;
|
opt->sims = opt->sims / NUM_THREADS;
|
||||||
|
threads = malloc(sizeof(pthread_t) * NUM_THREADS);
|
||||||
|
|
||||||
for(i=0; i<NUM_THREADS; i++) {
|
for(i=0; i<NUM_THREADS; i++) {
|
||||||
options[i] = *opt;
|
options[i] = *opt;
|
||||||
/* These are pointers, so need to copy them directly,
|
/* The dates pointers, so need to copy them directly,
|
||||||
* otherwise we will probably have 2 threads trying to
|
* otherwise we will probably have 2 threads trying to
|
||||||
* access them at the same time
|
* access them at the same time
|
||||||
*/
|
*/
|
||||||
options[i].expiry_date = opt->expiry_date;
|
options[i].expiry_date = opt->expiry_date;
|
||||||
options[i].value_date = opt->value_date;
|
options[i].value_date = opt->value_date;
|
||||||
options[i].randoms = randoms[i];
|
options[i].randoms = randoms[i];
|
||||||
}
|
|
||||||
|
|
||||||
threads = malloc(sizeof(pthread_t) * NUM_THREADS);
|
|
||||||
|
|
||||||
for(i=0; i<NUM_THREADS; i++) {
|
|
||||||
if (pthread_create(&threads[i], NULL, run_simulations, &options[i])) {
|
if (pthread_create(&threads[i], NULL, run_simulations, &options[i])) {
|
||||||
printf("Error in thread creation\n");
|
printf("Error in thread creation\n");
|
||||||
}
|
}
|
||||||
@@ -180,9 +160,8 @@ void gbm(struct Option *opt)
|
|||||||
opt->sims += result->sims;
|
opt->sims += result->sims;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(threads);
|
|
||||||
for(i=0; i<NUM_THREADS; i++)
|
for(i=0; i<NUM_THREADS; i++)
|
||||||
free(randoms[i]);
|
free(randoms[i]);
|
||||||
free(randoms);
|
free(randoms);
|
||||||
|
free(threads);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user