From 186e8e40e9de7e20a4fe57a14854facf13b606aa Mon Sep 17 00:00:00 2001 From: Kevin Keogh Date: Mon, 31 Jul 2017 00:05:43 -0400 Subject: [PATCH] Style cleanup, add comments --- build/opt-pricer | Bin 18192 -> 0 bytes src/gbm_mc.c | 50 ++++++++++++++++++-------- src/opt-pricer.c | 90 +++++++++++++++++++++++------------------------ src/utils.c | 4 +-- src/utils.h | 4 +-- 5 files changed, 82 insertions(+), 66 deletions(-) delete mode 100755 build/opt-pricer diff --git a/build/opt-pricer b/build/opt-pricer deleted file mode 100755 index a2f084fd4be8383b21babf532f25066079551294..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18192 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 (Y)) ? (X) : (Y)) +#define max(X, Y) (((X) > (Y)) ? (X) : (Y)) #include "gbm_mc.h" #include "utils.h" @@ -28,6 +28,8 @@ double gbm_simulation(double spot, double rfr, double vol, double tte, double ra void *run_simulations(void *opt_ptr) { + /* A single thread simulation, calculates the PV and Greeks */ + int i; double tte, theta_tte, expiry_date, value_date, level, rand, df; double delta_shift = 0, vega_shift = 0, theta_shift = 0, rho_shift = 0; @@ -36,16 +38,17 @@ void *run_simulations(void *opt_ptr) double base = 0; double max_rand = 0; - struct Option *opt = (struct Option*) opt_ptr; + struct Option *opt = (struct Option *) opt_ptr; - if (opt->sims < 1) opt->sims = 1; + if (opt->sims < 1) + opt->sims = 1; expiry_date = mktime(opt->expiry_date); value_date = mktime(opt->value_date); tte = difftime(expiry_date, value_date) / (60 * 60 * 24 * 365); theta_tte = tte - 1. / 365; - for (i=0; isims; i++) { + for (i = 0; i < opt->sims; i++) { rand = opt->randoms[i]; max_rand = rand > max_rand ? rand : max_rand; /* Base scenario */ @@ -103,30 +106,41 @@ void gbm(struct Option *opt) pthread_t *threads; struct Option *options; double **randoms; + options = malloc(sizeof(struct Option) * NUM_THREADS); - randoms = malloc(sizeof(double*) * NUM_THREADS); + randoms = malloc(sizeof(double *) * NUM_THREADS); + + /* Create 2D array */ for(i=0; isims / NUM_THREADS); } - /* generate array of normal randoms */ - for(i=0;;) { - if (j == (opt->sims / NUM_THREADS)) { + /* 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; } - - if (i == NUM_THREADS) { - break; - } - - randoms[i][j] = gaussrand(); j++; } + /* Set the number of simulations on a per-thread basis + */ opt->sims = opt->sims / NUM_THREADS; + for(i=0; iexpiry_date; options[i].value_date = opt->value_date; options[i].randoms = randoms[i]; @@ -145,8 +159,9 @@ void gbm(struct Option *opt) for(i=0; ifv += result->fv / NUM_THREADS; opt->delta += result->delta / NUM_THREADS; opt->gamma += result->gamma / NUM_THREADS; @@ -156,4 +171,9 @@ void gbm(struct Option *opt) opt->sims += result->sims; } + free(threads); + for(i=0; i #include +#include #include #include #include @@ -42,7 +43,7 @@ static struct helptext options[] = { "Put or call flag"}, {"-h, --help", "This help text"}, - { NULL , NULL } + { NULL, NULL } }; @@ -71,7 +72,7 @@ int print_help(void) } -char* read_type(struct Option opt) +char *read_type(struct Option opt) { return (opt.type == 1) ? "Call" : "Put"; } @@ -85,9 +86,6 @@ int main(int argc, char *argv[]) struct tm value, expiry; struct Option bs_opt, mc_opt; - extern char *optarg; - extern int getopt_long(); - memset(&expiry, 0, sizeof(expiry)); memset(&value, 0, sizeof(value)); @@ -95,46 +93,46 @@ int main(int argc, char *argv[]) while ((opt = getopt_long(argc, argv, "s:k:r:v:d:e:N:cph", long_options, &option_index)) != -1) { switch (opt) { - case 's': - if (sscanf(optarg, "%lf", &spot) == EOF) { - return 1; - }; - break; - case 'k': /* strike */ - if (sscanf(optarg, "%lf", &strike) == EOF) { - return 1; - }; - break; - case 'r': /* risk-free rate */ - if (sscanf(optarg, "%lf.", &rfr) == EOF) { - return 1; - }; - break; - case 'v': /* implied volatility */ - if (sscanf(optarg, "%lf", &vol) == EOF) { - return 1; - }; - break; - case 'e': /* expiry date, must be YYYY-MM-DD */ - strptime(optarg, "%Y-%m-%d", &expiry); - break; - case 'd': /* valuation date, must be YYYY-MM-DD */ - strptime(optarg, "%Y-%m-%d", &value); - break; - case 'N': /* number of simulations */ - if (sscanf(optarg, "%lf", &sims) == EOF) { - return 1; - }; - break; - case 'c': /* set as call */ - type = 1; - break; - case 'p': /* set as put */ - type = -1; - break; - case 'h': /* print help*/ - print_help(); - return 0; + case 's': + if (sscanf(optarg, "%lf", &spot) == EOF) { + return 1; + }; + break; + case 'k': /* strike */ + if (sscanf(optarg, "%lf", &strike) == EOF) { + return 1; + }; + break; + case 'r': /* risk-free rate */ + if (sscanf(optarg, "%lf.", &rfr) == EOF) { + return 1; + }; + break; + case 'v': /* implied volatility */ + if (sscanf(optarg, "%lf", &vol) == EOF) { + return 1; + }; + break; + case 'e': /* expiry date, must be YYYY-MM-DD */ + strptime(optarg, "%Y-%m-%d", &expiry); + break; + case 'd': /* valuation date, must be YYYY-MM-DD */ + strptime(optarg, "%Y-%m-%d", &value); + break; + case 'N': /* number of simulations */ + if (sscanf(optarg, "%lf", &sims) == EOF) { + return 1; + }; + break; + case 'c': /* set as call */ + type = 1; + break; + case 'p': /* set as put */ + type = -1; + break; + case 'h': /* print help */ + print_help(); + return 0; } } if (spot == 0 || strike == 0 || rfr == 0 || vol == 0) { @@ -156,7 +154,7 @@ int main(int argc, char *argv[]) bsm(&bs_opt); gbm(&mc_opt); - setlocale(LC_ALL,""); + setlocale(LC_ALL, ""); printf( "\nValuation date: %s\n\n" " | BS Analytic | BS Monte Carlo |\n" diff --git a/src/utils.c b/src/utils.c index 6c33e79..e226d43 100644 --- a/src/utils.c +++ b/src/utils.c @@ -35,11 +35,11 @@ double normalpdf(double z) } -double gaussrand() +double gaussrand(void) { /* Marsaglia and Bray, ``A Convenient Method for Generating Normal Variables'' */ static double V1, V2, S; - static int phase = 0; + static int phase; double X; if (phase == 0) { diff --git a/src/utils.h b/src/utils.h index 1297eb9..74e294d 100644 --- a/src/utils.h +++ b/src/utils.h @@ -1,13 +1,11 @@ #ifndef UTILS_H #define UTILS_H -void srand(unsigned int seed); - double normalcdf(double z); double normalpdf(double z); -double gaussrand(); +double gaussrand(void); struct Option { /* option details */