How to find new trading strategy ideas and objectively assess them for your portfolio using a custom-built backtesting engine in Python. How to implement advanced trading strategies using time series analysis, machine learning and Bayesian statistics with R and Python. By QuantStart Team. The Mathematical Fundamentals Nowadays there is a comprehensive literature available for financial engineering. For those of you who are unfamiliar with financial markets or the derivative products within them, the best place to start is with John Hull's Options, Futures, and Other Derivatives.
This is not a highly mathematical treatment of the subject, instead it concentrates on the different markets and products such as futures, options, swaps and other interest rate derivatives. I would suggest reading all of the chapters in this book, eventually, but only concurrently with a more mathematical text.
Familiarise yourself with the chapters on futures markets, options markets, binomial trees, Wiener processes and the Black-Scholes-Merton model. Later on you can read about the "Greeks" and volatility. Hull is a great "bedtime" or "commuter" read, but you'll need something more mathematically-oriented to really get to grips with the options pricing material. Next up is Mark Joshi's The Concepts and Practice of Mathematical Finance , which is pitched at 3rd year undergraduate mathematics level. You will need to read and fully understand Chapters Chapter 6, on Risk Neutrality, is probably the most challenging at this stage.
You will then have a good grasp of how options are priced both in theory and in practice. Chapters concentrate on exotic or early-exercise options. As a desk quant you will need to be aware of these concepts too and they provide insight into how the theory of Chapters is applied. The remainder of the book concentrates on interest rate derivatives as well as more advanced models for asset price paths. I would suggest learning the basics extremely well, before beginning these chapters.
Chapter 3 in particular covers risk neutral pricing at a good level. The remainder of the book concentrates on interest rates and more advanced models. I will emphasise again - make sure you understand the basics extremely well, particularly the Black-Scholes model, different types of options and pricing techniques as well as practical pricing methods such as Monte Carlo and how it works. Research Preparation For some of you, getting a job in the financial industry is not the goal - you might want to pursue research in certain topics, either at PhD level or as a post-doctoral student, potentially coming from industry.
Advanced Mathematical Finance Advanced mathematical finance really comes down to learning more about stochastic calculus and risk neutral pricing. Mark Joshi's recent More Mathematical Finance essentially continues where his other book finishes. Early parts of the book concentrate on the theory and practical pricing of credit derivatives. Later on, deeper Monte Carlo and other pricing methods are discussed.
If your research area is likely to involve practical implementation, this is a great book to get hold of. For deeper explorations of stochastic calculus, it is worth picking up Brownian Motion and Stochastic Calculus by Karatzas and Shreve as well as Stochastic Differential Equations by Oksendal. Both books delve deeply into their respective areas and are required reading for anyone beginning research into stochastic analysis.
Master reading list for Quants, MFE (Financial Engineering) students
For the modelling of interest rates and term structure, Brigo's book Interest Rate Models - Theory and Practice will provide the necessary groundwork to begin reading Filipovic's Term-Structure Models. The book is almost a requirement for quant analyst interviews today as it contains many "gotchas" that can easily show whether you've been spending any time with the language!
A new feature here is that an option with a particular payo such as a put can be either of European or American type. Similarly, Call and possibly more classes for other payos will also be inheriting from both the EurOption and AmOption classes, as in Figure 3. The code to capture this structure follows below. Listing 3. Similar for the Call class. The Snell envelope procedure 3. In addition to vectors, the STL contains many other useful predefined data structures.
Component i of the vector is referred to by Price[i] in the code, similar to using an array of type double. It is arguably a design flaw since one variable should be sucient. In Section 3. The pricing of both European and American options is now easily accomplished in main. PriceBySnell Model. It is redundant to have two copies of the same number. The expiry date is a common feature shared by all options. Similar remarks apply to the function SetN and the virtual function Payoff.
It would be much more sensible to have a single copy of each of these functions shared between the EurOption and AmOption classes rather than two copies owned separately by each of these two classes. How do we achieve this? We create a new class, and call it the Option class, to contain the common features shared by all options such as the expiry date and a payo function. Then we change the EurOption and AmOption classes to become subclasses of the Option class, so they will inherit these features. This is what happens in the next version of the code.
Let us analyse the changes. The variable N, function SetN and virtual function Payoff are moved into this class. These classes no longer explicitly contain N, SetN or Payoff , but inherit these members from the Option class. There is a new feature here that must be explained: the role of the keyword virtual in this context. This brings us to the topic of virtual inheritance. Let us temporarily remove the keyword virtual, so the above line becomes class EurOption: public Option. When Optopn Depending on the compiler, it may read something like this: reference to Set N is ambiguous.
The reason for the error message is this. Without virtual inheritance with the keyword virtual removed the EurOption and AmOption classes inherit their own distinct copies of N from the Option class. In turn, the Call class inherits two distinct copies of N, one via the EurOption class and one via the AmOption class. Similar comments apply to the Put class. This situation is illustrated in Figure 3. The Option class appears twice in this diagram to indicate that two distinct copies of its members are created in the subclasses. When virtual inheritance applies that is, the keyword virtual is reinstated , the code compiles and runs without a complaint.
In this case a single copy of N and indeed of any other member of the Option class is shared between the subclasses EurOption and AmOption. It is this single shared copy of N that is then inherited by the Call class as well as by the Put class. Virtual inheritance is illustrated in Figure 3. The Option class appears once in this diagram, indicating that a single copy of each of its members is shared by the subclasses. A new function int GetN is included in the Option class. Since N is a private member of the Option class, this public function is needed to access N from the subclasses.
There is no change to Main We would like to compute and store the price of an American option not only at time 0, but also for each time step n and node i in the binoial tree.
Numerical methods in finance with C++ | Reading lists @ LSE
In addition, we want to compute the early exercise policy for an American option. We are going to encode this information as data of type bool, taking just two possible values, 0 if the option should not be exercised at a given node, or 1 otherwise, depending on whether the above condition is violated or not. We wrap this vector of vectors in a class called BinLattice, and provide related functionality such as setting the number of time steps N or setting and retrieving a value at time n and node i.
In this function some output formatting features such as fixed decimal point notation are used with cout. The entire code for the BinLattice class can be found in the header file BinLattice This breaks with our custom of placing the definitions of more complicated functions such as Display in a. The reason is that the BinLattice class is going to be converted into a class template, which does not lend itself to separate compilation. To record the stopping policy, it would be easy enough to write a separate class for data of type bool by following the pattern of the BinLattice class.
However, we do not want the headache of several duplicate code fragments to maintain. Class templates oer a much neater solution. The type is not hardwired inside the class, but passed to it as a parameter. We achieve this by modifying the BinLattice class as follows. Note that the keyword class can be used instead of typename. Every occurrence of double is replaced by Type. In particular: 2. There is no. A class template can only be compiled after an object has been declared using the template with a specific data type, for example double, substituted for the type parameter, and we have not done so yet.
Separate compilation will not work for them. RiskNeutProb ;. SetN N ; StoppingTree. SetNode N,i,Payoff Model. S N,i ; StoppingTree. GetR ; PriceTree. SetNode n,i,Payoff Model.
S n,i ; StoppingTree. The following changes have been made in the PriceBySnell function from Listings 3. We want the values computed and placed at the nodes to remain available after the function terminates. American options ing 3. The size of the PriceTree and StoppingTree is determined by the number of steps to expiry for the option. New lines of code are added within the body of PriceBySnell to set the appropriate values of bool type in the StoppingTree lattice.
Finally, in main we compute and display the price tree and stopping policy tree for an American put. Exercise 3. For details, see [DMFM]. One of several possible approximation schemes is the following. Develop code to compute the approximate price for an American put option in the BlackScholes model by means of this binomial tree approximation. Their setup is similar to class templates as illustrated by Exercise 3.
In Section 4. Test this function template, using it to interchange the contents of variables of various types. Implied volatility Bisection method NewtonRaphson method Function pointers Virtual functions Function templates Computing implied volatility Remarks on templates. In finance we frequently encounter the need to compute numerical solutions to non-linear equations.
Typical examples include computing implied volatility see Sections 4. There are several well-known numerical methods for solving non-linear equations. The simplest of these are the bisection method and the NewtonRaphson method. We are going to develop three implementations of these methods: by means of function pointers, virtual functions and function templates, comparing their advantages and disadvantages. Two of these programming approaches, namely function pointers and virtual functions, we have used before, and this is an opportunity to rehearse them more thoroughly.
Using function templates in place of function pointers or virtual functions is a new technique, elegant and computationally ecient, which we are going to learn in this chapter. For details, see [BSM]. If the values of S 0 , K, T, , r are all known, then 4. Among these variables, T and K are known quantities written into the option contract.
Quotes for the current stock price S 0 and interest rate r are also readily available. However, the volatility is not, and needs to be estimated from market data. One popular way of estimating is to look up the market price C quote quoted for some European call option and then to solve the non-linear equation 4. The solution , called implied volatility, can then be used to price and hedge options of other kinds. It is assumed that f is continuous on [a, b] and f a c, f b c have opposite signs.
We construct a sequence xn as follows: Take x0 a, b. Listing 4. The function SolveByBisect is defined to implement the bisection method. It takes a function pointer Fct as an argument, so a function f can be passed to the solver. In addition, SolveByBisect takes arguments Tgt for the target value c of the function, LEnd and REnd for the left and right endpoints of the interval [a, b], and Acc for the desired accuracy of the numerical solution, which will determine when the algorithm should be stopped.
Care is taken in SolveByBisect that only one evaluation of f is made for each loop iteration in order to speed up computation. The price is worth paying because the bisection method is not lightning fast. Checking whether or not f a c, f b c have opposite signs to begin with is omitted in SolveByBisect for simplicity.
It takes two function pointers Fct and DFct so that both a function f and its derivative f can be passed. In this case the algorithm will be terminated after the prescribed accuracy is reached. In other circumstances SolveByNR may enter an infinite loop. This ought to be prevented, for example by setting an upper limit on the number of iterations, but it is not, for simplicity. Function pointers are simple enough, but limit the possibilities for expansion. When solving 4. An abstract class called Function is introduced to represent a general function f. The class has two pure virtual member functions: Value to return the value of f at x, and Deriv to return the value of the derivative f at x.
We need to. DFct, the function pointer passed to SolveByNR in the previous version to compute the derivative is no longer needed. Deriv is now a member of the Function class, and both Value and Deriv can be accessed through the pointer Fct to this class. It should be used when a function that is a member of a class is called with a pointer to an object of that class or a subclass. Some concrete functions can now be introduced as subclasses of the Function class, and then the solvers called to do their business. Class F1, a subclass of the Function class, corresponds to the old function F1 in the previous version.
Note that an object MyF1 of class F1 is created as part of the definition of the class. This is just to illustrate this possibility. Alternatively, we could remove MyF1 preceding the closing semicolon at the end of the definition of class F1, and include a separate line F1 MyF1;. Class F2 is also a subclass of the Function class. An object MyF2 of class F2 is created as part of the definition of the class, with a initiated with the value 3.
This is needed for the virtual functions to work inside the solvers. When the virtual functions Value or Deriv are called with this pointer, they do their checking at run time and select the correct version to be executed. However, there is a price to pay to have type checking performed at run time. Because it occurs inside a loop, it will happen repeatedly, possibly creating noticeable computing time overheads. It is not a significant issue here because the loops go through a few iterations only for the prescribed accuracy.
Try to figure out how many! But it is not hard to imagine a situation, perhaps involving multiple nested loops with millions of iterations, when it would pay to work harder to improve eciency. Templates oer a technique that largely retains the advantages of virtual functions over function pointers, but shifts type checking from run time to compile time.
In some cases of heavy numerical computations this could mean measurable runtime savings for the end user.
There is never a free lunch, and templates come with their own set of problems. These will be pointed out later, once we have examined the code. Gone with it are the pure virtual functions. It is remarkable how few changes are necessary to templatise the code. Arguably, things have been simplified given that the abstract class and virtual functions have disappeared, and no inheritance is involved. If more functions were involved, each with its own class, there would be even more versions of SolveByBisect and SolveByNR in the compiled code. This can result in long compile times and large.
It may or may not be a price worth paying for gains in the speed of computation at run time. Because we no longer work with virtual functions, using pointers is unnecessary. This will be done in Exercise 4. Exercise 4. Using Solver Rewrite the code for option pricing in Options First of all, we implement a class representing a European call option in the BlackScholes model, complete with a function for computing the option price by means of the BlackScholes formula 4.
This requires, in particular, computing the distribution function N x for the normal distribution N 0, 1. The distribution function is given by 4. To compute the implied volatility using the NewtonRaphson solver, we also need an expression for the derivative of the European call option price with respect to volatility. This derivative, called vega, is given by 2. The EurCall class contains the variables T, K characterising the call option and a constructor function to initialise these variables. There is no need for this class to contain the payo function, which is not going to be used explicitly in this context.
The distribution function N x is computed using the rational function approximation 4. Here we see the values of the constants and a1 , a2 , a3 , a4 , a5 in 4. We are going to use the templatised solvers from Listing 4. To this end we need to create a class containing functions Value and Deriv connected, respectively, to the functions for the option price and vega in the EurCall class.
This is done and then used to compute the impled volatility in the next piece of code. The subclass Intermediary of the EurCall class is in charge of this job. The constructor function of the Intermediary class calls the constructor of the EurCall class to initiate T, K, and then initiates S0, r. An object Call of the Intermediary class is declared and the parameters of this object are initiated. One diculty with templates is that they are prone to programming bugs and can be harder to debug than code without templates, producing mystifying compiler errors.
On the other hand, templates capturing some generic data structures and tasks can save a huge amount of coding, reducing the scope for errors and improving readability. When using templates, proceed with caution: Carefully consider alternative techniques, balancing the pros and cons. First write a specific version with no templates and with typical data types in place of template parameters.
Test and debug the code thoroughly before templatising it. We followed this procedure when developing the templates in Sections 3. When documenting templates, take care to specify any restrictions on the object types that can be substituted for template parameters. For example, only classes that have public member functions Value and Deriv consistent with the prototypes double Value double x ; double Deriv double x ;. Use templates for relatively small generic tasks and structures that are likely to be recycled in several dierent contexts. Larger or more specific tasks might be better o without templates, except perhaps for running time considerations when relevant.
For example, a template for a pair or for a sequence of objects is very likely to be re-used many times. A template for a solver is likely to be used with many dierent function types. An option payo might. On the other hand, a full-scale option pricer would seem an unlikely candidate for templatising, as it would be too large and too specific. Path-dependent options Valuation Pricing error Greek parameters Variance reduction Path-dependent basket options.
Consider a game of heads and tails. We suspect that the coin is not symmetric, and want to investigate how this influences the game. A simple solution would be to toss the coin many times, and to compute the average of the outcomes. This way we can estimate the expected outcome of the game. Such computation of expectation is the underlying idea behind Monte Carlo methods.
We also consider a risky asset. A typical example of a path-dependent option is the arithmetic Asian call, where the payo function is given by. In the majority of cases, including the arithmetic Asian call, such expectation cannot be computed analytically. Below we shall show how the expectation can be computed using Monte Carlo. From 5. Let Z1 ,. By the law of large numbers EQ h S t1 ,. This means that for suciently large N, by 5.
Sample paths can be generated on a computer. This makes 5. We now give a theorem that will allow us to generate a random number with distribution N 0, 1. Theorem 5. For the proof of the theorem see [PF]. We can use Theorem 5. Using 5.
This is important, since in 5. Here is an example of code which implements this recipe. Listing 5. A SamplePath is a vector of numbers of type double. By declaring SamplePath through typedef, from now on we can use SamplePath as any other standard type, for example, by declaring SamplePath S;. The class stores the parameters S 0 , r,. Here we declare all parameters as public in order to streamline the code and save space. These variables should be declared as private and introduced together with the corresponding public access functions.
In this chapter we are going to cut many such corners in order to keep the code as short and transparent as possible. A computer can never generate a truly random number. The job of generating pseudo-random numbers is done by the rand function. The command srand time NULL ;. It is customary to use current time as the seed. We should not set the seed each time rand is executed. This could spoil independence between samples. In our program we make sure that srand time NULL ;.
It is worthwhile to know that we can also choose a fixed seed. For example, for any constant integer a, if we write. This is often helpful when comparing results or debugging. GenerateSamplePath generates a sample path using 5. Here we intentionally pass S by reference in order not to create a new instance of S each time the function is called. Since the function will be executed many times, this will help to speed up our program. Making pi a constant speeds up computations, since it will not have to be computed each time we call Gauss.
Gauss generates Z using 5. Now we write out the code for pricing path-dependent options using 5. We show how to price an arithmetic Asian call with payo function 5. It computes the price of an option using 5. We declare N as long since the number of sample paths needed for accurate computations could exceed the range of int.
Payoff is a virtual function. The class ArithmAsianCall is used to price arithmetic Asian calls. The Payoff function for this class is computed using 5. This is important since passing by reference speeds up computations.
Calling Option. Exercise 5. In this section we discuss how to estimate the size of such an error. This means that N converges to zero as we increase N, but this convergence is slow. For example 1. N, 10 which means that to reduce the error by one decimal point we need to make about times more simulations.
Below we modify our code from Listings 5. We add Price and PricingError as members of the class. After executing Option. We compute H and Hsq simultaneously. Using the same S for H and Hsq speeds up computations and improves accuracy. There is no need to modify BSModel We can add a new file, Main In this section we compute the Greek parameters using the Monte Carlo approach.
We show how to compute the delta, leaving other parameters as exercises. Note that we use the same sample path S for the computation of the price, pricing error and. This is important since it speeds up computations and improves accuracy. By adding a new file, Main If Y is close to X, then the error of such computation should be small. We refer to Y as a control variate for X. This method allows us to reduce the error of computation without increasing the number of simulations.
The idea behind the choice of Y as a control variate follows from the fact that by Taylors expansion of cos z , for small z, cos z 1 12 z2. Let us explain how to find the price of a path-dependent option with a payo function h : Rm R, using some other option as a control variate. Suppose that we have an option with a payo function g : Rm R, which is close to h. In the following version of the code the PathDepOption class from Listing 5.
This is the pricing function in which we compute H 0 using 5. CVOption plays the role of control variate. Options that can be used as control variates need to have an analytic pricing formula. Here we add a function in which we compute G 0 from the BlackScholes formula. We make this function virtual, since the formula may vary depending on the type of option. Not all path-dependent options can be priced analytically. Here we return 0.
The keyword this requires careful explanation. When an object of some class is used, then this appearing anywhere inside that class designates a pointer to that object. Here the pointer this appears inside the PathDepOption class or more precisely, inside a function belonging to that class. Later on, inside the main function in Listing 5. When Option. We compute H 0 using 5. By calling VarRedOpt.
Then G 0 is computed in CVOption. PriceByBSFormula from an analytic formula. To apply this code we still need to choose a control variate and implement its PriceByBSFormula function. As an example for the variance reduction technique, we are going to price an arithmetic Asian call option with payo function 5. Since the geometric average is often close to the arithmetic average, this choice seems a good idea, provided that we know how to compute G 0 analytically.
The York Research Database
The formula for C a, K, T, b, r is given in 4. We are now ready to present the code for pricing the geometric Asian call 5. This option will play the role of control variate when pricing arithmetic Asian calls. We are ready to price the arithmetic Asian call, using the geometric Asian call as control variate. Option is the arithmetic Asian call which we are going to price, and CVOption is the control variate.
We price Option using the variance reduction technique, with control variate CVOption. We also price Option using the standard Monte Carlo method and display the error for comparison. Note that the error has been reduced without increasing N. Control variates can be used to compute the Greeks. We demonstrate how this can be done by using as an example. Compute using 5. The price of the control variate can be computed using the fact that c2. We write. The prices have the following dynamics under the risk-neutral probability:. In other words, Z1 ,.
Below we implement 5. We start by setting up functions which will be used to handle matrix and vector operations. We declare various operators on vectors and matrices. We pass variables by reference to speed up computations. The keyword const is used to ensure that the operators do not make any alterations to the variables passed to them. The result of multiplying a vector V by a matrix C is a vector. Here we have three very natural operators, which will allow us to multiply a vector by a number, add a number to a vector, and add two vectors. All operators declared in Matrix. We omit the details for some of them in order not to fill up space with trivial code.
The code can be found on the accompanying web page: www.
We now present the code which uses 5. Thanks to the various operators that have been defined, the code is compact and strongly resembles Listings 5. Since our model can have more than one asset, a sample path will consists of a sequence of vectors. Based on these, all other parameters of the model can be computed.
This function generates a sample of a d-dimensional random variable with normal distribution N 0, I. Here we use 5. We now clearly see the benefits of using the various operators. Thanks to them GenerateSamplePath is just as short as the function used for the BlackScholes model with a single underlying asset. Below we present code for pricing an arithmetic Asian basket call option with payo 5. To keep the code as simple as possible we focus on option pricing and leave error estimation and computation of Greek parameters as exercises.
The code form Listing 5. The only dierence is that we include BSModel Here we compute the arithmetic average from 5. We initialise an object Option for an arithmetic Asian basket call option, and execute the pricing function. Error estimation for basket options can be done using 5. We can use identical code to that in Listing 5.
Of course we need to change include "PathDepOption We finish the chapter by discussing how to compute the Greeks for a basket option. We demonstrate this by means of an example, showing how to compute the s corresponding to the underlying assets. Be sure to use the same samples while computing 1 ,. Parabolic partial dierential equations Explicit method Implicit schemes Changing coordinates American options Proofs.
We refer to f as the terminal boundary condition, to fl as the lower boundary condition and to fu as the upper boundary condition. A typical reason for studying 6. Let S t denote the price at time t of the underlying asset under the BlackScholes model. Suppose that at time t the price of a financial For more details see [BSM].
Equation 6. We write u t, z for a solution to the BlackScholes equation 6. We also write h z , hl t , hu t for the boundary conditions for 6. The lower and upper boundary conditions depend on the type of the option we wish to price. They can usually be derived from heuristic or arbitrage arguments. For example, for a put option with expiry date T and strike price K, if S t is high, then the option is practically worthless since it is unlikely to be exercised. If S t is close to zero, then we can assume that we are almost certain to exercise the put at expiry and obtain a payo close to K.
Exercise 6. Before discussing how to solve equation 6. As an example we consider the European put under the BlackScholes model, leaving other options as exercises.