Dear all
I have two newbie problems. I want to price a European D&I Put for an equity paying discrete dividends. For this purpose I took "QuantLib-1.2/test-suite/barrieroption.cpp" as a frame for my own piece of source (see bottom of this mail; "utilities.hpp" and "utilities.cpp" can be found in the dirctory "QuantLib-1.2/test-suite" of the QL source tree). IR, volatility and the underlying's spot are defined as "SimpleQuote", the barrier option is of type "DividendBarrierOption" (see line 88 of code below). 1. Problem ----------------- When running through the for-loop (line 121) I expected that changing the underlying's spot price (e.g. "spot -> setValue(123.4)", see line 124 of code below) would have an impact on calculated values of the barrier option ( e.g. "dividendBarrierOption.NPV()" ), but whenever I change the value of the underlying's spot, the calculated quantities remain unchanged. As I use the Pricing Engine "FdBlackScholesBarrierEngine", I realized that in the file "ql/pricingengines/barrier/fdblackscholesbarrierengine.cpp" the constructor "FdBlackScholesBarrierEngine" is not defined as an Observer of the "GeneralizedBlackScholesProcess", which is the first argumet of the constructor. Hence, I added a "registerWith(process_);" to the constructor "FdBlackScholesBarrierEngine" and the calculated quantities of my "dividendBarrierOption" became spot price sensitive. Is adding "registerWith(process_);" to the constructor a reliable/reasonable/good way to obtain values sensitive to the spot price??? If not, can you give me some hints? 2. Problem ------------------ After having "solved" (?) my above 1st problem, I added an additional option of type "BarrierOption" but without any dividends (see line 65 of code), and set its "PricingEngine" to the very same copy of the PricingEngine (see lines 98 & 99 of code). I then realized that QuantLib produces the very same NPV() etc. for the two options, ignoring that the one option is modeled with dividends while the other is modeled without dividends. When creating two independent copies of the same PricingEngine (see line 58 - 63) and relating them to the two options (i.e. replacing one of the two "fdEngine" in lines 98 & 99 by "engine"), things seem to be fine. Do I really have to have seperate pricing engines for the two barrier options? Many thanks & kind regards, Paul <-------------------------------------------------- Source Code --------------------------------------------------> #include "utilities.hpp" #include <ql/time/calendars/switzerland.hpp> #include <ql/time/daycounters/actual360.hpp> #include <ql/time/date.hpp> #include <ql/quotes/simplequote.hpp> #include <ql/exercise.hpp> #include <ql/processes/blackscholesprocess.hpp> #include <ql/pricingengines/barrier/analyticbarrierengine.hpp> #include <ql/pricingengines/barrier/mcbarrierengine.hpp> #include <ql/pricingengines/barrier/fdblackscholesbarrierengine.hpp> #include <ql/instruments/dividendbarrieroption.hpp> #include <iostream> #include <iomanip> int main(){ using namespace QuantLib; Calendar cal = Switzerland(); DayCounter dc = Actual360(); Date today = Date(30,Aug,2012); Date maturity = Date(20,Sep,2013); boost::shared_ptr<SimpleQuote> spot(new SimpleQuote(0.0)); boost::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.0)); boost::shared_ptr<YieldTermStructure> qTS = flatRate(today, qRate, dc); boost::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.0)); boost::shared_ptr<YieldTermStructure> rTS = flatRate(today, rRate, dc); boost::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.0)); boost::shared_ptr<BlackVolTermStructure> volTS = flatVol(today, vol, dc); boost::shared_ptr<Exercise> exercise(new EuropeanExercise(maturity)); spot -> setValue(8.835); qRate -> setValue(0.0); rRate ->setValue(0.0024890168); vol ->setValue(0.27183378); boost::shared_ptr<StrikedTypePayoff> payoff( new PlainVanillaPayoff(Option::Put,8.75)); boost::shared_ptr<BlackScholesMertonProcess> stochProcess(new BlackScholesMertonProcess( Handle<Quote>(spot), Handle<YieldTermStructure>(qTS), Handle<YieldTermStructure>(rTS), Handle<BlackVolTermStructure>(volTS))); boost::shared_ptr<PricingEngine> engine( new FdBlackScholesBarrierEngine(stochProcess, 400, 800)); boost::shared_ptr<PricingEngine> fdEngine( new FdBlackScholesBarrierEngine(stochProcess, 400, 800)); BarrierOption barrierOption( Barrier::DownIn, 6.13, 0.0, payoff, exercise); std::vector<Date> dividendDates; std::vector<double> dividends; dividendDates.push_back(Date(14,Sep,2012)); dividends.push_back(0.24); dividendDates.push_back(Date(14,Dec,2012)); dividends.push_back(0.24); dividendDates.push_back(Date(14,Mar,2013)); dividends.push_back(0.24); dividendDates.push_back(Date(14,May,2013)); dividends.push_back(0.24); dividendDates.push_back(Date(14,Jul,2013)); dividends.push_back(0.24); dividendDates.push_back(Date(14,Sep,2013)); dividends.push_back(0.24); DividendBarrierOption dividendBarrierOption( Barrier::DownIn, 6.13, 0.0, payoff, exercise, dividendDates, dividends); barrierOption.setPricingEngine(fdEngine); dividendBarrierOption.setPricingEngine(fdEngine); Real pvBarrier,deltaBarrier,gammaBarrier; Real pvDividendBarrier,deltaDividendBarrier,gammaDividendBarrier; Size width[] = {10,18,18,18,18,18,18}; std::cout << std::setw(width[0]) << "Spot" << std::setw(width[1]) << "PV(no div.)" << std::setw(width[2]) << "PV(with div.)" << std::setw(width[3]) << "Delta(no div.)" << std::setw(width[4]) << "Delta(with div.)" << std::setw(width[5]) << "Gamma(no div.)" << std::setw(width[6]) << "Gamma(with div.)" << std::endl; for(int loop = 0;loop < 5;loop++) { Real loopS = 6.13+loop*0.1; spot->setValue(loopS); pvBarrier = barrierOption.NPV(); deltaBarrier = barrierOption.delta(); gammaBarrier = barrierOption.gamma(); pvDividendBarrier = dividendBarrierOption.NPV(); deltaDividendBarrier = dividendBarrierOption.delta(); gammaDividendBarrier = dividendBarrierOption.gamma(); std::cout << std::fixed; std::cout << std::setprecision(4); std::cout << std::setw(width[0]) << loopS << std::setw(width[1]) << pvBarrier << std::setw(width[2]) << pvDividendBarrier << std::setw(width[3]) << deltaBarrier << std::setw(width[4]) << deltaDividendBarrier << std::setw(width[5]) << gammaBarrier << std::setw(width[6]) << gammaDividendBarrier << std::endl; } return 0; } ------------------------------------------------------------------------------ Live Security Virtual Conference Exclusive live event will cover all the ways today's security and threat landscape has changed and how IT managers can respond. Discussions will include endpoint security, mobile security and the latest in malware threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/ _______________________________________________ QuantLib-users mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-users |
Hi all
Paul, thanks for your problem description!
1. Problem: you are right, this is not the expected behavior. The FDBlackScholesBarrierEngine should be an observer of the Black-Scholes process. I've changed the corresponding code in the SVN trunk.
2. Problem This problem occurs because the same pricing engine is shared between two different type of options, namely BarrierOption and DividendBarrierOption. As far as I can see this might be a more general weekness of the dividend engines, e.g. I can reproduce a similar behavior with
VanillaOption, DividendVanillaOption and AnalyticDividendEuropeanEngine
The root of the problem is that the method BarrierOption::setupArguments does not delete the DividendSchedule within the pricing engine, which has been set by the latest DividendBarrierOption::setupArguments call.
I can think of three possible solutions but other people might come up with better ideas!
Solution A: One solution would now be to define void FdBlackScholesBarrierEngine::reset() { arguments_.cashFlow.clear(); } but we'd have to do this for quite a few other engines as well, which suffer under the same problem.
Solution B: A more general solution would be to define a reset method in PricingEngine::arguments like the reset method we have in PricingEngine::results. The reset method in GenericEngine would then be void GenericEngine::reset() { results_.reset(); arguments_.reset(); } In addition we define void DividendBarrierOption::arguments::reset() { cashFlow.clear(); } void DividendVanillaOption::arguments::reset() { cashFlow.clear(); } Shall we then define a proper reset method for the other pricing arguments as well(?)
Solution C: void GenericEngine::reset() { results_.reset(); arguments_ = ArgumentsType();} Even though it's a single line change to fix the problem I personally don't like it.
regards Klaus
On Tuesday, September 04, 2012 04:22:16 PM Sepp Imboden wrote: Dear all ------------------------------------------------------------------------------ Live Security Virtual Conference Exclusive live event will cover all the ways today's security and threat landscape has changed and how IT managers can respond. Discussions will include endpoint security, mobile security and the latest in malware threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/ _______________________________________________ QuantLib-users mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-users |
Hi,
I dont know about the specific problem but I have stumbled on something looking similar. Might a variant of 'A' be? (or 'B' reusing whats there): void FdBlackScholesBarrierEngine::update() { arguments_.cashFlow.clear(); // ...and anything else, we know the arg type here GenericEngine<bla, bla>::update(); } this will be called on the engine being reasigned to another object. Best pp ----- Mail original ----- De: "Klaus Spanderen" <[hidden email]> À: [hidden email] Cc: "Sepp Imboden" <[hidden email]> Envoyé: Jeudi 6 Septembre 2012 00:30:34 Objet: Re: [Quantlib-users] Questions: FdBlackScholesBarrierEngine Hi all Paul, thanks for your problem description! 1. Problem: you are right, this is not the expected behavior. The FDBlackScholesBarrierEngine should be an observer of the Black-Scholes process. I've changed the corresponding code in the SVN trunk. 2. Problem This problem occurs because the same pricing engine is shared between two different type of options, namely BarrierOption and DividendBarrierOption. As far as I can see this might be a more general weekness of the dividend engines, e.g. I can reproduce a similar behavior with VanillaOption, DividendVanillaOption and AnalyticDividendEuropeanEngine The root of the problem is that the method BarrierOption::setupArguments does not delete the DividendSchedule within the pricing engine, which has been set by the latest DividendBarrierOption::setupArguments call. I can think of three possible solutions but other people might come up with better ideas! Solution A: One solution would now be to define void FdBlackScholesBarrierEngine::reset() { arguments_.cashFlow.clear(); } but we'd have to do this for quite a few other engines as well, which suffer under the same problem. Solution B: A more general solution would be to define a reset method in PricingEngine::arguments like the reset method we have in PricingEngine::results. The reset method in GenericEngine would then be void GenericEngine::reset() { results_.reset(); arguments_.reset(); } In addition we define void DividendBarrierOption::arguments::reset() { cashFlow.clear(); } void DividendVanillaOption::arguments::reset() { cashFlow.clear(); } Shall we then define a proper reset method for the other pricing arguments as well(?) Solution C: void GenericEngine::reset() { results_.reset(); arguments_ = ArgumentsType();} Even though it's a single line change to fix the problem I personally don't like it. regards Klaus On Tuesday, September 04, 2012 04:22:16 PM Sepp Imboden wrote: Dear all I have two newbie problems. I want to price a European D&I Put for an equity paying discrete dividends. For this purpose I took "QuantLib-1.2/test-suite/barrieroption.cpp" as a frame for my own piece of source (see bottom of this mail; "utilities.hpp" and "utilities.cpp" can be found in the dirctory "QuantLib-1.2/test-suite" of the QL source tree). IR, volatility and the underlying's spot are defined as "SimpleQuote", the barrier option is of type "DividendBarrierOption" (see line 88 of code below). 1. Problem ----------------- When running through the for-loop (line 121) I expected that changing the underlying's spot price (e.g. "spot -> setValue(123.4)", see line 124 of code below) would have an impact on calculated values of the barrier option ( e.g. "dividendBarrierOption.NPV()" ), but whenever I change the value of the underlying's spot, the calculated quantities remain unchanged. As I use the Pricing Engine "FdBlackScholesBarrierEngine", I realized that in the file "ql/pricingengines/barrier/fdblackscholesbarrierengine.cpp" the constructor "FdBlackScholesBarrierEngine" is not defined as an Observer of the "GeneralizedBlackScholesProcess", which is the first argumet of the constructor. Hence, I added a "registerWith(process_);" to the constructor "FdBlackScholesBarrierEngine" and the calculated quantities of my "dividendBarrierOption" became spot price sensitive. Is adding "registerWith(process_);" to the constructor a reliable/reasonable/good way to obtain values sensitive to the spot price??? If not, can you give me some hints? 2. Problem ------------------ After having "solved" (?) my above 1st problem, I added an additional option of type "BarrierOption" but without any dividends (see line 65 of code), and set its "PricingEngine" to the very same copy of the PricingEngine (see lines 98 & 99 of code). I then realized that QuantLib produces the very same NPV() etc. for the two options, ignoring that the one option is modeled with dividends while the other is modeled without dividends. When creating two independent copies of the same PricingEngine (see line 58 - 63) and relating them to the two options (i.e. replacing one of the two "fdEngine" in lines 98 & 99 by "engine"), things seem to be fine. Do I really have to have seperate pricing engines for the two barrier options? Many thanks & kind regards, Paul <-------------------------------------------------- Source Code --------------------------------------------------> #include "utilities.hpp" #include <ql/time/calendars/switzerland.hpp> #include <ql/time/daycounters/actual360.hpp> #include <ql/time/date.hpp> #include <ql/quotes/simplequote.hpp> #include <ql/exercise.hpp> #include <ql/processes/blackscholesprocess.hpp> #include <ql/pricingengines/barrier/analyticbarrierengine.hpp> #include <ql/pricingengines/barrier/mcbarrierengine.hpp> #include <ql/pricingengines/barrier/fdblackscholesbarrierengine.hpp> #include <ql/instruments/dividendbarrieroption.hpp> #include <iostream> #include <iomanip> int main(){ using namespace QuantLib; Calendar cal = Switzerland(); DayCounter dc = Actual360(); Date today = Date(30,Aug,2012); Date maturity = Date(20,Sep,2013); boost::shared_ptr<SimpleQuote> spot(new SimpleQuote(0.0)); boost::shared_ptr<SimpleQuote> qRate(new SimpleQuote(0.0)); boost::shared_ptr<YieldTermStructure> qTS = flatRate(today, qRate, dc); boost::shared_ptr<SimpleQuote> rRate(new SimpleQuote(0.0)); boost::shared_ptr<YieldTermStructure> rTS = flatRate(today, rRate, dc); boost::shared_ptr<SimpleQuote> vol(new SimpleQuote(0.0)); boost::shared_ptr<BlackVolTermStructure> volTS = flatVol(today, vol, dc); boost::shared_ptr<Exercise> exercise(new EuropeanExercise(maturity)); spot -> setValue(8.835); qRate -> setValue(0.0); rRate ->setValue(0.0024890168); vol ->setValue(0.27183378); boost::shared_ptr<StrikedTypePayoff> payoff( new PlainVanillaPayoff(Option::Put,8.75)); boost::shared_ptr<BlackScholesMertonProcess> stochProcess(new BlackScholesMertonProcess( Handle<Quote>(spot), Handle<YieldTermStructure>(qTS), Handle<YieldTermStructure>(rTS), Handle<BlackVolTermStructure>(volTS))); boost::shared_ptr<PricingEngine> engine( new FdBlackScholesBarrierEngine(stochProcess, 400, 800)); boost::shared_ptr<PricingEngine> fdEngine( new FdBlackScholesBarrierEngine(stochProcess, 400, 800)); BarrierOption barrierOption( Barrier::DownIn, 6.13, 0.0, payoff, exercise); std::vector<Date> dividendDates; std::vector<double> dividends; dividendDates.push_back(Date(14,Sep,2012)); dividends.push_back(0.24); dividendDates.push_back(Date(14,Dec,2012)); dividends.push_back(0.24); dividendDates.push_back(Date(14,Mar,2013)); dividends.push_back(0.24); dividendDates.push_back(Date(14,May,2013)); dividends.push_back(0.24); dividendDates.push_back(Date(14,Jul,2013)); dividends.push_back(0.24); dividendDates.push_back(Date(14,Sep,2013)); dividends.push_back(0.24); DividendBarrierOption dividendBarrierOption( Barrier::DownIn, 6.13, 0.0, payoff, exercise, dividendDates, dividends); barrierOption.setPricingEngine(fdEngine); dividendBarrierOption.setPricingEngine(fdEngine); Real pvBarrier,deltaBarrier,gammaBarrier; Real pvDividendBarrier,deltaDividendBarrier,gammaDividendBarrier; Size width[] = {10,18,18,18,18,18,18}; std::cout << std::setw(width[0]) << "Spot" << std::setw(width[1]) << "PV(no div.)" << std::setw(width[2]) << "PV(with div.)" << std::setw(width[3]) << "Delta(no div.)" << std::setw(width[4]) << "Delta(with div.)" << std::setw(width[5]) << "Gamma(no div.)" << std::setw(width[6]) << "Gamma(with div.)" << std::endl; for(int loop = 0;loop < 5;loop++) { Real loopS = 6.13+loop*0.1; spot->setValue(loopS); pvBarrier = barrierOption.NPV(); deltaBarrier = barrierOption.delta(); gammaBarrier = barrierOption.gamma(); pvDividendBarrier = dividendBarrierOption.NPV(); deltaDividendBarrier = dividendBarrierOption.delta(); gammaDividendBarrier = dividendBarrierOption.gamma(); std::cout << std::fixed; std::cout << std::setprecision(4); std::cout << std::setw(width[0]) << loopS << std::setw(width[1]) << pvBarrier << std::setw(width[2]) << pvDividendBarrier << std::setw(width[3]) << deltaBarrier << std::setw(width[4]) << deltaDividendBarrier << std::setw(width[5]) << gammaBarrier << std::setw(width[6]) << gammaDividendBarrier << std::endl; } return 0; } ------------------------------------------------------------------------------ Live Security Virtual Conference Exclusive live event will cover all the ways today's security and threat landscape has changed and how IT managers can respond. Discussions will include endpoint security, mobile security and the latest in malware threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/ _______________________________________________ QuantLib-users mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-users ------------------------------------------------------------------------------ Live Security Virtual Conference Exclusive live event will cover all the ways today's security and threat landscape has changed and how IT managers can respond. Discussions will include endpoint security, mobile security and the latest in malware threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/ _______________________________________________ QuantLib-users mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-users |
Free forum by Nabble | Edit this page |