Hi again everybody,
here's also a C++ class for pricing options premiums (Black-Scholes-Merton).
here's also a C++ class for pricing options premiums (Black-Scholes-Merton).
Code:
/*
BSM.cpp - Black-Scholes-Merton options pricing engine
2016-01-26-Tu: v0.99: init
Author: U.M. in Germany (user botpro at www.elitetrader.com)
Compile:
g++ -Wall -O2 -std=c++11 BSM.cpp -o BSM.exe
Run:
Linux/Unix: ./BSM.exe
Windows: BSM.exe
Tested on 64bit Linux only
Example runs on Linux:
./BSM.exe 100 100 30 42
Spot=100.00 Strike=100 Vola%=30.00 ExpDays=42.00(t=0.16667) AnnDriftPct%=0.00 AnnDividPct%=0.00 --> Call=4.88297 Put=4.88297
./BSM.exe 100 100 30 63
Spot=100.00 Strike=100 Vola%=30.00 ExpDays=63.00(t=0.25000) AnnDriftPct%=0.00 AnnDividPct%=0.00 --> Call=5.97853 Put=5.97853
./BSM.exe 100 100 30 252
Spot=100.00 Strike=100 Vola%=30.00 ExpDays=252.00(t=1.00000) AnnDriftPct%=0.00 AnnDividPct%=0.00 --> Call=11.92354 Put=11.92354
./BSM.exe 100 100 30 504
Spot=100.00 Strike=100 Vola%=30.00 ExpDays=504.00(t=2.00000) AnnDriftPct%=0.00 AnnDividPct%=0.00 --> Call=16.79960 Put=16.79960
Misc:
- each invocation of the calc() function calculates Call.Value and Put.Value
- uses Year=252 trading days, this can be changed via constructor parameter
- extracted for standalone use from my BlackScholes class named TCBS
*/
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
using namespace std;
#define ZEROADJ 1e-18
double normal_cdf(const double value)
{
return 0.5 * erfc(-value * M_SQRT1_2);
}
class BSM
{ // Black-Scholes-Merton options pricing engine
public:
double S, K, s, t, r, q, dbDaysInYear;
double u, st, rt, qt, ut;
double z, z0;
double z1, z2; // ie. d1, d2 in orig BS
double p1, p2;
struct TS
{
double Value; // the calculated premium will be stored here
// The Greeks (omitted here):
// double Delta, Vega, Theta, Rho, Gamma, Vanna, Charm, Speed, Zomma, Color, DVegaDTime, Vomma,
// DualDelta, DualGamma, DualTheta, Ultima, Lambda, ForwardDelta, DriftlessDelta, Cross;
TS()
{
Value = 0.0;
//...
}
};
TS Call, Put;
BSM()
{
S = K = s = t = r = q = dbDaysInYear = u = st = rt = qt = ut = 0;
z = z0 = z1 = z2 = p1 = p2 = 0;
}
public:
void calc(const double AdbSpot_S, const double AdbStrike_K, const double AdbAnnVolaPct, const double AdbExpireDays,
const double AdbAnnDriftPct = 0.0, const double AdbAnnDividPct = 0.0, const double AdbDaysInYear = 252.0)
{
dbDaysInYear = AdbDaysInYear;
S = AdbSpot_S;
K = AdbStrike_K;
s = AdbAnnVolaPct / 100.0;
t = AdbExpireDays / dbDaysInYear;
t = max(t, ZEROADJ); // safety
r = AdbAnnDriftPct / 100.0;
q = AdbAnnDividPct / 100.0;
st = s * sqrt(t);
rt = r * t;
qt = q * t;
u = r - q;
ut = u * t;
#if 0
// orig BS d1, d2:
z1 = (log(S / K) + (u + s * s / 2.0) * t) / st;
z2 = z1 - st;
#else
// my unpublished method using z1, z2 (makes Ito's lemma unnecessary): 100% identical to d1, d2 of orig BS:
z = st / 2.0;
z0 = (log(S / K) + ut) / st;
z1 = z0 + z;
z2 = z0 - z;
#endif
// calc the corrosponding probabilities p1, p2 belonging to z1, z2:
p1 = normal_cdf(z1);
p2 = normal_cdf(z2);
// calc Call premium:
const double exp_mqt = exp(-qt), exp_mrt = exp(-rt);
Call.Value = S * exp_mqt * p1 - K * exp_mrt * p2;
if (Call.Value < 0.0) Call.Value = ZEROADJ; // safety
// calc Put premium: via Put/Call Parity:
Put.Value = Call.Value + K * exp_mrt - S * exp_mqt;
if (Put.Value < 0.0) Put.Value = ZEROADJ; // safety
}
};
int main(int argc, char* argv[])
{
if (argc < 5) { printf("%s dbSpot dbStrike dbAnnVola%% dbExpDays\n", argv[0]); return 1; }
const double dbSpot = atof(argv[1]);
const double dbStrike = atof(argv[2]);
const double dbAnnVolaPct = atof(argv[3]);
const double dbExpDays = atof(argv[4]);
BSM B;
B.calc(dbSpot, dbStrike, dbAnnVolaPct, dbExpDays);
printf("Spot=%.2f Strike=%.0f Vola%%=%.2f ExpDays=%.2f(t=%.5f) AnnDriftPct%%=%.2f AnnDividPct%%=%.2f --> Call=%.5f Put=%.5f\n",
B.S, B.K, B.s * 100.0, B.t * B.dbDaysInYear, B.t, B.r * 100.0, B.q * 100.0, B.Call.Value, B.Put.Value);
return 0;
}