This example computes profit and loss of a discrete interval hedging strategy and compares with the outcome with the results of Derman and Kamal's Goldman Sachs Equity Derivatives Research Note "When You Cannot Hedge Continuously: The Corrections to
Black-Scholes". It shows the use of the Monte Carlo framework.
#if !defined(BOOST_ALL_NO_LIB) && defined(BOOST_MSVC)
#endif
#include <iostream>
#include <iomanip>
class ReplicationError
{
public:
: maturity_(maturity),
payoff_(type, strike),
s0_(s0),
Real forward =
s0_*qDiscount/rDiscount;
std::cout <<
"Option value: " << black.
value() << std::endl;
vega_ = black.
vega(maturity_);
std::cout << std::endl;
std::cout << std::setw(8) << " " << " | "
<< std::setw(8) << " " << " | "
<< std::setw(8) << "P&L" << " | "
<< std::setw(8) << "P&L" << " | "
<< std::setw(12) << "Derman&Kamal" << " | "
<< std::setw(8) << "P&L" << " | "
<< std::setw(8) << "P&L" << std::endl;
std::cout << std::setw(8) << "samples" << " | "
<< std::setw(8) << "trades" << " | "
<< std::setw(8) << "mean" << " | "
<< std::setw(8) << "std.dev." << " | "
<< std::setw(12) << "formula" << " | "
<< std::setw(8) << "skewness" << " | "
<< std::setw(8) << "kurtosis" << std::endl;
std::cout << std::string(78, '-') << std::endl;
}
void compute(
Size nTimeSteps,
Size nSamples);
private:
};
class ReplicationPathPricer :
public PathPricer<Path> {
public:
"risk free rate (r) must be positive or zero");
QL_REQUIRE(maturity_ > 0.0,
"maturity must be positive");
"volatility (sigma) must be positive or zero");
}
Real operator()(
const Path& path)
const override;
private:
};
int main(int, char* []) {
try {
std::cout << std::endl;
Time maturity = 1.0/12.0;
Rate riskFreeRate = 0.05;
ReplicationError rp(Option::Call, maturity, strike, underlying,
volatility, riskFreeRate);
hedgesNum = 21;
rp.compute(hedgesNum, scenarios);
hedgesNum = 84;
rp.compute(hedgesNum, scenarios);
return 0;
} catch (std::exception& e) {
std::cerr << e.what() << std::endl;
return 1;
} catch (...) {
std::cerr << "unknown error" << std::endl;
return 1;
}
}
Real ReplicationPathPricer::operator()(
const Path& path)
const {
Rate stockDividendYield = 0.0;
Real money_account = 0.0;
Real forward = stock*qDiscount/rDiscount;
auto payoff = ext::make_shared<PlainVanillaPayoff>(type_,
strike_);
money_account += black.value();
Real delta = black.delta(stock);
Real stockAmount = delta;
money_account -= stockAmount*stock;
for (
Size step = 0; step <
n-1; step++){
money_account *= std::exp( r_*dt );
stock = path[step+1];
rDiscount = std::exp(-r_*(maturity_-
t));
qDiscount = std::exp(-stockDividendYield*(maturity_-
t));
forward = stock*qDiscount/rDiscount;
delta = black.delta(stock);
money_account -= (delta - stockAmount)*stock;
stockAmount = delta;
}
money_account *= std::exp( r_*dt );
money_account -= optionPayoff;
money_account += stockAmount*stock;
return money_account;
}
void ReplicationError::compute(
Size nTimeSteps,
Size nSamples)
{
QL_REQUIRE(nTimeSteps>0,
"the number of steps must be > 0");
Date today = Date::todaysDate();
ext::make_shared<FlatForward>(today, r_, dayCount));
ext::make_shared<FlatForward>(today, 0.0, dayCount));
ext::make_shared<BlackConstantVol>(today, calendar,
sigma_, dayCount));
auto diffusion = ext::make_shared<BlackScholesMertonProcess>(
stateVariable, dividendYield, riskFreeRate, volatility);
PseudoRandom::make_sequence_generator(nTimeSteps, 0);
bool brownianBridge = false;
auto myPathGenerator = ext::make_shared<generator_type>(
diffusion, maturity_, nTimeSteps,
rsg, brownianBridge);
auto myPathPricer = ext::make_shared<ReplicationPathPricer>(
MCSimulation(myPathGenerator,
myPathPricer,
statisticsAccumulator,
false);
MCSimulation.addSamples(nSamples);
Real PLMean = MCSimulation.sampleAccumulator().mean();
Real PLStDev = MCSimulation.sampleAccumulator().standardDeviation();
Real PLSkew = MCSimulation.sampleAccumulator().skewness();
Real PLKurt = MCSimulation.sampleAccumulator().kurtosis();
std::cout << std::fixed
<< std::setw(8) << nSamples << " | "
<< std::setw(8) << nTimeSteps << " | "
<< std::setw(8) << std::setprecision(3) << PLMean << " | "
<< std::setw(8) << std::setprecision(2) << PLStDev << " | "
<< std::setw(12) << std::setprecision(2) << theorStD << " | "
<< std::setw(8) << std::setprecision(2) << PLSkew << " | "
<< std::setw(8) << std::setprecision(2) << PLKurt << std::endl;
}
Actual/365 (Fixed) day counter.
Black-formula calculator class.
Black constant volatility, no time dependence, no strike dependence.
Actual/365 (Fixed) day count convention.
Black 1976 calculator class.
Real vega(Time maturity) const
empirical-distribution risk measures
Shared handle to an observable.
Inverse cumulative random sequence generator.
General-purpose Monte Carlo model for path samples.
Generates random paths using a sequence generator.
single-factor random walk
Real front() const
initial asset value
base class for path pricers
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
const ext::shared_ptr< Payoff > payoff_
flat forward rate term structure
detail::percent_holder volatility(Volatility)
output volatilities as percentages
Real Time
continuous quantity with 1-year units
Real DiscountFactor
discount factor between dates
Real Volatility
volatility
std::size_t Size
size of a container
ext::shared_ptr< QuantLib::Payoff > payoff
General-purpose Monte Carlo model.
RelinkableHandle< Quote > makeQuoteHandle(Real value)
ext::shared_ptr< YieldTermStructure > r
Global definitions and compiler switches.