1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 3 /* 4 Copyright (C) 2010 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/analyticeuropeanmargrabeengine.hpp> 21 #include <ql/math/distributions/normaldistribution.hpp> 22 #include <ql/instruments/payoffs.hpp> 23 #include <ql/exercise.hpp> 24 25 namespace QuantLib { 26 AnalyticEuropeanMargrabeEngine(const ext::shared_ptr<GeneralizedBlackScholesProcess> & process1,const ext::shared_ptr<GeneralizedBlackScholesProcess> & process2,Real correlation)27 AnalyticEuropeanMargrabeEngine::AnalyticEuropeanMargrabeEngine( 28 const ext::shared_ptr<GeneralizedBlackScholesProcess>& process1, 29 const ext::shared_ptr<GeneralizedBlackScholesProcess>& process2, 30 Real correlation) 31 : process1_(process1), process2_(process2), rho_(correlation) { 32 registerWith(process1_); 33 registerWith(process2_); 34 } 35 calculate() const36 void AnalyticEuropeanMargrabeEngine::calculate() const { 37 38 QL_REQUIRE(arguments_.exercise->type() == Exercise::European, 39 "not an European Option"); 40 41 ext::shared_ptr<EuropeanExercise> exercise = 42 ext::dynamic_pointer_cast<EuropeanExercise>(arguments_.exercise); 43 QL_REQUIRE(exercise, "not an European Option"); 44 45 ext::shared_ptr<NullPayoff> payoff = 46 ext::dynamic_pointer_cast<NullPayoff>(arguments_.payoff); 47 QL_REQUIRE(payoff, "non a Null Payoff type"); 48 49 Integer quantity1 = arguments_.Q1; 50 Integer quantity2 = arguments_.Q2; 51 52 Real s1 = process1_->stateVariable()->value(); 53 Real s2 = process2_->stateVariable()->value(); 54 55 Real variance1 = process1_->blackVolatility()->blackVariance( 56 exercise->lastDate(), s1); 57 Real variance2 = process2_->blackVolatility()->blackVariance( 58 exercise->lastDate(), s2); 59 60 DiscountFactor riskFreeDiscount = 61 process1_->riskFreeRate()->discount(exercise->lastDate()); 62 63 DiscountFactor dividendDiscount1 = 64 process1_->dividendYield()->discount(exercise->lastDate()); 65 DiscountFactor dividendDiscount2 = 66 process2_->dividendYield()->discount(exercise->lastDate()); 67 68 Real forward1 = process1_->stateVariable()->value() * 69 dividendDiscount1 / riskFreeDiscount; 70 Real forward2 = process2_->stateVariable()->value() * 71 dividendDiscount2 / riskFreeDiscount; 72 73 Real stdDev1 = std::sqrt(variance1); 74 Real stdDev2 = std::sqrt(variance2); 75 Real variance = variance1 + variance2 - 2*rho_*stdDev1*stdDev2; 76 Real stdDev = std::sqrt(variance); 77 Real d1 = (std::log((quantity1*forward1)/(quantity2*forward2)) 78 + 0.5*variance) / stdDev; 79 Real d2 = d1 - stdDev; 80 Real Nd1, Nd2, nd1, nd2; 81 CumulativeNormalDistribution cum; 82 NormalDistribution norm; 83 Nd1 = cum(d1); 84 Nd2 = cum(d2); 85 nd1 = norm(d1); 86 nd2 = norm(d2); 87 DayCounter rfdc = process1_->riskFreeRate()->dayCounter(); 88 Time t = rfdc.yearFraction(process1_->riskFreeRate()->referenceDate(), 89 arguments_.exercise->lastDate()); 90 Real sqt = std::sqrt(t); 91 Real q1 = -std::log(dividendDiscount1)/(sqt*sqt); 92 Real q2 = -std::log(dividendDiscount2)/(sqt*sqt); 93 94 results_.value = 95 riskFreeDiscount * (quantity1*forward1*Nd1 - quantity2*forward2*Nd2); 96 97 // Greeks 98 results_.delta1 = riskFreeDiscount*(quantity1*forward1*Nd1)/s1; 99 results_.delta2 = -riskFreeDiscount*(quantity2*forward2*Nd2)/s2; 100 results_.gamma1 = (riskFreeDiscount*(quantity1*forward1*nd1)/s1)/(quantity1*s1*stdDev); 101 results_.gamma2 = (-riskFreeDiscount*(quantity2*forward2*nd2)/s2)/(-quantity2*s2*stdDev); 102 Real vega = riskFreeDiscount*(quantity1*forward1*nd1)*sqt; 103 results_.theta = -((stdDev*vega/sqt)/(2*t)-(q1*quantity1*s1*results_.delta1)-(q2*quantity2*s2*results_.delta2)); 104 results_.rho = 0.0; 105 } 106 107 } 108