Igor Swie
2017-04-28 08:12:08 UTC
Hi,
I have tried to price arithmetic asian options with the Monte Carlo pricer
and a complete volatility surface.
There are about 80 points for the construction of the volatility surface
and I run the Monte Carlo simulation with 1500 paths.
I get the result after 1 or 2 minutes which is incredibly slow compared to
other fiancnial softwares (less than 1s).
Who would have an idea of the problem?
Besides is the code I used:
/*************************************code********************************/
void asian()
{
// Calendar set up
Calendar calendar = TARGET();
Date todaysDate(4, April, 2017);
Settings::instance().evaluationDate() = todaysDate;
DayCounter dayCounter = Actual360();
// Option parameters Asian FX
Option::Type optionType(Option::Call);
Average::Type averageType = Average::Arithmetic;
Date maturity(4, April, 2018);
Real strike = 0.74;
Volatility volatility = 0.07053702474;
Date obsStart(4, March, 2018);
Real runningSum = 0;
Size pastFixings = 0;
vector<Date> fixingDates;
for (Date incrementedDate = obsStart; incrementedDate <= maturity;
incrementedDate += 1)
{
if (calendar.isBusinessDay(incrementedDate))
{
fixingDates.push_back(incrementedDate);
}
}
// Option exercise type
boost::shared_ptr<Exercise> europeanExercise(
new EuropeanExercise(maturity));
//Model param
Real underlying = 0.748571186;
Spread dividendYield = 0.04125;
Rate riskFreeRate = 0.0225377;
// Quote handling
Handle<Quote> underlyingH(
boost::shared_ptr<Quote>(new SimpleQuote(underlying)));
// Yield term structure handling
Handle<YieldTermStructure> flatTermStructure(
boost::shared_ptr<YieldTermStructure>(new FlatForward(todaysDate,
dividendYield, dayCounter)));
// Dividend term structure handling
Handle<YieldTermStructure> flatDividendTermStructure(
boost::shared_ptr<YieldTermStructure>(new FlatForward(todaysDate,
riskFreeRate, dayCounter)));
// Volatility structure handling: constant volatility
Handle<BlackVolTermStructure> flatVolTermStructure(
boost::shared_ptr<BlackVolTermStructure>(new BlackConstantVol(todaysDate,
calendar, volatility, dayCounter)));
string path = "E:\\Libraries\\QuantLib-1.9.1\\VolMatrixA.csv";
vector<Real> strikes = {};
GetStrikes(path, strikes);
vector<Date> expirations;
GetExpiryDates(path, expirations);
Matrix volMatrix = GetVolData(path, expirations, strikes);
BlackVarianceSurface
volatilitySurface(Settings::instance().evaluationDate(),
calendar, expirations, strikes, volMatrix, dayCounter);
volatilitySurface.setInterpolation<Bicubic>();
volatilitySurface.enableExtrapolation(true);
const boost::shared_ptr<BlackVarianceSurface> volatilitySurfaceH(
new BlackVarianceSurface(volatilitySurface));
Handle<BlackVolTermStructure> volTermStructure(volatilitySurfaceH);
// the BS equation behind
boost::shared_ptr<BlackScholesMertonProcess> bsmProcess(
new BlackScholesMertonProcess(underlyingH, flatDividendTermStructure,
flatTermStructure, volTermStructure));
// Payoff
boost::shared_ptr<StrikedTypePayoff> payoffAsianOption(
new PlainVanillaPayoff(
Option::Type(optionType),
strike));
// Options
DiscreteAveragingAsianOption discreteArithmeticAsianAverageOption(
averageType,
runningSum,
pastFixings,
fixingDates,
payoffAsianOption,
europeanExercise);
// Ouputting on the screen
cout << "Option type = " << optionType << endl;
cout << "Option maturity = " << maturity << endl;
cout << "Underlying = " << underlying << endl;
cout << "Strike = " << strike << endl;
cout << "Risk-free interest rate = " << setprecision(4) <<
io::rate(riskFreeRate) << endl;
cout << "Dividend yield = " << setprecision(4) << io::rate(dividendYield)
<< endl;
cout << "Volatility = " << setprecision(4) << io::volatility(volatility) <<
endl;
cout << "Time-length between successive fixings = weekly time step" << endl;
cout << "Previous fixings = " << pastFixings << endl;
cout << setprecision(10) << endl;
boost::timer timer;
//Pricing engine
discreteArithmeticAsianAverageOption.setPricingEngine(
boost::shared_ptr<PricingEngine>(
MakeMCDiscreteArithmeticAPEngine<LowDiscrepancy>(bsmProcess)
.withSamples(1500)));
timer.restart();
try
{
cout << "Discrete ArithMC Price: " <<
discreteArithmeticAsianAverageOption.NPV() << endl;
}
catch (exception const& e) { cout << "Erreur: " << e.what() << endl; }
cout << " in " << timer.elapsed() << " s" << endl;
timer.restart();
}
/**************************end
************************************************/
and the volatility data used in .csv format: first column the strikes,
second column volatilities at maturity 6/27/2017 for the corresponding
strikes ans so on.
/***************************volatility
data**************************************/
Strike ,6/27/2017,9/27/2017,12/27/2017,6/27/2018,
0.67263,0.144183920277296,0.139374695503699,0.135526204819277,0.12885
0.71865,0.133703802426343,0.129893056346044,0.126909006024096,0.12175
0.7487,0.126860526863085,0.123701764371087,0.121209416342412,0.11695
0.77129,0.121720863192182,0.118881707209199,0.116979766476388,0.11381
0.78984,0.117581136690647,0.115218428824572,0.113899219047619,0.11163
0.80587,0.114363421052632,0.112523118729097,0.111637193240265,0.11019
0.82034,0.111728795180723,0.110489402985075,0.109987692307692,0.10921
0.83379,0.109805703883495,0.109100413723512,0.108870460584588,0.1086
0.84658,0.108581646586345,0.108250493273543,0.108197213114754,0.10829
0.85792,0.108190964125561,0.107986172506739,0.10796631037213,0.10822
0.87354,0.10859510460251,0.108310304612707,0.108232350773766,0.10849
0.89085,0.110043016488846,0.109404567049808,0.109102906403941,0.10919
0.90904,0.112447321958457,0.111343238289206,0.110615417475728,0.11036
0.9289,0.115567066189624,0.113888152866242,0.112830993150685,0.11201
0.95157,0.119454321849106,0.117151688909342,0.115569047072331,0.11433
0.97862,0.123858310308183,0.121275916334661,0.119199029605263,0.11731
1.01337,0.129434558979809,0.126231870274572,0.123929902439024,0.12145
1.06261,0.137335982996812,0.133099606048548,0.12994278699187,0.12723
1.14631,0.150767120085016,0.144773641066454,0.140163713821138,0.13547
/********************************end vol data ***************************/
I think it's because too many calls are made to get the local volatility.
Thanks,
Igor
I have tried to price arithmetic asian options with the Monte Carlo pricer
and a complete volatility surface.
There are about 80 points for the construction of the volatility surface
and I run the Monte Carlo simulation with 1500 paths.
I get the result after 1 or 2 minutes which is incredibly slow compared to
other fiancnial softwares (less than 1s).
Who would have an idea of the problem?
Besides is the code I used:
/*************************************code********************************/
void asian()
{
// Calendar set up
Calendar calendar = TARGET();
Date todaysDate(4, April, 2017);
Settings::instance().evaluationDate() = todaysDate;
DayCounter dayCounter = Actual360();
// Option parameters Asian FX
Option::Type optionType(Option::Call);
Average::Type averageType = Average::Arithmetic;
Date maturity(4, April, 2018);
Real strike = 0.74;
Volatility volatility = 0.07053702474;
Date obsStart(4, March, 2018);
Real runningSum = 0;
Size pastFixings = 0;
vector<Date> fixingDates;
for (Date incrementedDate = obsStart; incrementedDate <= maturity;
incrementedDate += 1)
{
if (calendar.isBusinessDay(incrementedDate))
{
fixingDates.push_back(incrementedDate);
}
}
// Option exercise type
boost::shared_ptr<Exercise> europeanExercise(
new EuropeanExercise(maturity));
//Model param
Real underlying = 0.748571186;
Spread dividendYield = 0.04125;
Rate riskFreeRate = 0.0225377;
// Quote handling
Handle<Quote> underlyingH(
boost::shared_ptr<Quote>(new SimpleQuote(underlying)));
// Yield term structure handling
Handle<YieldTermStructure> flatTermStructure(
boost::shared_ptr<YieldTermStructure>(new FlatForward(todaysDate,
dividendYield, dayCounter)));
// Dividend term structure handling
Handle<YieldTermStructure> flatDividendTermStructure(
boost::shared_ptr<YieldTermStructure>(new FlatForward(todaysDate,
riskFreeRate, dayCounter)));
// Volatility structure handling: constant volatility
Handle<BlackVolTermStructure> flatVolTermStructure(
boost::shared_ptr<BlackVolTermStructure>(new BlackConstantVol(todaysDate,
calendar, volatility, dayCounter)));
string path = "E:\\Libraries\\QuantLib-1.9.1\\VolMatrixA.csv";
vector<Real> strikes = {};
GetStrikes(path, strikes);
vector<Date> expirations;
GetExpiryDates(path, expirations);
Matrix volMatrix = GetVolData(path, expirations, strikes);
BlackVarianceSurface
volatilitySurface(Settings::instance().evaluationDate(),
calendar, expirations, strikes, volMatrix, dayCounter);
volatilitySurface.setInterpolation<Bicubic>();
volatilitySurface.enableExtrapolation(true);
const boost::shared_ptr<BlackVarianceSurface> volatilitySurfaceH(
new BlackVarianceSurface(volatilitySurface));
Handle<BlackVolTermStructure> volTermStructure(volatilitySurfaceH);
// the BS equation behind
boost::shared_ptr<BlackScholesMertonProcess> bsmProcess(
new BlackScholesMertonProcess(underlyingH, flatDividendTermStructure,
flatTermStructure, volTermStructure));
// Payoff
boost::shared_ptr<StrikedTypePayoff> payoffAsianOption(
new PlainVanillaPayoff(
Option::Type(optionType),
strike));
// Options
DiscreteAveragingAsianOption discreteArithmeticAsianAverageOption(
averageType,
runningSum,
pastFixings,
fixingDates,
payoffAsianOption,
europeanExercise);
// Ouputting on the screen
cout << "Option type = " << optionType << endl;
cout << "Option maturity = " << maturity << endl;
cout << "Underlying = " << underlying << endl;
cout << "Strike = " << strike << endl;
cout << "Risk-free interest rate = " << setprecision(4) <<
io::rate(riskFreeRate) << endl;
cout << "Dividend yield = " << setprecision(4) << io::rate(dividendYield)
<< endl;
cout << "Volatility = " << setprecision(4) << io::volatility(volatility) <<
endl;
cout << "Time-length between successive fixings = weekly time step" << endl;
cout << "Previous fixings = " << pastFixings << endl;
cout << setprecision(10) << endl;
boost::timer timer;
//Pricing engine
discreteArithmeticAsianAverageOption.setPricingEngine(
boost::shared_ptr<PricingEngine>(
MakeMCDiscreteArithmeticAPEngine<LowDiscrepancy>(bsmProcess)
.withSamples(1500)));
timer.restart();
try
{
cout << "Discrete ArithMC Price: " <<
discreteArithmeticAsianAverageOption.NPV() << endl;
}
catch (exception const& e) { cout << "Erreur: " << e.what() << endl; }
cout << " in " << timer.elapsed() << " s" << endl;
timer.restart();
}
/**************************end
************************************************/
and the volatility data used in .csv format: first column the strikes,
second column volatilities at maturity 6/27/2017 for the corresponding
strikes ans so on.
/***************************volatility
data**************************************/
Strike ,6/27/2017,9/27/2017,12/27/2017,6/27/2018,
0.67263,0.144183920277296,0.139374695503699,0.135526204819277,0.12885
0.71865,0.133703802426343,0.129893056346044,0.126909006024096,0.12175
0.7487,0.126860526863085,0.123701764371087,0.121209416342412,0.11695
0.77129,0.121720863192182,0.118881707209199,0.116979766476388,0.11381
0.78984,0.117581136690647,0.115218428824572,0.113899219047619,0.11163
0.80587,0.114363421052632,0.112523118729097,0.111637193240265,0.11019
0.82034,0.111728795180723,0.110489402985075,0.109987692307692,0.10921
0.83379,0.109805703883495,0.109100413723512,0.108870460584588,0.1086
0.84658,0.108581646586345,0.108250493273543,0.108197213114754,0.10829
0.85792,0.108190964125561,0.107986172506739,0.10796631037213,0.10822
0.87354,0.10859510460251,0.108310304612707,0.108232350773766,0.10849
0.89085,0.110043016488846,0.109404567049808,0.109102906403941,0.10919
0.90904,0.112447321958457,0.111343238289206,0.110615417475728,0.11036
0.9289,0.115567066189624,0.113888152866242,0.112830993150685,0.11201
0.95157,0.119454321849106,0.117151688909342,0.115569047072331,0.11433
0.97862,0.123858310308183,0.121275916334661,0.119199029605263,0.11731
1.01337,0.129434558979809,0.126231870274572,0.123929902439024,0.12145
1.06261,0.137335982996812,0.133099606048548,0.12994278699187,0.12723
1.14631,0.150767120085016,0.144773641066454,0.140163713821138,0.13547
/********************************end vol data ***************************/
I think it's because too many calls are made to get the local volatility.
Thanks,
Igor