diff --git a/Makefile b/Makefile index 7b2e65d..a35ceb3 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,9 @@ CC=gcc CFLAGS=-Wall -fPIC -O3 -ansi -pedantic-errors -LDFLAGS=-lgsl -lcblas -lm +LDFLAGS=-lcblas -lm PREFIX= /usr/local -opt-pricer : src/opt-pricer.c gbm.o black_scholes.o +opt-pricer : src/opt-pricer.c gbm.o black_scholes.o utils.o @$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@ gbm.o : src/gbm_mc.c @@ -12,6 +12,9 @@ gbm.o : src/gbm_mc.c black_scholes.o : src/black_scholes.c @$(CC) $(CFLAGS) -c $^ $(LDFLAGS) -o $@ +utils.o : src/utils.c + @$(CC) $(CFLAGS) -c $^ $(LDFLAGS) -o $@ + .PHONY: install install : opt-pricer @mkdir -p $(DESTDIR)$(PREFIX)/bin @@ -24,4 +27,4 @@ uninstall : .PHONY: clean clean : - @rm -f gbm.o black_scholes.o + @rm -f gbm.o black_scholes.o utils.o diff --git a/src/black_scholes.c b/src/black_scholes.c index 32b1c3d..87d8786 100644 --- a/src/black_scholes.c +++ b/src/black_scholes.c @@ -1,15 +1,11 @@ #define _XOPEN_SOURCE #include "black_scholes.h" +#include "utils.h" #include #include #include -double normalcdf(double value) -{ - return 0.5 * erfc(-value * M_SQRT1_2); -} - double bsm(double spot, double rfr, double vol, double strike, struct tm expiry, struct tm value, int type) { diff --git a/src/gbm_mc.c b/src/gbm_mc.c index 1bbfe37..cdcadd4 100644 --- a/src/gbm_mc.c +++ b/src/gbm_mc.c @@ -1,12 +1,10 @@ #define _XOPEN_SOURCE #define max(X,Y) (((X) > (Y)) ? (X) : (Y)) -#include -#include -#include +#include "gbm_mc.h" +#include "utils.h" #include #include -#include "gbm_mc.h" double gbm_simulation(double spot, double rfr, double vol, double tte, double rand) { @@ -21,32 +19,23 @@ double gbm_simulation(double spot, double rfr, double vol, double tte, double ra double gbm(double spot, double rfr, double vol, double strike, struct tm expiry, struct tm value, int type, int sims) { - const gsl_rng_type *T; double tte, expiry_date, value_date, level, price, rand; - double *results; - gsl_rng *r; + double results = 0; int i; - results = (double *)malloc(sizeof(double) * sims); + if (sims < 1) sims = 1; expiry_date = mktime(&expiry); value_date = mktime(&value); tte = difftime(expiry_date, value_date) / (60 * 60 * 24 * 365); - /* GSL RNG setup */ - gsl_rng_env_setup(); - T = gsl_rng_default; - r = gsl_rng_alloc(T); - for (i=0; i + double gbm_simulation(double spot, double rfr, double vol, double tte, double rand); double gbm(double spot, double rfr, double vol, double strike, struct tm expiry, struct tm value, int type, int sims); diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 0000000..faa709b --- /dev/null +++ b/src/utils.c @@ -0,0 +1,52 @@ +#define M_SQRT1_2 0.707106781186547524401 + +#include +#include + +double normalcdf(double z) +{ + /* https://www.johndcook.com/blog/cpp_phi/ */ + double a1, a2, a3, a4, a5, p, t, y; + int sign; + + a1 = 0.254829592; + a2 = -0.284496736; + a3 = 1.421413741; + a4 = -1.453152027; + a5 = 1.061405429; + p = 0.3275911; + + sign = 1; + if (z < 0) + sign = -1; + z = fabs(z) / pow(2, 0.5); + t = 1 / (1 + p * z); + y = 1 - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * exp(-z * z); + return 0.5 * (1 + sign * y); +} + +double gaussrand() +{ + static double V1, V2, S; + static int phase = 0; + double X; + + if (phase == 0) { + do { + double U1 = (double)rand() / RAND_MAX; + double U2 = (double)rand() / RAND_MAX; + + V1 = 2 * U1 - 1; + V2 = 2 * U2 - 1; + S = V1 * V1 + V2 * V2; + } while (S >= 1 || S == 0); + + X = V1 * sqrt(-2 * log(S) / S); + } else { + X = V2 * sqrt(-2 * log(S) / S); + } + + phase = 1 - phase; + + return X; +} diff --git a/src/utils.h b/src/utils.h new file mode 100644 index 0000000..dd48984 --- /dev/null +++ b/src/utils.h @@ -0,0 +1,8 @@ +#ifndef UTILS_H +#define UTILS_H + +double normalcdf(double value); + +double gaussrand(); + +#endif