00001
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
#include <ql/quantlib.hpp>
00047
00048
using namespace QuantLib;
00049
00050
00051
00052
00053
00054
class ReplicationError
00055 {
00056
public:
00057 ReplicationError(Option::Type type,
00058 Time maturity,
00059 Real strike,
00060 Real s0,
00061 Volatility sigma,
00062 Rate r)
00063 : maturity_(maturity), payoff_(type, strike), s0_(s0),
00064 sigma_(sigma), r_(r) {
00065
00066
00067
DiscountFactor rDiscount =
QL_EXP(-r_*maturity_);
00068
DiscountFactor qDiscount = 1.0;
00069
Real forward = s0_*qDiscount/rDiscount;
00070
Real variance = sigma_*sigma_*maturity_;
00071 boost::shared_ptr<StrikedTypePayoff> payoff(
00072
new PlainVanillaPayoff(payoff_));
00073 BlackFormula black(forward,rDiscount,variance,payoff);
00074 std::cout <<
"Option value: " << black.value() << std::endl;
00075
00076
00077 vega_ = black.vega(maturity_);
00078
00079 std::cout << std::endl;
00080 std::cout <<
00081
" | | P&L \t| P&L | Derman&Kamal | P&L"
00082
" \t| P&L" << std::endl;
00083
00084 std::cout <<
00085
"samples | trades | Mean \t| Std Dev | Formula |"
00086
" skewness \t| kurt." << std::endl;
00087
00088 std::cout <<
"---------------------------------"
00089
"----------------------------------------------" << std::endl;
00090 }
00091
00092
00093
void compute(Size nTimeSteps, Size nSamples);
00094
private:
00095
Time maturity_;
00096 PlainVanillaPayoff payoff_;
00097
Real s0_;
00098
Volatility sigma_;
00099
Rate r_;
00100
Real vega_;
00101 };
00102
00103
00104
00105
00106
class ReplicationPathPricer :
public PathPricer<Path>
00107 {
00108
public:
00109
00110 ReplicationPathPricer(Option::Type type,
00111 Real underlying,
00112 Real strike,
00113 Rate r,
00114 Time maturity,
00115 Volatility sigma)
00116 : type_(type), underlying_(underlying),
00117 strike_(strike), r_(r), maturity_(maturity), sigma_(sigma) {
00118
QL_REQUIRE(strike_ > 0.0,
"strike must be positive");
00119
QL_REQUIRE(underlying_ > 0.0,
"underlying must be positive");
00120
QL_REQUIRE(r_ >= 0.0,
00121
"risk free rate (r) must be positive or zero");
00122
QL_REQUIRE(maturity_ > 0.0,
"maturity must be positive");
00123
QL_REQUIRE(sigma_ >= 0.0,
00124
"volatility (sigma) must be positive or zero");
00125
00126 }
00127
00128
Real operator()(
const Path& path)
const;
00129
00130
private:
00131 Option::Type type_;
00132
Real underlying_, strike_;
00133
Rate r_;
00134
Time maturity_;
00135
Volatility sigma_;
00136 };
00137
00138
00139
00140
int main(
int,
char* [])
00141 {
00142
try {
00143
QL_IO_INIT
00144
00145
Time maturity = 1./12.;
00146
Real strike = 100;
00147
Real underlying = 100;
00148
Volatility volatility = 0.20;
00149
Rate riskFreeRate = 0.05;
00150 ReplicationError rp(Option::Call, maturity, strike, underlying,
00151 volatility, riskFreeRate);
00152
00153
Size scenarios = 50000;
00154
Size hedgesNum;
00155
00156 hedgesNum = 21;
00157 rp.compute(hedgesNum, scenarios);
00158
00159 hedgesNum = 84;
00160 rp.compute(hedgesNum, scenarios);
00161
00162
return 0;
00163 }
catch (std::exception& e) {
00164 std::cout << e.what() << std::endl;
00165
return 1;
00166 }
catch (...) {
00167 std::cout <<
"unknown error" << std::endl;
00168
return 1;
00169 }
00170 }
00171
00172
00173
00174
00175
00176
00177
00178
00179
Real ReplicationPathPricer::operator()(
const Path& path)
const
00180
{
00181
00182
00183
00184
00185
Size n = path.size();
00186
QL_REQUIRE(n>0,
"the path cannot be empty");
00187
00188
00189
Time dt = maturity_/n;
00190
00191
00192
Rate stockDividendYield = 0.0;
00193
00194
00195
Time t = 0;
00196
00197
00198
Real stock = underlying_;
00199
Real stockLogGrowth = 0.0;
00200
00201
00202
Real money_account = 0.0;
00203
00204
00205
00206
00207
00208
DiscountFactor rDiscount =
QL_EXP(-r_*maturity_);
00209
DiscountFactor qDiscount =
QL_EXP(-stockDividendYield*maturity_);
00210
Real forward = stock*qDiscount/rDiscount;
00211
Real variance = sigma_*sigma_*maturity_;
00212 boost::shared_ptr<StrikedTypePayoff> payoff(
00213
new PlainVanillaPayoff(type_,strike_));
00214 BlackFormula black(forward,rDiscount,variance,payoff);
00215
00216 money_account += black.value();
00217
00218
Real delta = black.delta(stock);
00219
00220
Real stockAmount = delta;
00221 money_account -= stockAmount*stock;
00222
00223
00224
00225
00226
for (
Size step = 0; step < n-1; step++){
00227
00228
00229 t += dt;
00230
00231
00232 money_account *=
QL_EXP( r_*dt );
00233
00234
00235
00236
00237 stockLogGrowth += path[step];
00238 stock = underlying_*
QL_EXP(stockLogGrowth);
00239
00240
00241
00242 rDiscount =
QL_EXP(-r_*(maturity_-t));
00243 qDiscount =
QL_EXP(-stockDividendYield*(maturity_-t));
00244 forward = stock*qDiscount/rDiscount;
00245 variance = sigma_*sigma_*(maturity_-t);
00246 BlackFormula black(forward,rDiscount,variance,payoff);
00247
00248
00249 delta = black.delta(stock);
00250
00251
00252 money_account -= (delta - stockAmount)*stock;
00253 stockAmount = delta;
00254 }
00255
00256
00257
00258
00259
00260 money_account *=
QL_EXP( r_*dt );
00261
00262 stockLogGrowth += path[n-1];
00263 stock = underlying_*
QL_EXP(stockLogGrowth);
00264
00265
00266
Real optionPayoff = PlainVanillaPayoff(type_, strike_)(stock);
00267 money_account -= optionPayoff;
00268
00269
00270 money_account += stockAmount*stock;
00271
00272
00273
return money_account;
00274 }
00275
00276
00277
00278
void ReplicationError::compute(Size nTimeSteps, Size nSamples)
00279 {
00280
QL_REQUIRE(nTimeSteps>0,
"the number of steps must be > 0");
00281
00282
00283
00284
00285
00286
00287
00288
00289 Date today = Date::todaysDate();
00290 RelinkableHandle<Quote> stateVariable(
00291 boost::shared_ptr<Quote>(
new SimpleQuote(s0_)));
00292 RelinkableHandle<TermStructure> riskFreeRate(
00293 boost::shared_ptr<TermStructure>(
00294
new FlatForward(today, today, r_)));
00295 RelinkableHandle<TermStructure> dividendYield(
00296 boost::shared_ptr<TermStructure>(
00297
new FlatForward(today, today, 0.0)));
00298 RelinkableHandle<BlackVolTermStructure> volatility(
00299 boost::shared_ptr<BlackVolTermStructure>(
00300
new BlackConstantVol(today, sigma_)));
00301 boost::shared_ptr<StochasticProcess> diffusion(
00302
new BlackScholesProcess(stateVariable, dividendYield,
00303 riskFreeRate, volatility));
00304
00305
00306
00307
00308 PseudoRandom::rsg_type rsg =
00309 PseudoRandom::make_sequence_generator(nTimeSteps, 0);
00310
00311
typedef SingleAsset<PseudoRandom>::path_generator_type generator_type;
00312 boost::shared_ptr<generator_type> myPathGenerator(
00313
new generator_type(diffusion, maturity_, nTimeSteps,
00314 rsg,
false));
00315
00316
00317
00318
00319 boost::shared_ptr<PathPricer<Path> > myPathPricer(
new
00320 ReplicationPathPricer(payoff_.optionType(), s0_,
00321 payoff_.strike(), r_, maturity_, sigma_));
00322
00323
00324 Statistics statisticsAccumulator;
00325
00326
00327
00328
00329 OneFactorMonteCarloOption MCSimulation(myPathGenerator,
00330 myPathPricer,
00331 statisticsAccumulator,
00332
false);
00333
00334
00335 MCSimulation.addSamples(nSamples);
00336
00337
00338
00339
Real PLMean = MCSimulation.sampleAccumulator().mean();
00340
Real PLStDev = MCSimulation.sampleAccumulator().standardDeviation();
00341
Real PLSkew = MCSimulation.sampleAccumulator().skewness();
00342
Real PLKurt = MCSimulation.sampleAccumulator().kurtosis();
00343
00344
00345
Real theorStD =
QL_SQRT(M_PI/4/nTimeSteps)*vega_*sigma_;
00346
00347
00348 std::cout << nSamples <<
"\t| "
00349 << nTimeSteps <<
"\t | "
00350 << DecimalFormatter::toString(PLMean, 3) <<
" \t| "
00351 << DecimalFormatter::toString(PLStDev, 2) <<
" \t | "
00352 << DecimalFormatter::toString(theorStD, 2) <<
" \t | "
00353 << DecimalFormatter::toString(PLSkew, 2) <<
" \t| "
00354 << DecimalFormatter::toString(PLKurt, 2) << std::endl;
00355 }