1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 3 /* 4 Copyright (C) 2012 Master IMAFA - Polytech'Nice Sophia - Université de Nice Sophia Antipolis 5 6 This file is part of QuantLib, a free-software/open-source library 7 for financial quantitative analysts and developers - http://quantlib.org/ 8 9 QuantLib is free software: you can redistribute it and/or modify it 10 under the terms of the QuantLib license. You should have received a 11 copy of the license along with this program; if not, please email 12 <quantlib-dev@lists.sf.net>. The license is also available online at 13 <http://quantlib.org/license.shtml>. 14 15 This program is distributed in the hope that it will be useful, but WITHOUT 16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 FOR A PARTICULAR PURPOSE. See the license for more details. 18 */ 19 20 #include <ql/experimental/exoticoptions/analytictwoassetbarrierengine.hpp> 21 #include <ql/exercise.hpp> 22 #include <ql/math/distributions/normaldistribution.hpp> 23 #include <ql/math/distributions/bivariatenormaldistribution.hpp> 24 25 namespace QuantLib { 26 AnalyticTwoAssetBarrierEngine(const ext::shared_ptr<GeneralizedBlackScholesProcess> & process1,const ext::shared_ptr<GeneralizedBlackScholesProcess> & process2,const Handle<Quote> & rho)27 AnalyticTwoAssetBarrierEngine::AnalyticTwoAssetBarrierEngine( 28 const ext::shared_ptr<GeneralizedBlackScholesProcess>& process1, 29 const ext::shared_ptr<GeneralizedBlackScholesProcess>& process2, 30 const Handle<Quote>& rho) 31 : process1_(process1), process2_(process2), rho_(rho) { 32 registerWith(process1_); 33 registerWith(process2_); 34 registerWith(rho_); 35 } 36 calculate() const37 void AnalyticTwoAssetBarrierEngine::calculate() const { 38 ext::shared_ptr<PlainVanillaPayoff> payoff = 39 ext::dynamic_pointer_cast<PlainVanillaPayoff>(arguments_.payoff); 40 QL_REQUIRE(payoff, "non-plain payoff given"); 41 QL_REQUIRE(payoff->strike()>0.0,"strike must be positive"); 42 43 Real spot2 = process2_->x0(); 44 // option is triggered by S2 45 QL_REQUIRE(spot2 >= 0.0, "negative or null underlying given"); 46 QL_REQUIRE(!triggered(spot2), "barrier touched"); 47 48 Barrier::Type barrierType = arguments_.barrierType; 49 50 switch (payoff->optionType()) { 51 case Option::Call: 52 switch (barrierType) { 53 case Barrier::DownOut: 54 results_.value = A(1,-1) +B(1,-1) ; 55 break; 56 case Barrier::UpOut: 57 results_.value = A(1,1) + B(1,1) ; 58 break; 59 case Barrier::DownIn: 60 results_.value = call()-(A(1,-1) +B(1,-1) ); 61 break; 62 case Barrier::UpIn: 63 results_.value = call()-(A(1,1) +B(1,1)); 64 break; 65 } 66 break; 67 case Option::Put: 68 switch (barrierType) { 69 case Barrier::DownOut: 70 results_.value = A(-1,-1)+B(-1,-1) ; 71 break; 72 case Barrier::UpOut: 73 results_.value = A(-1,1)+B(-1,1) ; 74 break; 75 case Barrier::DownIn: 76 results_.value = put()-(A(-1,-1) +B(-1,-1) ); 77 break; 78 case Barrier::UpIn: 79 results_.value = put()-(A(-1,1) +B(-1,1) ); 80 break; 81 } 82 break; 83 default: 84 QL_FAIL("unknown type"); 85 } 86 } 87 underlying1() const88 Real AnalyticTwoAssetBarrierEngine::underlying1() const { 89 return process1_->x0(); 90 } 91 underlying2() const92 Real AnalyticTwoAssetBarrierEngine::underlying2() const { 93 return process2_->x0(); 94 } 95 strike() const96 Real AnalyticTwoAssetBarrierEngine::strike() const { 97 ext::shared_ptr<PlainVanillaPayoff> payoff = 98 ext::dynamic_pointer_cast<PlainVanillaPayoff>(arguments_.payoff); 99 QL_REQUIRE(payoff, "non-plain payoff given"); 100 return payoff->strike(); 101 } 102 residualTime() const103 Time AnalyticTwoAssetBarrierEngine::residualTime() const { 104 return process1_->time(arguments_.exercise->lastDate()); 105 } 106 volatility1() const107 Volatility AnalyticTwoAssetBarrierEngine::volatility1() const { 108 return process1_->blackVolatility()->blackVol(residualTime(), strike()); 109 } 110 volatility2() const111 Volatility AnalyticTwoAssetBarrierEngine::volatility2() const { 112 return process2_->blackVolatility()->blackVol(residualTime(), strike()); 113 } 114 barrier() const115 Real AnalyticTwoAssetBarrierEngine::barrier() const { 116 return arguments_.barrier; 117 } 118 rho() const119 Real AnalyticTwoAssetBarrierEngine::rho() const { 120 return rho_->value(); 121 } 122 riskFreeRate() const123 Rate AnalyticTwoAssetBarrierEngine::riskFreeRate() const { 124 return process1_->riskFreeRate()->zeroRate(residualTime(), 125 Continuous, NoFrequency); 126 } 127 128 dividendYield1() const129 Rate AnalyticTwoAssetBarrierEngine::dividendYield1() const { 130 return process1_->dividendYield()->zeroRate(residualTime(), 131 Continuous, NoFrequency); 132 } 133 dividendYield2() const134 Rate AnalyticTwoAssetBarrierEngine::dividendYield2() const { 135 return process2_->dividendYield()->zeroRate(residualTime(), 136 Continuous, NoFrequency); 137 } 138 costOfCarry1() const139 Rate AnalyticTwoAssetBarrierEngine::costOfCarry1() const { 140 return riskFreeRate() - dividendYield1(); 141 } 142 costOfCarry2() const143 Rate AnalyticTwoAssetBarrierEngine::costOfCarry2() const { 144 return riskFreeRate() - dividendYield2(); 145 } 146 d1() const147 Real AnalyticTwoAssetBarrierEngine::d1() const { 148 return (std::log(underlying1()/strike())+(mu(costOfCarry1(),volatility1())+volatility1()*volatility1())*residualTime())/ 149 (volatility1()*std::sqrt(residualTime())); 150 } 151 d2() const152 Real AnalyticTwoAssetBarrierEngine::d2() const { 153 return d1() - volatility1()*std::sqrt(residualTime()); 154 } 155 d3() const156 Real AnalyticTwoAssetBarrierEngine::d3() const { 157 return d1()+ (2*rho()*std::log(barrier()/underlying2()))/(volatility2()*std::sqrt(residualTime())); 158 } 159 d4() const160 Real AnalyticTwoAssetBarrierEngine::d4() const { 161 return d2()+ (2*rho()*std::log(barrier()/underlying2()))/(volatility2()*std::sqrt(residualTime())); 162 } 163 e1() const164 Real AnalyticTwoAssetBarrierEngine::e1() const { 165 return (std::log(barrier()/underlying2())-(mu(costOfCarry2(),volatility2())+rho()*volatility1()*volatility2())*residualTime())/ 166 (volatility2()*std::sqrt(residualTime())); 167 } 168 e2() const169 Real AnalyticTwoAssetBarrierEngine::e2() const { 170 return e1()+rho()*volatility1()*std::sqrt(residualTime()); 171 } 172 e3() const173 Real AnalyticTwoAssetBarrierEngine::e3() const { 174 return e1()-(2*std::log(barrier()/underlying2()))/(volatility2()*std::sqrt(residualTime())); 175 } 176 e4() const177 Real AnalyticTwoAssetBarrierEngine::e4() const { 178 return e2()-(2*std::log(barrier()/underlying2()))/(volatility2()*std::sqrt(residualTime())); 179 } 180 mu(Real b,Real vol) const181 Real AnalyticTwoAssetBarrierEngine::mu(Real b, Real vol) const { 182 return b-(vol*vol)/2; 183 } 184 call() const185 Real AnalyticTwoAssetBarrierEngine::call() const { 186 CumulativeNormalDistribution nd; 187 return underlying1()*nd(d1())-strike()*std::exp(-riskFreeRate()*residualTime())*nd(d2()); 188 } 189 put() const190 Real AnalyticTwoAssetBarrierEngine::put() const { 191 CumulativeNormalDistribution nd; 192 return strike()*std::exp(-riskFreeRate()*residualTime())*nd(-d2())-underlying1()*nd(-d1()); 193 } 194 A(Real eta,Real phi) const195 Real AnalyticTwoAssetBarrierEngine::A(Real eta, Real phi) const { 196 Real S1 = underlying1(), S2 = underlying2(); 197 Rate b1 = costOfCarry1(), b2 = costOfCarry2(); 198 Rate r = riskFreeRate(); 199 Time T = residualTime(); 200 Real H = barrier(), X = strike(); 201 Volatility sigma1 = volatility1(), sigma2 = volatility2(); 202 Real rho = rho_->value(); 203 204 Rate mu1 = b1 - sigma1*sigma1/2.0; 205 Rate mu2 = b2 - sigma2*sigma2/2.0; 206 207 Real d1 = (std::log(S1/X)+(mu1+sigma1*sigma1)*T)/ 208 (sigma1*std::sqrt(T)); 209 Real d2 = d1 - sigma1*std::sqrt(T); 210 Real d3 = d1 + (2*rho*std::log(H/S2))/(sigma2*std::sqrt(T)); 211 Real d4 = d2 + (2*rho*std::log(H/S2))/(sigma2*std::sqrt(T)); 212 213 Real e1 = (std::log(H/S2)-(mu2+rho*sigma1*sigma2)*T)/ 214 (sigma2*std::sqrt(T)); 215 Real e2 = e1 + rho*sigma1*std::sqrt(T); 216 Real e3 = e1 - (2*std::log(H/S2))/(sigma2*std::sqrt(T)); 217 Real e4 = e2 - (2*std::log(H/S2))/(sigma2*std::sqrt(T)); 218 219 Real w = 220 eta*S1*std::exp((b1-r)*T) * 221 (M(eta*d1, phi*e1,-eta*phi*rho) 222 -std::exp((2*(mu2+rho*sigma1*sigma2)*std::log(H/S2))/(sigma2*sigma2)) 223 *M(eta*d3, phi*e3, -eta*phi*rho)) 224 225 - eta*X*std::exp(-r*T) * 226 (M(eta*d2, phi*e2, -eta*phi*rho) 227 -std::exp((2*mu2*std::log(H/S2))/(sigma2*sigma2))* 228 M(eta*d4, phi*e4, -eta*phi*rho) ) ; 229 230 return w; 231 } 232 B(Real,Real) const233 Real AnalyticTwoAssetBarrierEngine::B(Real, Real) const { 234 return 0.0; 235 } 236 M(Real m_a,Real m_b,Real rho) const237 Real AnalyticTwoAssetBarrierEngine::M(Real m_a, Real m_b, Real rho) const { 238 BivariateCumulativeNormalDistributionDr78 f(rho); 239 return f(m_a, m_b); 240 } 241 242 } 243 244