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