• No se han encontrado resultados

Índice de la varianza extraída (IVE) para nivel individual

3.5. FIABILIDAD Y VALIDEZ DEL INSTRUMENTO DE MEDIDA

3.5.3. Í NDICE DE LA VARIANZA EXTRAÍDA (IVE)

3.5.3.2. Índice de la varianza extraída (IVE) para nivel individual

The first stage in implementation is to briefly discuss the Black-Scholes analytic solution for the price of a vanilla call or put option. Consider the price of a European Vanilla Call, C(S, t). S is the underlying asset price, K is the strike price, r is the interest rate (or the “risk-free rate”), T is the time to maturity and σ is the (constant) volatility of the underlying asset S. N is a function which will be described in detail below. The analytical formula for C(S, t) is given by:

C(S, t) = SN (d1) − Ke−rTN (d2)

With d1 and d2 defined as follows:

d1 = log(S/K) + (r +σ22)T σ√T d2 = d1− σ √ T 123

Making use of put-call parity, we can also price a European vanilla put, P (S, t), with the following formula:

P (S, t) = Ke−rT − S + C(S, t) = Ke−rT − S + (SN (d1) − Ke−rTN (d2))

All that remains is to describe the function N , which is the cumulative distribution function of the standard normal distribution. The formula for N is given by:

N (x) = √1 2π

Z x

−∞

e−t2/2dt

It would also help to have closed form solutions for the “Greeks”. These are the sensitivities of the option price to the various underlying parameters. They will be calculated in the next chapter. However, in order to calculate these sensitivities we need the formula for the probability density function of the standard normal distribution which is given below:

f (x) =√1 2πe

−x2/2

10.2

C++ Implementation

This code will not consist of any object oriented or generic programming techniques at this stage. Right now the goal is to help you understand a basic C++ implementation of a pricing engine, without all of the additional object machinery to encapsulate away the mathematical functions. I’ve written out the program in full and then below I’ll explain how each component works subsequently:

#define USE MATH DEFINES

#include <i o s t r e a m >

#include <cmath>

// S t a n d a r d normal p r o b a b i l i t y d e n s i t y f u n c t i o n

double norm pdf (const double& x ) {

125

}

// An a p p r o x i m a t i o n t o t h e c u m u l a t i v e d i s t r i b u t i o n f u n c t i o n // f o r t h e s t a n d a r d normal d i s t r i b u t i o n

// Note : T h i s i s a r e c u r s i v e f u n c t i o n

double n o r m c d f (const double& x ) {

double k = 1 . 0 / ( 1 . 0 + 0 . 2 3 1 6 4 1 9 ∗ x ) ;

double k sum = k ∗ ( 0 . 3 1 9 3 8 1 5 3 0 + k ∗ ( − 0 . 3 5 6 5 6 3 7 8 2 + k ∗ ( 1 . 7 8 1 4 7 7 9 3 7 + k ∗ ( − 1 . 8 2 1 2 5 5 9 7 8 + 1 . 3 3 0 2 7 4 4 2 9 ∗ k ) ) ) ) ;

i f ( x >= 0 . 0 ) {

return ( 1 . 0 − ( 1 . 0 / ( pow ( 2 ∗ M PI , 0 . 5 ) ) ) ∗ exp ( −0.5∗ x∗x ) ∗ k sum ) ; } e l s e { return 1 . 0 − n o r m c d f (−x ) ; } } // T h i s c a l c u l a t e s d j , f o r j i n { 1 , 2 } . T h i s term a p p e a r s i n t h e c l o s e d // form s o l u t i o n f o r t h e European c a l l o r p u t p r i c e

double d j (const i n t& j , const double& S , const double& K, const double& r ,

const double& v , const double& T) {

return ( l o g ( S/K) + ( r + ( pow( −1 , j −1) ) ∗ 0 . 5 ∗ v∗v ) ∗T) / ( v ∗ ( pow (T , 0 . 5 ) ) ) ; }

// C a l c u l a t e t h e European v a n i l l a c a l l p r i c e b a s e d on // u n d e r l y i n g S , s t r i k e K, r i s k −f r e e r a t e r , v o l a t i l i t y o f // u n d e r l y i n g sigma and t i m e t o m a t u r i t y T

double c a l l p r i c e (const double& S , const double& K, const double& r ,

const double& v , const double& T) {

return S ∗ n o r m c d f ( d j ( 1 , S , K, r , v , T) )−K∗ exp(− r ∗T) ∗ n o r m c d f ( d j ( 2 , S , K, r , v , T) ) ; } // C a l c u l a t e t h e European v a n i l l a p u t p r i c e b a s e d on // u n d e r l y i n g S , s t r i k e K, r i s k −f r e e r a t e r , v o l a t i l i t y o f // u n d e r l y i n g sigma and t i m e t o m a t u r i t y T

const double& v , const double& T) { return −S∗ n o r m c d f (− d j ( 1 , S , K, r , v , T) )+K∗ exp(− r ∗T) ∗ n o r m c d f (− d j ( 2 , S , K, r , v , T) ) ; } i n t main (i n t a r g c , char ∗∗ a r g v ) { // F i r s t we c r e a t e t h e p a r a m e t e r l i s t double S = 1 0 0 . 0 ; // O p t i o n p r i c e double K = 1 0 0 . 0 ; // S t r i k e p r i c e double r = 0 . 0 5 ; // Risk−f r e e r a t e (5%) double v = 0 . 2 ; // V o l a t i l i t y o f t h e u n d e r l y i n g (20%) double T = 1 . 0 ; // One y e a r u n t i l e x p i r y // Then we c a l c u l a t e t h e c a l l / p u t v a l u e s double c a l l = c a l l p r i c e ( S , K, r , v , T) ; double put = p u t p r i c e ( S , K, r , v , T) ; // F i n a l l y we o u t p u t t h e p a r a m e t e r s and p r i c e s s t d : : c o u t << ” U n d e r l y i n g : ” << S << s t d : : e n d l ; s t d : : c o u t << ” S t r i k e : ” << K << s t d : : e n d l ; s t d : : c o u t << ” Risk−F r e e Rate : ” << r << s t d : : e n d l ; s t d : : c o u t << ” V o l a t i l i t y : ” << v << s t d : : e n d l ; s t d : : c o u t << ” M a t u r i t y : ” << T << s t d : : e n d l ; s t d : : c o u t << ” C a l l P r i c e : ” << c a l l << s t d : : e n d l ; s t d : : c o u t << ” Put P r i c e : ” << put << s t d : : e n d l ; return 0 ; }

Let’s now take a look at the program step-by-step.

The first line is a pre-processor macro which tells the C++ compiler to make use of the C-standard mathematical constants. Note that some compilers may not fully support these constants. Make sure you test them out first!

127

The next section imports theiostreamandcmathlibraries. This allows us to use thestd :: cout

command to output code. In addition we now have access to the C mathematical functions such asexp,pow, logand sqrt:

#include <i o s t r e a m >

#include <cmath>

Once we have the correct libraries imported we need to create the core statistics functions which make up most of the computation for the prices. Here is the standard normal probability density function. M PIis the C-standard mathematical constant for π:

// S t a n d a r d normal p r o b a b i l i t y d e n s i t y f u n c t i o n

double norm pdf (const double& x ) {

return ( 1 . 0 / ( pow ( 2 ∗ M PI , 0 . 5 ) ) ) ∗ exp ( −0.5∗ x∗x ) ; }

The next statistics function is the approximation to the cumulative distribution function for the standard normal distribution. This approximation is found in Joshi. Note that this is a recursive function (i.e. it calls itself!):

// An a p p r o x i m a t i o n t o t h e c u m u l a t i v e d i s t r i b u t i o n f u n c t i o n // f o r t h e s t a n d a r d normal d i s t r i b u t i o n

// Note : T h i s i s a r e c u r s i v e f u n c t i o n

double n o r m c d f (const double& x ) {

double k = 1 . 0 / ( 1 . 0 + 0 . 2 3 1 6 4 1 9 ∗ x ) ;

double k sum = k ∗ ( 0 . 3 1 9 3 8 1 5 3 0 + k ∗ ( − 0 . 3 5 6 5 6 3 7 8 2 + k ∗ ( 1 . 7 8 1 4 7 7 9 3 7 + k ∗ ( − 1 . 8 2 1 2 5 5 9 7 8 + 1 . 3 3 0 2 7 4 4 2 9 ∗ k ) ) ) ) ;

i f ( x >= 0 . 0 ) {

return ( 1 . 0 − ( 1 . 0 / ( pow ( 2 ∗ M PI , 0 . 5 ) ) ) ∗ exp ( −0.5∗ x∗x ) ∗ k sum ) ; } e l s e {

return 1 . 0 − n o r m c d f (−x ) ; }

}

The last remaining set of functions are directly related to the pricing of European vanilla calls and puts. We need to calculate the dj values first, otherwise we would be repeating ourselves by

adding the function code directly to each of call price and put price:

// T h i s c a l c u l a t e s d j , f o r j i n { 1 , 2 } . T h i s term a p p e a r s i n t h e c l o s e d // form s o l u t i o n f o r t h e European c a l l o r p u t p r i c e

double d j (const i n t& j , const double& S , const double& K, const double& r ,

const double& v , const double& T) {

return ( l o g ( S/K) + ( r + ( pow( −1 , j −1) ) ∗ 0 . 5 ∗ v∗v ) ∗T) / ( v ∗ ( pow (T , 0 . 5 ) ) ) ; }

Now that we have the cumulative distribution function for the standard normal distribution (norm cdf) coded up, as well as the dj function, we can calculate the closed-form solution for the

European vanilla call price. You can see that it is a fairly simple formula, assuming that the aforementioned functions have already been implemented:

// C a l c u l a t e t h e European v a n i l l a c a l l p r i c e b a s e d on // u n d e r l y i n g S , s t r i k e K, r i s k −f r e e r a t e r , v o l a t i l i t y o f // u n d e r l y i n g sigma and t i m e t o m a t u r i t y T

double c a l l p r i c e (const double& S , const double& K, const double& r ,

const double& v , const double& T) {

return S ∗ n o r m c d f ( d j ( 1 , S , K, r , v , T) )−K∗ exp(− r ∗T) ∗ n o r m c d f ( d j ( 2 , S , K, r , v , T) ) ;

}

And similarly for the vanilla put (this formula can be derived easily via put-call parity):

// C a l c u l a t e t h e European v a n i l l a p u t p r i c e b a s e d on // u n d e r l y i n g S , s t r i k e K, r i s k −f r e e r a t e r , v o l a t i l i t y o f // u n d e r l y i n g sigma and t i m e t o m a t u r i t y T

double p u t p r i c e (const double& S , const double& K, const double& r ,

const double& v , const double& T) {

return −S∗ n o r m c d f (− d j ( 1 , S , K, r , v , T) )+K∗ exp(− r ∗T) ∗ n o r m c d f (− d j ( 2 , S , K, r , v , T) ) ;

}

Every C++ program must have amainprogram. This is where the functions described above are actually called and the values derived are output to the console. We make use of theiostream

library to provide us with the std :: cout and std :: endl output handlers. Finally, we exit the program: i n t main (i n t a r g c , char ∗∗ a r g v ) { // F i r s t we c r e a t e t h e p a r a m e t e r l i s t double S = 1 0 0 . 0 ; // O p t i o n p r i c e double K = 1 0 0 . 0 ; // S t r i k e p r i c e double r = 0 . 0 5 ; // Risk−f r e e r a t e (5%)

129 double v = 0 . 2 ; // V o l a t i l i t y o f t h e u n d e r l y i n g (20%) double T = 1 . 0 ; // One y e a r u n t i l e x p i r y // Then we c a l c u l a t e t h e c a l l / p u t v a l u e s double c a l l = c a l l p r i c e ( S , K, r , v , T) ; double put = p u t p r i c e ( S , K, r , v , T) ; // F i n a l l y we o u t p u t t h e p a r a m e t e r s and p r i c e s s t d : : c o u t << ” U n d e r l y i n g : ” << S << s t d : : e n d l ; s t d : : c o u t << ” S t r i k e : ” << K << s t d : : e n d l ; s t d : : c o u t << ” Risk−F r e e Rate : ” << r << s t d : : e n d l ; s t d : : c o u t << ” V o l a t i l i t y : ” << v << s t d : : e n d l ; s t d : : c o u t << ” M a t u r i t y : ” << T << s t d : : e n d l ; s t d : : c o u t << ” C a l l P r i c e : ” << c a l l << s t d : : e n d l ; s t d : : c o u t << ” Put P r i c e : ” << put << s t d : : e n d l ; return 0 ; }

The output of the code on my Mac OSX system is as follows:

U n d e r l y i n g : 100 S t r i k e : 100 Risk−F r e e Rate : 0 . 0 5 V o l a t i l i t y : 0 . 2 M a t u r i t y : 1 C a l l P r i c e : 1 0 . 4 5 0 6 Put P r i c e : 5 . 5 7 3 5 2

This code should give you a good idea of how closed form solutions to the Black-Scholes equations can be coded up in a procedural manner with C++. The next steps are to calculate the “Greeks” in the same vein, as closed form solutions exist, solutions for digital and power options, as well as a basic Monte Carlo pricer with which to validate against.

We have now shown how to price a European option with analytic solutions. We were able to take the closed-form solution of the Black-Scholes equation for a European vanilla call or put and provide a price.

This is possible because the boundary conditions generated by the pay-off function of the European vanilla option allow us to easily calculate a closed-form solution. Many option pay-off functions lead to boundary conditions which are much harder to solve analytically and some are impossible to solve this way. Thus in these situations we need to rely on numerical approximation. We will now price the same European vanilla option with a very basic Monte Carlo solver in C++ and then compare our numerical values to the analytical case. We won’t be concentrating on an extremely efficient or optimised implementation at this stage. Right now I just want to show you how to get up and running to give you an understanding of how risk neutral pricing works numerically. We will also see how our values differ from those generated analytically.