269 lines
6.6 KiB
C++
269 lines
6.6 KiB
C++
#pragma once
|
|
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <string>
|
|
#include <cassert>
|
|
#include <iostream>
|
|
#include <chrono>
|
|
#include <fstream>
|
|
#include <memory>
|
|
#include <random>
|
|
|
|
//Precision to use for calculations
|
|
|
|
typedef struct OptionData_ {
|
|
float s; // spot price
|
|
float strike; // strike price
|
|
float r; // risk-free interest rate
|
|
float divq; // dividend rate
|
|
float v; // volatility
|
|
float t; // time to maturity or option expiration in years
|
|
// (1yr = 1.0, 6mos = 0.5, 3mos = 0.25, ..., etc)
|
|
char OptionType; // Option type. "P"=PUT, "C"=CALL
|
|
float divs; // dividend vals (not used in this test)
|
|
float DGrefval; // DerivaGem Reference Value
|
|
} OptionData;
|
|
|
|
extern OptionData *optdata;
|
|
extern float *prices;
|
|
extern int numOptions;
|
|
extern int NUM_RUNS;
|
|
extern int* otype;
|
|
extern float* sptprice;
|
|
extern float* strike;
|
|
extern float* rate;
|
|
extern float* volatility;
|
|
extern float* otime;
|
|
extern int numError;
|
|
extern float* BUFFER;
|
|
extern int* BUFFER2;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Cumulative Normal Distribution Function
|
|
// See Hull, Section 11.8, P.243-244
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
#define inv_sqrt_2xPI 0.39894228040143270286
|
|
|
|
inline float CNDF( float InputX ) {
|
|
int sign;
|
|
|
|
float OutputX;
|
|
float xInput;
|
|
float xNPrimeofX;
|
|
float expValues;
|
|
float xK2;
|
|
float xK2_2, xK2_3;
|
|
float xK2_4, xK2_5;
|
|
float xLocal, xLocal_1;
|
|
float xLocal_2, xLocal_3;
|
|
|
|
// Check for negative value of InputX
|
|
if (InputX < 0.0) {
|
|
InputX = -InputX;
|
|
sign = 1;
|
|
}
|
|
else {
|
|
sign = 0;
|
|
}
|
|
|
|
xInput = InputX;
|
|
|
|
// Compute NPrimeX term common to both four & six decimal accuracy calcs
|
|
expValues = std::exp(-0.5f * InputX * InputX);
|
|
xNPrimeofX = expValues;
|
|
xNPrimeofX = xNPrimeofX * inv_sqrt_2xPI;
|
|
|
|
xK2 = 0.2316419 * xInput;
|
|
xK2 = 1.0 + xK2;
|
|
xK2 = 1.0 / xK2;
|
|
xK2_2 = xK2 * xK2;
|
|
xK2_3 = xK2_2 * xK2;
|
|
xK2_4 = xK2_3 * xK2;
|
|
xK2_5 = xK2_4 * xK2;
|
|
|
|
xLocal_1 = xK2 * 0.319381530;
|
|
xLocal_2 = xK2_2 * (-0.356563782);
|
|
xLocal_3 = xK2_3 * 1.781477937;
|
|
xLocal_2 = xLocal_2 + xLocal_3;
|
|
xLocal_3 = xK2_4 * (-1.821255978);
|
|
xLocal_2 = xLocal_2 + xLocal_3;
|
|
xLocal_3 = xK2_5 * 1.330274429;
|
|
xLocal_2 = xLocal_2 + xLocal_3;
|
|
|
|
xLocal_1 = xLocal_2 + xLocal_1;
|
|
xLocal = xLocal_1 * xNPrimeofX;
|
|
xLocal = 1.0 - xLocal;
|
|
|
|
OutputX = xLocal;
|
|
|
|
if (sign) {
|
|
OutputX = 1.0 - OutputX;
|
|
}
|
|
|
|
return OutputX;
|
|
}
|
|
|
|
|
|
|
|
inline float BlkSchlsEqEuroNoDiv(
|
|
float sptprice, float strike, float rate,
|
|
float volatility, float time, int otype, float) {
|
|
|
|
float OptionPrice;
|
|
|
|
// local private working variables for the calculation
|
|
//float xStockPrice; // These two variables are not used
|
|
//float xStrikePrice;
|
|
float xRiskFreeRate;
|
|
float xVolatility;
|
|
float xTime;
|
|
float xSqrtTime;
|
|
|
|
float logValues;
|
|
float xLogTerm;
|
|
float xD1;
|
|
float xD2;
|
|
float xPowerTerm;
|
|
float xDen;
|
|
float d1;
|
|
float d2;
|
|
float FutureValueX;
|
|
float NofXd1;
|
|
float NofXd2;
|
|
float NegNofXd1;
|
|
float NegNofXd2;
|
|
|
|
//xStockPrice = sptprice;
|
|
//xStrikePrice = strike;
|
|
xRiskFreeRate = rate;
|
|
xVolatility = volatility;
|
|
|
|
xTime = time;
|
|
xSqrtTime = std::sqrt(xTime);
|
|
|
|
logValues = std::log(sptprice/strike);
|
|
|
|
xLogTerm = logValues;
|
|
|
|
xPowerTerm = xVolatility * xVolatility;
|
|
xPowerTerm = xPowerTerm * 0.5;
|
|
|
|
xD1 = xRiskFreeRate + xPowerTerm;
|
|
xD1 = xD1 * xTime;
|
|
xD1 = xD1 + xLogTerm;
|
|
|
|
xDen = xVolatility * xSqrtTime;
|
|
xD1 = xD1 / xDen;
|
|
xD2 = xD1 - xDen;
|
|
|
|
d1 = xD1;
|
|
d2 = xD2;
|
|
|
|
NofXd1 = CNDF( d1 );
|
|
NofXd2 = CNDF( d2 );
|
|
|
|
FutureValueX = strike * ( std::exp( -(rate)*(time) ) );
|
|
if (otype == 0) {
|
|
OptionPrice = (sptprice * NofXd1) - (FutureValueX * NofXd2);
|
|
}
|
|
else {
|
|
NegNofXd1 = (1.0 - NofXd1);
|
|
NegNofXd2 = (1.0 - NofXd2);
|
|
OptionPrice = (FutureValueX * NegNofXd2) - (sptprice * NegNofXd1);
|
|
}
|
|
|
|
return OptionPrice;
|
|
}
|
|
|
|
|
|
inline void check_error(unsigned i, float price) {
|
|
float priceDelta = optdata[i].DGrefval - price;
|
|
if(std::fabs(priceDelta) >= 1e-4 ){
|
|
printf("Error on %d. Computed=%.5f, Ref=%.5f, Delta=%.5f\n",
|
|
i, price, optdata[i].DGrefval, priceDelta);
|
|
numError ++;
|
|
}
|
|
}
|
|
|
|
|
|
// Sequential version
|
|
inline void bs_seq(float *seq_prices) {
|
|
|
|
int i, j;
|
|
float price;
|
|
|
|
for (j=0; j<NUM_RUNS; j++) {
|
|
for (i=0; i<numOptions; i++) {
|
|
/* Calling main function to calculate option value based on
|
|
* Black & Scholes's equation.
|
|
*/
|
|
price = BlkSchlsEqEuroNoDiv( sptprice[i], strike[i],
|
|
rate[i], volatility[i], otime[i],
|
|
otype[i], 0);
|
|
seq_prices[i] = price;
|
|
|
|
#ifdef ERR_CHK
|
|
check_error(i, seq_prices[i]);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void destroy_options() {
|
|
free(optdata);
|
|
free(prices);
|
|
free(BUFFER);
|
|
free(BUFFER2);
|
|
}
|
|
|
|
// Read input option data from file
|
|
inline void generate_options(size_t num_options) {
|
|
|
|
numOptions = num_options == 0 ? 1 : num_options;
|
|
NUM_RUNS = numOptions;
|
|
|
|
// Allocate spaces for the option data
|
|
optdata = static_cast<OptionData*>(malloc(numOptions*sizeof(OptionData)));
|
|
prices = static_cast<float*>(malloc(numOptions*sizeof(float)));
|
|
|
|
for(int i=0; i<numOptions; ++i) {
|
|
optdata[i].s = ::rand() % 200;
|
|
optdata[i].strike = ::rand() % 200;
|
|
optdata[i].r = 0.1f;
|
|
optdata[i].divq = 0.0f;
|
|
optdata[i].v = ::rand() % 100 / 100.0f;
|
|
optdata[i].t = ::rand() % 100 / 100.0f;
|
|
optdata[i].OptionType = ::rand() % 2 ? 'P' : 'C';
|
|
optdata[i].divs = 0.0f;
|
|
optdata[i].DGrefval = ::rand() % 20;
|
|
}
|
|
|
|
const int PAD {256};
|
|
const int LINESIZE {64};
|
|
|
|
BUFFER = static_cast<float *>(malloc(5 * numOptions * sizeof(float) + PAD));
|
|
sptprice = reinterpret_cast<float *>(((unsigned long long)BUFFER + PAD) & ~(LINESIZE - 1));
|
|
strike = sptprice + numOptions;
|
|
rate = strike + numOptions;
|
|
volatility = rate + numOptions;
|
|
otime = volatility + numOptions;
|
|
|
|
BUFFER2 = static_cast<int *>(malloc(numOptions * sizeof(float) + PAD));
|
|
//otype = (int *) (((unsigned long long)BUFFER2 + PAD) & ~(LINESIZE - 1));
|
|
otype = reinterpret_cast<int *>(((unsigned long long)BUFFER2 + PAD) & ~(LINESIZE - 1));
|
|
|
|
for(auto i=0; i<numOptions; i++) {
|
|
otype[i] = (optdata[i].OptionType == 'P') ? 1 : 0;
|
|
sptprice[i] = optdata[i].s;
|
|
strike[i] = optdata[i].strike;
|
|
rate[i] = optdata[i].r;
|
|
volatility[i] = optdata[i].v;
|
|
otime[i] = optdata[i].t;
|
|
}
|
|
}
|
|
|
|
std::chrono::microseconds measure_time_taskflow(unsigned);
|
|
std::chrono::microseconds measure_time_tbb(unsigned);
|
|
std::chrono::microseconds measure_time_omp(unsigned);
|
|
|