Skip to content

Commit

Permalink
Merge pull request #810.
Browse files Browse the repository at this point in the history
Monte Carlo pricing engines for all lookbacks
  • Loading branch information
lballabio committed May 9, 2020
2 parents 619ebe5 + 10827f0 commit 86869ef
Show file tree
Hide file tree
Showing 11 changed files with 860 additions and 95 deletions.
4 changes: 3 additions & 1 deletion QuantLib.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1508,6 +1508,7 @@
<ClInclude Include="ql\pricingengines\lookback\analyticcontinuousfloatinglookback.hpp" />
<ClInclude Include="ql\pricingengines\lookback\analyticcontinuouspartialfixedlookback.hpp" />
<ClInclude Include="ql\pricingengines\lookback\analyticcontinuouspartialfloatinglookback.hpp" />
<ClInclude Include="ql\pricingengines\lookback\mclookbackengine.hpp" />
<ClInclude Include="ql\pricingengines\mclongstaffschwartzengine.hpp" />
<ClInclude Include="ql\pricingengines\mcsimulation.hpp" />
<ClInclude Include="ql\pricingengines\quanto\all.hpp" />
Expand Down Expand Up @@ -2522,6 +2523,7 @@
<ClCompile Include="ql\pricingengines\lookback\analyticcontinuousfloatinglookback.cpp" />
<ClCompile Include="ql\pricingengines\lookback\analyticcontinuouspartialfixedlookback.cpp" />
<ClCompile Include="ql\pricingengines\lookback\analyticcontinuouspartialfloatinglookback.cpp" />
<ClCompile Include="ql\pricingengines\lookback\mclookbackengine.cpp" />
<ClCompile Include="ql\pricingengines\swap\cvaswapengine.cpp" />
<ClCompile Include="ql\pricingengines\swap\discountingswapengine.cpp" />
<ClCompile Include="ql\pricingengines\swap\discretizedswap.cpp" />
Expand Down Expand Up @@ -2747,4 +2749,4 @@
<Import Project=".\Build.props" Condition="Exists('.\Build.props')" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
8 changes: 7 additions & 1 deletion QuantLib.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -2568,6 +2568,9 @@
<ClInclude Include="ql\pricingengines\lookback\analyticcontinuouspartialfloatinglookback.hpp">
<Filter>pricingengines\lookback</Filter>
</ClInclude>
<ClInclude Include="ql\pricingengines\lookback\mclookbackengine.hpp">
<Filter>pricingengines\lookback</Filter>
</ClInclude>
<ClInclude Include="ql\pricingengines\bond\all.hpp">
<Filter>pricingengines\bond</Filter>
</ClInclude>
Expand Down Expand Up @@ -5652,6 +5655,9 @@
<ClCompile Include="ql\pricingengines\lookback\analyticcontinuouspartialfloatinglookback.cpp">
<Filter>pricingengines\lookback</Filter>
</ClCompile>
<ClCompile Include="ql\pricingengines\lookback\mclookbackengine.cpp">
<Filter>pricingengines\lookback</Filter>
</ClCompile>
<ClCompile Include="ql\pricingengines\bond\bondfunctions.cpp">
<Filter>pricingengines\bond</Filter>
</ClCompile>
Expand Down Expand Up @@ -6949,4 +6955,4 @@
<Filter>methods\finitedifferences\schemes</Filter>
</ClCompile>
</ItemGroup>
</Project>
</Project>
2 changes: 2 additions & 0 deletions ql/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,7 @@ set(QuantLib_SRC
pricingengines/lookback/analyticcontinuousfloatinglookback.cpp
pricingengines/lookback/analyticcontinuouspartialfixedlookback.cpp
pricingengines/lookback/analyticcontinuouspartialfloatinglookback.cpp
pricingengines/lookback/mclookbackengine.cpp
pricingengines/swap/cvaswapengine.cpp
pricingengines/swap/discountingswapengine.cpp
pricingengines/swap/discretizedswap.cpp
Expand Down Expand Up @@ -1940,6 +1941,7 @@ set(QuantLib_HDR
pricingengines/lookback/analyticcontinuousfloatinglookback.hpp
pricingengines/lookback/analyticcontinuouspartialfixedlookback.hpp
pricingengines/lookback/analyticcontinuouspartialfloatinglookback.hpp
pricingengines/lookback/mclookbackengine.hpp
pricingengines/mclongstaffschwartzengine.hpp
pricingengines/mcsimulation.hpp
pricingengines/quanto/all.hpp
Expand Down
11 changes: 11 additions & 0 deletions ql/instruments/payoffs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,17 @@ namespace QuantLib {
QL_FAIL("floating payoff not handled");
}

Real FloatingTypePayoff::operator()(Real price, Real strike) const {
switch (type_) {
case Option::Call:
return std::max<Real>(price - strike,0.0);
case Option::Put:
return std::max<Real>(strike - price,0.0);
default:
QL_FAIL("unknown/illegal option type");
}
}

std::string StrikedTypePayoff::description() const {
std::ostringstream result;
result << TypePayoff::description() << ", " <<
Expand Down
1 change: 1 addition & 0 deletions ql/instruments/payoffs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ namespace QuantLib {
//! \name Payoff interface
//@{
std::string name() const { return "FloatingType";}
Real operator()(Real price, Real strike) const;
Real operator()(Real price) const;
virtual void accept(AcyclicVisitor&);
//@}
Expand Down
6 changes: 4 additions & 2 deletions ql/pricingengines/lookback/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ this_include_HEADERS = \
analyticcontinuousfixedlookback.hpp \
analyticcontinuousfloatinglookback.hpp \
analyticcontinuouspartialfixedlookback.hpp \
analyticcontinuouspartialfloatinglookback.hpp
analyticcontinuouspartialfloatinglookback.hpp \
mclookbackengine.hpp

cpp_files = \
analyticcontinuousfixedlookback.cpp \
analyticcontinuousfloatinglookback.cpp \
analyticcontinuouspartialfixedlookback.cpp \
analyticcontinuouspartialfloatinglookback.cpp
analyticcontinuouspartialfloatinglookback.cpp \
mclookbackengine.cpp

if UNITY_BUILD

Expand Down
1 change: 1 addition & 0 deletions ql/pricingengines/lookback/all.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
#include <ql/pricingengines/lookback/analyticcontinuousfloatinglookback.hpp>
#include <ql/pricingengines/lookback/analyticcontinuouspartialfixedlookback.hpp>
#include <ql/pricingengines/lookback/analyticcontinuouspartialfloatinglookback.hpp>
#include <ql/pricingengines/lookback/mclookbackengine.hpp>

252 changes: 252 additions & 0 deletions ql/pricingengines/lookback/mclookbackengine.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
Copyright (C) 2020 Lew Wei Hao
This file is part of QuantLib, a free-software/open-source library
for financial quantitative analysts and developers - http://quantlib.org/
QuantLib is free software: you can redistribute it and/or modify it
under the terms of the QuantLib license. You should have received a
copy of the license along with this program; if not, please email
<quantlib-dev@lists.sf.net>. The license is also available online at
<http://quantlib.org/license.shtml>.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the license for more details.
*/

#include <ql/pricingengines/lookback/mclookbackengine.hpp>
#include <algorithm>

namespace QuantLib {

class LookbackFixedPathPricer : public PathPricer<Path> {
public:
LookbackFixedPathPricer(Option::Type type,
Real strike,
DiscountFactor discount);
Real operator()(const Path& path) const;
private:
PlainVanillaPayoff payoff_;
DiscountFactor discount_;
};

class LookbackPartialFixedPathPricer : public PathPricer<Path> {
public:
LookbackPartialFixedPathPricer(Time lookbackStart,
Option::Type type,
Real strike,
const DiscountFactor discount);
Real operator()(const Path& path) const;
private:
Time lookbackStart_;
PlainVanillaPayoff payoff_;
DiscountFactor discount_;
};

class LookbackFloatingPathPricer : public PathPricer<Path> {
public:
LookbackFloatingPathPricer(Option::Type type,
DiscountFactor discount);
Real operator()(const Path& path) const;
private:
FloatingTypePayoff payoff_;
DiscountFactor discount_;
};

class LookbackPartialFloatingPathPricer : public PathPricer<Path> {
public:
LookbackPartialFloatingPathPricer(Time lookbackEnd,
Option::Type type,
DiscountFactor discount);
Real operator()(const Path& path) const;
private:
Time lookbackEnd_;
FloatingTypePayoff payoff_;
DiscountFactor discount_;
};

namespace detail {

ext::shared_ptr<PathPricer<Path> >
mc_lookback_path_pricer(
const ContinuousFixedLookbackOption::arguments& args,
const GeneralizedBlackScholesProcess& process,
DiscountFactor discount) {
ext::shared_ptr<PlainVanillaPayoff> payoff =
ext::dynamic_pointer_cast<PlainVanillaPayoff>(args.payoff);
QL_REQUIRE(payoff, "non-plain payoff given");

return ext::shared_ptr<PathPricer<Path> >(
new LookbackFixedPathPricer(payoff->optionType(),
payoff->strike(),
discount));
}

ext::shared_ptr<PathPricer<Path> >
mc_lookback_path_pricer(
const ContinuousPartialFixedLookbackOption::arguments& args,
const GeneralizedBlackScholesProcess& process,
DiscountFactor discount) {
ext::shared_ptr<PlainVanillaPayoff> payoff =
ext::dynamic_pointer_cast<PlainVanillaPayoff>(args.payoff);
QL_REQUIRE(payoff, "non-plain payoff given");

Time lookbackStart = process.time(args.lookbackPeriodStart);

return ext::shared_ptr<PathPricer<Path> >(
new LookbackPartialFixedPathPricer(lookbackStart,
payoff->optionType(),
payoff->strike(),
discount));
}

ext::shared_ptr<PathPricer<Path> >
mc_lookback_path_pricer(
const ContinuousFloatingLookbackOption::arguments& args,
const GeneralizedBlackScholesProcess& process,
DiscountFactor discount) {
ext::shared_ptr<FloatingTypePayoff> payoff =
ext::dynamic_pointer_cast<FloatingTypePayoff>(args.payoff);
QL_REQUIRE(payoff, "non-floating payoff given");

return ext::shared_ptr<PathPricer<Path> >(
new LookbackFloatingPathPricer(payoff->optionType(),
discount));
}

ext::shared_ptr<PathPricer<Path> >
mc_lookback_path_pricer(
const ContinuousPartialFloatingLookbackOption::arguments& args,
const GeneralizedBlackScholesProcess& process,
DiscountFactor discount) {
ext::shared_ptr<FloatingTypePayoff> payoff =
ext::dynamic_pointer_cast<FloatingTypePayoff>(args.payoff);
QL_REQUIRE(payoff, "non-floating payoff given");

Time lookbackEnd = process.time(args.lookbackPeriodEnd);

return ext::shared_ptr<PathPricer<Path> >(
new LookbackPartialFloatingPathPricer(lookbackEnd,
payoff->optionType(),
discount));
}

}


LookbackFixedPathPricer::LookbackFixedPathPricer(
Option::Type type,
Real strike,
DiscountFactor discount)
: payoff_(type, strike), discount_(discount) {
QL_REQUIRE(strike>=0.0,
"strike less than zero not allowed");
}

Real LookbackFixedPathPricer::operator()(const Path& path) const {
QL_REQUIRE(!path.empty(), "the path cannot be empty");

Real underlying;
switch (payoff_.optionType()) {
case Option::Put:
underlying = *std::min_element(path.begin()+1, path.end());
break;
case Option::Call:
underlying = *std::max_element(path.begin()+1, path.end());
break;
default:
QL_FAIL("unknown option type");
}

return payoff_(underlying) * discount_;
}


LookbackPartialFixedPathPricer::LookbackPartialFixedPathPricer(
Time lookbackStart,
Option::Type type,
Real strike,
const DiscountFactor discount)
: lookbackStart_(lookbackStart), payoff_(type, strike), discount_(discount) {
QL_REQUIRE(strike>=0.0,
"strike less than zero not allowed");
}

Real LookbackPartialFixedPathPricer::operator()(const Path& path) const {
QL_REQUIRE(!path.empty(), "the path cannot be empty");

TimeGrid timeGrid = path.timeGrid();
Size startIndex = timeGrid.closestIndex(lookbackStart_);
Real underlying;
switch (payoff_.optionType()) {
case Option::Put:
underlying = *std::min_element(path.begin()+startIndex+1, path.end());
break;
case Option::Call:
underlying = *std::max_element(path.begin()+startIndex+1, path.end());
break;
default:
QL_FAIL("unknown option type");
}

return payoff_(underlying) * discount_;
}


LookbackFloatingPathPricer::LookbackFloatingPathPricer(
Option::Type type,
const DiscountFactor discount)
: payoff_(type), discount_(discount) {}

Real LookbackFloatingPathPricer::operator()(const Path& path) const {
QL_REQUIRE(!path.empty(), "the path cannot be empty");

Real terminalPrice = path.back();
Real strike;
switch (payoff_.optionType()) {
case Option::Call:
strike = *std::min_element(path.begin()+1, path.end());
break;
case Option::Put:
strike = *std::max_element(path.begin()+1, path.end());
break;
default:
QL_FAIL("unknown option type");
}

return payoff_(terminalPrice, strike) * discount_;
}


LookbackPartialFloatingPathPricer::LookbackPartialFloatingPathPricer(
Time lookbackEnd,
Option::Type type,
DiscountFactor discount)
: lookbackEnd_(lookbackEnd), payoff_(type), discount_(discount) {}

Real LookbackPartialFloatingPathPricer::operator()(const Path& path) const {
QL_REQUIRE(!path.empty(), "the path cannot be empty");

TimeGrid timeGrid = path.timeGrid();
Size endIndex = timeGrid.closestIndex(lookbackEnd_);
Real terminalPrice = path.back();
Real strike;

switch (payoff_.optionType()) {
case Option::Call:
strike = *std::min_element(path.begin()+1, path.begin()+endIndex+1);
break;
case Option::Put:
strike = *std::max_element(path.begin()+1, path.begin()+endIndex+1);
break;
default:
QL_FAIL("unknown option type");
}

return payoff_(terminalPrice, strike) * discount_;
}

}

0 comments on commit 86869ef

Please sign in to comment.