QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
stulzengine.cpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2004 Ferdinando Ametrano
5 Copyright (C) 2004 Neil Firth
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/math/distributions/bivariatenormaldistribution.hpp>
24#include <ql/math/distributions/normaldistribution.hpp>
25#include <ql/pricingengines/basket/stulzengine.hpp>
26#include <ql/pricingengines/blackcalculator.hpp>
27#include <ql/pricingengines/blackformula.hpp>
28#include <utility>
29
30namespace QuantLib {
31
32 namespace {
33
34 // calculate the value of euro min basket call
35 Real euroTwoAssetMinBasketCall(Real forward1, Real forward2,
36 Real strike,
37 DiscountFactor riskFreeDiscount,
38 Real variance1, Real variance2,
39 Real rho) {
40
41 Real stdDev1 = std::sqrt(variance1);
42 Real stdDev2 = std::sqrt(variance2);
43
44 Real variance = variance1 + variance2 - 2*rho*stdDev1*stdDev2;
45 Real stdDev = std::sqrt(variance);
46
47 Real modRho1 = (rho * stdDev2 - stdDev1) / stdDev;
48 Real modRho2 = (rho * stdDev1 - stdDev2) / stdDev;
49
50 Real D1 = (std::log(forward1/forward2) + 0.5*variance) / stdDev;
51
52 Real alfa, beta, gamma;
53 if (strike != 0.0) {
60
61 Real D1_1 =
62 (std::log(forward1/strike) + 0.5*variance1) / stdDev1;
63 Real D1_2 =
64 (std::log(forward2/strike) + 0.5*variance2) / stdDev2;
65 alfa = bivCNormMod1(D1_1, -D1);
66 beta = bivCNormMod2(D1_2, D1 - stdDev);
67 gamma = bivCNorm(D1_1 - stdDev1, D1_2 - stdDev2);
68 } else {
69 CumulativeNormalDistribution cum;
70 alfa = cum(-D1);
71 beta = cum(D1 - stdDev);
72 gamma = 1.0;
73 }
74
75 return riskFreeDiscount *
76 (forward1*alfa + forward2*beta - strike*gamma);
77
78 }
79
80 // calculate the value of euro max basket call
81 Real euroTwoAssetMaxBasketCall(Real forward1, Real forward2,
82 Real strike,
83 DiscountFactor riskFreeDiscount,
84 Real variance1, Real variance2,
85 Real rho) {
86
87 ext::shared_ptr<StrikedTypePayoff> payoff(new
88 PlainVanillaPayoff(Option::Call, strike));
89
90 Real black1 = blackFormula(payoff->optionType(), payoff->strike(),
91 forward1, std::sqrt(variance1)) * riskFreeDiscount;
92
93 Real black2 = blackFormula(payoff->optionType(), payoff->strike(),
94 forward2, std::sqrt(variance2)) * riskFreeDiscount;
95
96 return black1 + black2 -
97 euroTwoAssetMinBasketCall(forward1, forward2, strike,
98 riskFreeDiscount,
99 variance1, variance2, rho);
100 }
101 }
102
103 StulzEngine::StulzEngine(ext::shared_ptr<GeneralizedBlackScholesProcess> process1,
104 ext::shared_ptr<GeneralizedBlackScholesProcess> process2,
105 Real correlation)
106 : process1_(std::move(process1)), process2_(std::move(process2)), rho_(correlation) {
109 }
110
112
113 QL_REQUIRE(arguments_.exercise->type() == Exercise::European,
114 "not an European Option");
115
116 ext::shared_ptr<EuropeanExercise> exercise =
117 ext::dynamic_pointer_cast<EuropeanExercise>(arguments_.exercise);
118 QL_REQUIRE(exercise, "not an European Option");
119
120 ext::shared_ptr<BasketPayoff> basket_payoff =
121 ext::dynamic_pointer_cast<BasketPayoff>(arguments_.payoff);
122
123 ext::shared_ptr<MinBasketPayoff> min_basket =
124 ext::dynamic_pointer_cast<MinBasketPayoff>(arguments_.payoff);
125
126 ext::shared_ptr<MaxBasketPayoff> max_basket =
127 ext::dynamic_pointer_cast<MaxBasketPayoff>(arguments_.payoff);
128 QL_REQUIRE(min_basket || max_basket, "unknown basket type");
129
130 ext::shared_ptr<PlainVanillaPayoff> payoff =
131 ext::dynamic_pointer_cast<PlainVanillaPayoff>(basket_payoff->basePayoff());
132 QL_REQUIRE(payoff, "non-plain payoff given");
133
134 Real strike = payoff->strike();
135
136 Real variance1 = process1_->blackVolatility()->blackVariance(
137 exercise->lastDate(), strike);
138 Real variance2 = process2_->blackVolatility()->blackVariance(
139 exercise->lastDate(), strike);
140
141 DiscountFactor riskFreeDiscount =
142 process1_->riskFreeRate()->discount(exercise->lastDate());
143
144 // cannot handle non zero dividends, so don't believe this...
145 DiscountFactor dividendDiscount1 =
146 process1_->dividendYield()->discount(exercise->lastDate());
147 DiscountFactor dividendDiscount2 =
148 process2_->dividendYield()->discount(exercise->lastDate());
149
150 Real forward1 = process1_->stateVariable()->value() *
151 dividendDiscount1 / riskFreeDiscount;
152 Real forward2 = process2_->stateVariable()->value() *
153 dividendDiscount2 / riskFreeDiscount;
154
155 if (max_basket != nullptr) {
156 switch (payoff->optionType()) {
157 // euro call on a two asset max basket
158 case Option::Call:
160 euroTwoAssetMaxBasketCall(forward1, forward2, strike,
161 riskFreeDiscount,
162 variance1, variance2,
163 rho_);
164
165 break;
166 // euro put on a two asset max basket
167 case Option::Put:
168 results_.value = strike * riskFreeDiscount -
169 euroTwoAssetMaxBasketCall(forward1, forward2, 0.0,
170 riskFreeDiscount,
171 variance1, variance2, rho_) +
172 euroTwoAssetMaxBasketCall(forward1, forward2, strike,
173 riskFreeDiscount,
174 variance1, variance2, rho_);
175 break;
176 default:
177 QL_FAIL("unknown option type");
178 }
179 } else if (min_basket != nullptr) {
180 switch (payoff->optionType()) {
181 // euro call on a two asset min basket
182 case Option::Call:
184 euroTwoAssetMinBasketCall(forward1, forward2, strike,
185 riskFreeDiscount,
186 variance1, variance2,
187 rho_);
188 break;
189 // euro put on a two asset min basket
190 case Option::Put:
191 results_.value = strike * riskFreeDiscount -
192 euroTwoAssetMinBasketCall(forward1, forward2, 0.0,
193 riskFreeDiscount,
194 variance1, variance2, rho_) +
195 euroTwoAssetMinBasketCall(forward1, forward2, strike,
196 riskFreeDiscount,
197 variance1, variance2, rho_);
198 break;
199 default:
200 QL_FAIL("unknown option type");
201 }
202 } else {
203 QL_FAIL("unknown type");
204 }
205 }
206
207}
208
std::pair< iterator, bool > registerWith(const ext::shared_ptr< Observable > &)
Definition: observable.hpp:228
ext::shared_ptr< Exercise > exercise
Definition: option.hpp:65
ext::shared_ptr< Payoff > payoff
Definition: option.hpp:64
ext::shared_ptr< GeneralizedBlackScholesProcess > process2_
Definition: stulzengine.hpp:53
ext::shared_ptr< GeneralizedBlackScholesProcess > process1_
Definition: stulzengine.hpp:52
StulzEngine(ext::shared_ptr< GeneralizedBlackScholesProcess > process1, ext::shared_ptr< GeneralizedBlackScholesProcess > process2, Real correlation)
void calculate() const override
QL_REAL Real
real number
Definition: types.hpp:50
Real DiscountFactor
discount factor between dates
Definition: types.hpp:66
Definition: any.hpp:35
BivariateCumulativeNormalDistributionWe04DP BivariateCumulativeNormalDistribution
default bivariate implementation
Real blackFormula(Option::Type optionType, Real strike, Real forward, Real stdDev, Real discount, Real displacement)
STL namespace.