| 1 | /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
| 2 | |
| 3 | /* |
| 4 | Copyright (C) 2003 Neil Firth |
| 5 | Copyright (C) 2003 Ferdinando Ametrano |
| 6 | Copyright (C) 2007 StatPro Italia srl |
| 7 | |
| 8 | This file is part of QuantLib, a free-software/open-source library |
| 9 | for financial quantitative analysts and developers - http://quantlib.org/ |
| 10 | |
| 11 | QuantLib is free software: you can redistribute it and/or modify it |
| 12 | under the terms of the QuantLib license. You should have received a |
| 13 | copy of the license along with this program; if not, please email |
| 14 | <quantlib-dev@lists.sf.net>. The license is also available online at |
| 15 | <http://quantlib.org/license.shtml>. |
| 16 | |
| 17 | This program is distributed in the hope that it will be useful, but WITHOUT |
| 18 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 19 | FOR A PARTICULAR PURPOSE. See the license for more details. |
| 20 | */ |
| 21 | |
| 22 | #include <ql/exercise.hpp> |
| 23 | #include <ql/instruments/barrieroption.hpp> |
| 24 | #include <ql/instruments/dividendbarrieroption.hpp> |
| 25 | #include <ql/instruments/impliedvolatility.hpp> |
| 26 | #include <ql/pricingengines/barrier/analyticbarrierengine.hpp> |
| 27 | #include <ql/pricingengines/barrier/fdblackscholesbarrierengine.hpp> |
| 28 | #include <memory> |
| 29 | |
| 30 | namespace QuantLib { |
| 31 | |
| 32 | BarrierOption::BarrierOption( |
| 33 | Barrier::Type barrierType, |
| 34 | Real barrier, |
| 35 | Real rebate, |
| 36 | const ext::shared_ptr<StrikedTypePayoff>& payoff, |
| 37 | const ext::shared_ptr<Exercise>& exercise) |
| 38 | : OneAssetOption(payoff, exercise), |
| 39 | barrierType_(barrierType), barrier_(barrier), rebate_(rebate) {} |
| 40 | |
| 41 | void BarrierOption::setupArguments(PricingEngine::arguments* args) const { |
| 42 | |
| 43 | OneAssetOption::setupArguments(args); |
| 44 | |
| 45 | auto* moreArgs = dynamic_cast<BarrierOption::arguments*>(args); |
| 46 | QL_REQUIRE(moreArgs != nullptr, "wrong argument type" ); |
| 47 | moreArgs->barrierType = barrierType_; |
| 48 | moreArgs->barrier = barrier_; |
| 49 | moreArgs->rebate = rebate_; |
| 50 | |
| 51 | /* this is a workaround in case an engine is used for both barrier |
| 52 | and dividend options. The dividends might have been set by another |
| 53 | instrument and need to be cleared. */ |
| 54 | QL_DEPRECATED_DISABLE_WARNING |
| 55 | auto* arguments = dynamic_cast<DividendBarrierOption::arguments*>(args); |
| 56 | if (arguments != nullptr) { |
| 57 | arguments->cashFlow.clear(); |
| 58 | } |
| 59 | QL_DEPRECATED_ENABLE_WARNING |
| 60 | } |
| 61 | |
| 62 | |
| 63 | Volatility BarrierOption::impliedVolatility( |
| 64 | Real targetValue, |
| 65 | const ext::shared_ptr<GeneralizedBlackScholesProcess>& process, |
| 66 | Real accuracy, |
| 67 | Size maxEvaluations, |
| 68 | Volatility minVol, |
| 69 | Volatility maxVol) const { |
| 70 | return impliedVolatility(price: targetValue, process, dividends: DividendSchedule(), |
| 71 | accuracy, maxEvaluations, minVol, maxVol); |
| 72 | } |
| 73 | |
| 74 | Volatility BarrierOption::impliedVolatility( |
| 75 | Real targetValue, |
| 76 | const ext::shared_ptr<GeneralizedBlackScholesProcess>& process, |
| 77 | const DividendSchedule& dividends, |
| 78 | Real accuracy, |
| 79 | Size maxEvaluations, |
| 80 | Volatility minVol, |
| 81 | Volatility maxVol) const { |
| 82 | QL_REQUIRE(!isExpired(), "option expired" ); |
| 83 | |
| 84 | ext::shared_ptr<SimpleQuote> volQuote(new SimpleQuote); |
| 85 | |
| 86 | ext::shared_ptr<GeneralizedBlackScholesProcess> newProcess = |
| 87 | detail::ImpliedVolatilityHelper::clone(process, volQuote); |
| 88 | |
| 89 | // engines are built-in for the time being |
| 90 | std::unique_ptr<PricingEngine> engine; |
| 91 | switch (exercise_->type()) { |
| 92 | case Exercise::European: |
| 93 | if (dividends.empty()) |
| 94 | engine = std::make_unique<AnalyticBarrierEngine>(args&: newProcess); |
| 95 | else |
| 96 | engine = std::make_unique<FdBlackScholesBarrierEngine>(args&: newProcess, args: dividends); |
| 97 | break; |
| 98 | case Exercise::American: |
| 99 | case Exercise::Bermudan: |
| 100 | QL_FAIL("engine not available for non-European barrier option" ); |
| 101 | break; |
| 102 | default: |
| 103 | QL_FAIL("unknown exercise type" ); |
| 104 | } |
| 105 | |
| 106 | return detail::ImpliedVolatilityHelper::calculate(instrument: *this, |
| 107 | engine: *engine, |
| 108 | volQuote&: *volQuote, |
| 109 | targetValue, |
| 110 | accuracy, |
| 111 | maxEvaluations, |
| 112 | minVol, maxVol); |
| 113 | } |
| 114 | |
| 115 | |
| 116 | BarrierOption::arguments::arguments() |
| 117 | : barrierType(Barrier::Type(-1)), barrier(Null<Real>()), |
| 118 | rebate(Null<Real>()) {} |
| 119 | |
| 120 | void BarrierOption::arguments::validate() const { |
| 121 | OneAssetOption::arguments::validate(); |
| 122 | |
| 123 | switch (barrierType) { |
| 124 | case Barrier::DownIn: |
| 125 | case Barrier::UpIn: |
| 126 | case Barrier::DownOut: |
| 127 | case Barrier::UpOut: |
| 128 | break; |
| 129 | default: |
| 130 | QL_FAIL("unknown type" ); |
| 131 | } |
| 132 | |
| 133 | QL_REQUIRE(barrier != Null<Real>(), "no barrier given" ); |
| 134 | QL_REQUIRE(rebate != Null<Real>(), "no rebate given" ); |
| 135 | } |
| 136 | |
| 137 | bool BarrierOption::engine::triggered(Real underlying) const { |
| 138 | switch (arguments_.barrierType) { |
| 139 | case Barrier::DownIn: |
| 140 | case Barrier::DownOut: |
| 141 | return underlying < arguments_.barrier; |
| 142 | case Barrier::UpIn: |
| 143 | case Barrier::UpOut: |
| 144 | return underlying > arguments_.barrier; |
| 145 | default: |
| 146 | QL_FAIL("unknown type" ); |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | } |
| 151 | |
| 152 | |