#include "Call.h" #include #include #include #include #include "normal.h" #include "util.h" /** * Simple Call class (Black Scholes, Binomial and Monte Carlo pricing methods). See * http://finance-old.bi.no/~bernt/gcc_prog/recipes/recipes/node7.html * http://www.scieng.ed.ac.uk/Students/Awards/Optionpricing.pdf * for some good background material. * * @version $Id$ */ //Call::Call() //{ //} Call::~Call() { } Call::Call(double spot, double exercise, double r, double volatility, double timeToExpiry) { Call::spot = spot; Call::exercise = exercise; Call::r = r; Call::volatility = volatility; Call::timeToExpiry = timeToExpiry; timeSqrt = sqrt(timeToExpiry); d1 = getD1(); d2 = getD2(); delta = calcDelta(); gamma = calcGamma(d1, spot, volatility, timeSqrt);; theta = calcTheta(); rho = calcRho(); vega = calcVega(d1, spot, timeSqrt); } double Call::priceEuropeanBlackScholes() { return priceEuropeanBlackScholes(spot, exercise, r, volatility, timeToExpiry); } double Call::priceEuropeanBlackScholes(double spot, double exercise, double r, double volatility, double t) { double s = spot * nc(d1); double x = exercise * exp(-r * t) * nc(d2); return s - x; } double Call::priceEuropeanBinomial(int steps){ if (steps < 0) steps = 16; return priceEuropeanBinomial(spot, exercise, r, volatility, timeToExpiry, steps); } double Call::priceEuropeanBinomial(double spot, double exercise, double r, double volatility, double t, int steps) { double deltaT = t/steps; // risklessRate = exp(r(At)) double risklessRate = exp(r * deltaT); double discountRate = 1/risklessRate; // upward movement: u = exp(vol * sqrt((At))) double u = exp(volatility * sqrt(deltaT)); // downward movement: d = exp-(vol * sqrt((At))) double d = 1/u; double probabilityUp = (risklessRate-d)/(u-d); double probabilityDown = 1 - probabilityUp; vector stockPrices(steps + 1); // Set prices of underlying at maturity stockPrices[0] = spot * pow(d, steps); // uu is the distance between maturity values double uu = u*u; for (int i = 1; i <= steps; i++) { stockPrices[i] = uu * stockPrices[i - 1]; } vector callValues(steps + 1); // Set call payoffs at maturity for (int i = 0; i <= steps; i++) { callValues[i] = max(0.0, stockPrices[i] - exercise); } for (int step = steps - 1; step >= 0; --step) { for (int i = 0; i <= step; ++i) { double callValue = ((probabilityUp * callValues[i + 1]) + (probabilityDown * callValues[i])) * discountRate; callValues[i] = callValue; } } return callValues[0]; } double Call::priceEuropeanMonteCarlo(int numEstimates) { if (numEstimates <= 0) numEstimates = 100; return priceEuropeanMonteCarlo(spot, exercise, r, volatility, timeToExpiry, numEstimates); } double Call::priceEuropeanMonteCarlo(double spot, double exercise, double r, double volatility, double t, int numEstimates) { double callValue, price, callValueTotal = 0; for (int i = 0; i < numEstimates; i++) { callValue = getSimulatedValue(spot, exercise, r, volatility); callValueTotal += callValue; } price = exp(-r * timeToExpiry) * (callValueTotal/numEstimates); return price; } double Call::getSimulatedValue(double spot, double exercise, double r, double volatility) { util u = util(); double randomNormal = u.getRandomFromStandardNormal(0, 1); double rMean = (r - (0.5 * pow(volatility,2))) * timeToExpiry; double sd = volatility * timeSqrt; double exponentTerm = rMean + (sd * randomNormal); double simulatedStockValue = spot * exp(exponentTerm); double simulatedCallValue = max(simulatedStockValue - exercise, 0); //cout << simulatedCallValue << endl; return simulatedCallValue; } double Call::calcDelta(){ return nc(d1); } double Call::calcTheta() { double theta =- (spot * volatility * ndf(d1)) / (2*timeSqrt) - r * exercise * exp( -r*timeToExpiry) * nc(d2); return theta/365; } double Call::calcRho() { double rho = exercise * timeToExpiry * exp(-r * timeToExpiry) * nc(d2); return 0.01 * rho; }