Applied Financial Research Project Quantitative Analysis: Jump-diffusion valuation of variance swaps Name: Evdokiya D. Ignatova CID: 00656435 25th August 2011 Name: Evdokiya Ignatova 1 CID: 00656435
Client Specification The client is an investment bank which trades variance swap derivative products with investors. After the recent financial crisis the bank is re-evaluating their variance swap pricing models. They are interested to compare how accurately vanilla diffusion models versus jump-diffusion models forecast the realised variance. As a quant researcher my goal is to implement and compare Black-Scholes model to Merton Jump-Diffusion model in forecasting realised variance. In order to evaluate how accurately each model forecasts the realised variance, a number of graphs were created which demonstrated how well each model performed during calm and turbulent market periods. Finally, a number of statistics were calculated on the variance swap premium to measure the error in the forecasts. Name: Evdokiya Ignatova 2 CID: 00656435
Contents 1. Introduction ......................................................................................................................................... 4 2. Variance Swap pricing models ............................................................................................................. 5 Black-Scholes Model ...................................................................................................................... 6 Merton Jump-Diffusion Model ....................................................................................................... 7 3. Implementation.................................................................................................................................... 8 Technical Implementation ............................................................................................................. 8 Calibration ...................................................................................................................................... 9 Measuring the Error ..................................................................................................................... 10 4. Results ................................................................................................................................................ 10 5. Conclusion .......................................................................................................................................... 13 6. References .......................................................................................................................................... 14 7. Code ................................................................................................................................................... 15 C++ Code ...................................................................................................................................... 15 Python Code ................................................................................................................................. 18 Name: Evdokiya Ignatova 3 CID: 00656435
1. Introduction A variance swap is an over-the-counter product, which allows investors to obtain pure exposure to volatility in the market. It is a forward contract on the realised volatility of an underlying asset. Typical underliers include equity indices, single stocks, exchange rates, interest rates and commodities. Variance swaps also enable investors to take positions in correlation and dispersion trades as well as correlation swaps. Volatility as an asset class has a number of characteristics, which are attractive to investors. In uncertain markets, volatility is negatively correlated to traditional asset classes such as equity. Therefore volatility products can be added to hedge the risk of a downward shift in market. Additionally, volatility is mean-reverting, which allows investors to express a view on future levels of uncertainty in the market and trade the volatility spread. Traditionally, investors have traded volatility through delta-neutral option strategies. For example one technique is to take a long position in at-the-money straddle, which is a portfolio of at-the-money put and call options. However this approach has one major drawback and that is the options’ payoff is not purely dependent on the volatility in the market but also on the direction of the stock price movements and the passage of time (Bossu, 2005). Hence variance and volatility swaps emerged from the demand for pure exposure to the volatility of an asset. While volatility swaps may be more appealing, since their payoff is linear to the volatility of the underlying asset, these contracts are also difficult to price and hedge. Hence many investors focus on variance swaps, whose payoff can be replicated by a portfolio of put and call options weighted by the inverse of the square of their strike (Demeterfi et al 1999). A vanilla variance swap contract starting at time and expiring at time where , has payoff at expiry: ( ) (1) where N is the notional amount of the contract in dollars, is the realised variance of the asset price for the duration of the contract and is the fixed variance strike (the price of the swap contract), which is agreed upon by the two counterparties when entering the swap contract. At expiry the buyer of the swap would receive the difference between the realised variance and the fixed variance strike scaled by the pre-agreed notional. The realised variance is calculated as the Name: Evdokiya Ignatova 4 CID: 00656435
annualised average of the daily squared log return of the underlying asset from inception of the contract at time to expiry at time Naturally, before entering into a variance swap contract, both the investor and the dealer would want to know what the fair variance strike is. This study demonstrates how to calculate the fair variance strike using the risk-neutral expectation of the realised variance of an equity index. The fair variance strike was presented in terms of the annualised volatility of the index. Assuming the index price moves discontinuously and exhibits jumps for the duration of the variance swap contract, two stochastic models were compared, the Black-Scholes model and the Merton Jump-Diffusion model. The focus of this study was finding out how well each model forecasted the variance of the equity index in order to find the fair variance strike. This was achieved through implementing the two models and using them to forecast the daily annualised volatility. Secondly, the realised volatility was calculated and each model was compared to it. In order to measure how well the two models forecasted the annualised volatility a number of techniques were used. The daily forecasts from both models were calculated and plotted together with the actual realised volatility of the index using data for the last fourteen year. This was done for several variance swap maturities. Next, a number of statistical indicators were calculated in order to measure the magnitude of the error between the forecasted and the realised values. Finally, the models’ forecasts were compared across different market conditions: calm versus turbulent market. The report is presented in the following order: section 2 describes in detail the two asset price models and the pricing formula for a variance swap contract, section 3 discusses how the models were implemented, calibrated and how the models were evaluated, while section 4 presents the results of the study and section 5 discusses further areas of research and improvement. 2. Variance Swap pricing models To price a variance swap, it is necessary to find the fair variance strike such that the value of the contract at initiation is equal to zero. The strike is usually quoted in terms of the annualised volatility. The fair discrete variance strike is derived from the definition of a swap contract as illustrated by Demeterfi et al (1999): ( ) (2) where the present value of the swap is the risk neutral expectation of the discounted payoff at expiry of the swap contract. At inception the present value of the swap has to be equal to zero: Name: Evdokiya Ignatova 5 CID: 00656435
( ) (3) Hence, the fair variance strike can be computed from the risk-neutral expectation of the discrete realised variance: (4) The discretely sampled realised variance is traditionally calculated by looking at the annualised second moment of the log return of the asset for the duration of the contract. Let is a partition of the time interval [0,T], with equal segments with size , such that for and let be the asset price at the th sampling time for . Then the daily log-return is calculated as: ( ) (5) Therefore the discretely sampled realised variance is defined as: ∑ ( ) (6) w here is the annualization factor. It is important to notice that the above definition differs from the usual sample variance definition since the mean of the returns is not subtracted. This is the case because of the assumption in the model that the mean of the returns is close to zero and hence has little impact on the variance of the returns (for detailed proof see Bossu (2005)). This assumption is the main reason why the variance swap payoff is additive. Black-Scholes Model In order to find the expected realised variance, we need to make assumptions about the behaviour of the stock price. If we assume the stock price moves continuously with the following risk neutral dynamics: (7) where is the risk free rate, is the constant volatility and is the standard Brownian motion under the unique risk neutral measure . Applying Ito’s Lemma on ( ) Name: Evdokiya Ignatova 6 CID: 00656435
( ) ( ) ( )( ) (8) Substituting for , ( ) ( (9) ) ( ) Simplifying and expressing ( ) ( ) ( ) ( ) (10) Using the Euler scheme discretization of the above equation where and √ , where Z is a standard normal random variable: ( ) ( ( ) )( ) √ (11) Using the above definition of the stock price, a Monte Carlo simulation is performed to compute the realised variance, which is the average of the realised variance along each simulated price path. Merton Jump-Diffusion Model The Merton Jump-Diffusion model (Merton, 1975) is the proposed alternative for pricing of variance swap. This stochastic model differs from the Black-Scholes model by the addition of discontinuous jumps to the continuous diffusive part. Therefore the asset price has the following risk neutral dynamics under the unique risk neutral measure Q. ( ) (12) where is the stock price, right before a jump, is a jump process which satisfies the following equation: ∑( ) (13) where is a log-normal random variable with distribution ( ) and it represents the relative jump size in the asset price and is a Poisson process with constant jump intensity rate . Assuming is independent of and The average size of the asset price jump is represented by the parameter m, . Name: Evdokiya Ignatova 7 CID: 00656435
(14) Let ( ) ( ), then using Ito’s Lemma: ( ) (15) Using Euler scheme approximation of the above equation, where and √ , where Z is a standard normal random variable: ( )( ) √ ∑ ( ) (16) Since is a log-normal random variable with distribution ( ), the summation term can be also expressed as: ∑ ( ) √ (17) Also the parameters are related by the following equation, so only one side needs to be defined: ( ) (18) The process of computing the realised variance is exactly the same with the exception that the simulated price path is done using the new Euler approximation. It is important to notice that when the intensity . The jump-diffusion price path converges to the one of the Black-Scholes model. 3. Implementation Technical Implementation The two variance swap pricing models were implemented in C++. Using a Monte Carlo simulation technique, the fair variance strike was calculated as the average of the realised variances from the simulated price path. All price paths were generated using equation (16), since the Merton Jump-Diffusion model is an extension of the Black-Scholes model. Therefore when the jump intensity parameter was set to zero the vanilla Black-Scholes model was used and when different from zero the Merton Jump-Diffusion model was active. To ensure fast convergence of the algorithm, antithetic variance reduction techniques (Joshi, 2008) were used. To simulate the Brownian increments through normally distributed random variables, the Marsaglia Polar method (Joshi, 2008) was used. Name: Evdokiya Ignatova 8 CID: 00656435
The Poisson random variables were generated through the inverse transformation technique (Glasserman, 2004). The fair variance strike from each price path was calculated using equation (6) and presented as annualised volatility. Additionally, a suite of Python scripts were implemented to automate the calculations of the forecasted and realised variances from a data set spanning across fourteen years. It was also used to calibrate the jump-parameters, generate statistics, plot the results and measure the error between the forecasted and the realised variance. Calibration The two pricing models were compared on data for the S&P 500 equity index. All the historical data used in this study was taken from Wharton Research Data Services (WRDS). The two models share a number of parameters that had to be defined before running the Monte Carlo simulation, such as the risk-free rate, the dividend yield, the historical index prices and the initial stock volatility. The risk-free rate was taken from the zero-coupon term structure which was provided by WRDS. The historical index prices and the dividend yield were also taken from the same source. In order have a forward looking estimate of the initial stock volatility for the two models, as suggested by Demeterfi et al (1999), at-the-money implied volatilities were used from call options. The at-the-money implied volatility term structure for the S&P 500 index options was taken from WRDS. The Merton Jump-Diffusion Model required additional parameters such as intensity, mean and standard deviation of the jumps. These were calibrated through a sampling algorithm, which minimizes the root mean squared error between the Merton Jump-Diffusion forecasted variance and the historical variance similar to the technique described by Tankov & Voltchkova (2006). From initial comparison the Black-Scholes model to the realised variance, as illustrated in figures one and two, it was discovered that using implied volatility as the initial stock volatility parameter results into forecasted variance which captures the overall shape of the realised variance, but it also overestimates it. Hence adding the discontinuous jumps resulted into even higher over-estimation of the variance. To rectify this issue, a scaling parameter was introduced for Merton Jump-Diffusion model, which was applied on the initial stock volatility. This parameter allowed the jump-diffusion model to still make use of the implied volatilities, but it also ensured that the forecasted variance was within an acceptable range. Name: Evdokiya Ignatova 9 CID: 00656435
Measuring the Error To evaluate how accurately the two models predict the fair variance strike, it was important to measure the error between each model’s forecasted variance and the actual realised variance. It is important to notice that this error is also known as the variance risk premium. A similar approach to the one used by Alexander & Leontsinis (2011) was implemented by calculating a number of statistical measures on the difference between the forecasted and realised values such as the mean, standard deviation, min, max and the root mean squared error. 4. Results The results from the study are presented in the following graphs and tables. To better understand the effect of using implied volatilities, the daily forecasted variance swap strike from the Black-Scholes model was plotted against the historical realised variance for the S&P 500 index for the period 1996 to 2010. The fair variance strike was calculated for three different maturities and the accuracy of the forecast was measured through the statistics calculated on the variance swap premium. There are number of observations made from the following graphs. By using the implied volatilities as input parameter, the Black-Scholes model captured well the overall shape of the realised variance as it can be seen in the following three graphs. However it is important to notice that the forecasted variance tends to over-estimate the realised variance in calm markets and underestimate the true value during market crashes. One reason for this behaviour of the model is, naturally, the normal distribution assumptions for the asset returns. In addition to that, it can also be explained from behavioural point of view, where investors are being pessimistic during calm markets resulting into overreacting to negative news, while underreacting to negative news during market crashes (Frazzini 2006). Statistics on the Variance Swap Premium 1 month maturity Mean StDev Min Max RMSE (%) (Fig. 1) 1 month maturity daily calculated fair variance swap strike using the BS model and the daily realised variance expressed as annualised volatility (%). Name: Evdokiya Ignatova 10 CID: 00656435
Statistics on the Variance Swap Premium 3 months maturity Mean StDev Min Max RMSE (%) (Fig. 2) 3 months maturity daily calculated fair variance swap strike using the BS model and the daily realised variance expressed as annualised volatility (%). Statistics on the Variance Swap Premium 6 months maturity Mean StDev Min Max RMSE (%) (Fig. 3) 6 months maturity daily calculated fair variance swap strike using the BS model and the daily realised variance expressed as annualised volatility (%). Focusing on the statistics of the variance swap premium for the three graphs, another interesting pattern emerges for the given pricing model. The variance strike seems to be much harder to predict in the short run, than in the long run. This can be seen by observing the decreasing Root Mean Squared Error indicator of figures 1 to 3, which consistently decreases as the contract maturity increases. This illustrates the idea that in the short run asset prices are expected to be more volatile and harder to predict, while in the long run the volatility levels are expected to revert to the mean. The next step was to compare how the two models performed through different market periods: calm and turbulent. As shown in figures 4 and 5, during calm markets (1996-1997) the gain from the Merton Jump-Diffusion model is very small. Through calibration of the scaling parameter for the implied volatility (see fig. 4) the model still provides a marginally better fit, but this is the case only because it compensates for the general implied volatility over-estimation. This would have most likely been also possible with the Black-Scholes model with similar calibration. Once again it is interesting to note how the estimation error reduces for both models as the contract maturity increases, which re-emphases the fact that volatility is harder to forecast in the short run. Name: Evdokiya Ignatova 11 CID: 00656435
Statistics for Variance Swap Premium 3 months maturity Black-Scholes Merton Jump-Diffusion Mean StDev Min Max RMSE (%) Calibration: scaling=, =, =, std= (Fig. 4) 3 month maturity daily calculated fair variance swap strike using the BS and MJD models and the daily realised variance expressed as annualised volatility (%). Statistics for Variance Swap Premium 6 months maturity Black-Scholes M erton Jump-Diffusion Mean StDev Min Max RMSE (%) (Fig. 5) 6 months maturity daily calculated fair variance swap Calibration: scaling=, =, =, std= strike using the BS and MJD models and the daily realised variance expressed as annualised volatility (%). During market crashes, focusing on the banking crisis in the period of 2007 to 2010, it can be seen from the following graphs that the market volatility reached almost 80%. In this period of extreme volatility, the Merton Jump-Diffusion model performed better than the Black-Scholes model for short maturities, however not significantly better for longer maturities. Also in contrast with the calm market period the errors in the forecasts are quite significant for both models. Statistics Variance Swap Premium 3 months maturity Black-Scholes Merton Jump-Diffusion Mean StDev Min Max RMSE (%) Calibration: scaling=, =, =, std= (Fig. 6) 3 months maturity daily calculated fair variance swap strike using the BS and MJD models and the daily realised variance expressed as annualised volatility (%). Name: Evdokiya Ignatova 12 CID: 00656435
Statistics Variance Swap Premium 6 months maturity Black-Scholes M erton Jump-Diffusion Mean StDev Min Max RMSE (%) Calibration: scaling=, =, =, std= (Fig. 7) 6 months maturity daily calculated fair variance swap strike using the BS and MJD models and the daily realised variance expressed as annualised volatility (%). 5. Conclusion Through this study, two variance swap pricing models were evaluated, the Black-Scholes model which assumes continuous asset price movement and the Merton Jump-Diffusion model which allows for discontinuous asset price jumps. It was discovered that based on the assumption that we use implied volatilities as the parameter estimate for initial stock price volatility, there is some benefit of using the Merton Jump-Diffusion model over the Black-Scholes model. However, one needs to be aware of the need to calibrate the jump parameters, which adds extra complexity and has proven to be computationally expensive. In addition, the study also illustrated certain drawbacks shared by both models because of the distributional assumptions for the equity index returns. As a result of which both model tended to over-estimate the realised variance during calm periods and under-estimate the realised variance during market crashes. Future areas of research as a continuation of this study would be to move away from the normal distribution as model for the returns. Additionally, it would be important to investigate finer calibration methods for the jump parameters, since the calibration technique used as part of this study was very time consuming and computationally expensive. Another area of research would be to investigate other asset price models which allow the volatility to vary stochastically, but even more importantly to look at models with stochastic volatility with jumps. Name: Evdokiya Ignatova 13 CID: 00656435
6. References Bossu, Sebastien, Strasser, Eva & Guichard, Regis. (2005) Just what you need to know about variance swaps. [Online] Available from: [Accessed 8/8/2011]. Demeterfi, Kresimir, Derman, Emanuel, Kamal, Michael & Zou, Joseph. (1999) More Than You Ever Wanted To Know About Volatility Swaps. [Online] Available from: [Accessed 8/8/2011]. Merton, Robert C. (1976) Option pricing when underlying stock returns are discontinuous. [Online] Available from: [Accessed 8/25/2011]. Joshi, M. S. (2008) C++ design patterns and derivatives pricing. 2nd edition. Cambridge, Cambridge University Press. Glasserman, Paul. (2004) Monte Carlo methods in financial engineering. Applications of mathematics, New York, Springer. Tankov, P. & Voltchkova, E. (2006) Jump-Diffusion Models: A Practitioner's Guide. [Online] Available from: [Accessed 8/25/2011]. Alexander, Carol & Leontsinis, Stamatis. (2011) Model Risk in Variance Swap Rates. [Online] Available from: [Accessed 8/24/2011]. Frazzini, Andrea. (2006) The Disposition Effect and Underreaction to News. The Journal of Finance, 61 (4), 2017 pages 2046. Wharton Research Data Services (WRDS). [Online] Available from: [Accessed 8/25/2011] Name: Evdokiya Ignatova 14 CID: 00656435
7. Code C++ Code #include <> #include <boost/> #include <iostream> int main(int argc, const char** argv) { size_t no_paths = 5000; double s0 = boost::lexical_cast<double>(argv[1]); double r = boost::lexical_cast<double>(argv[2]); double q = boost::lexical_cast<double>(argv[3]); size_t days = boost::lexical_cast<size_t>(argv[4]); double vol = boost::lexical_cast<double>(argv[5]); double intensity = boost::lexical_cast<double>(argv[6]); double a = boost::lexical_cast<double>(argv[7]); double b = boost::lexical_cast<double>(argv[8]); size_t no_steps = days; pricer p(no_steps,no_paths); double fair_strike = _variance_swap(s0,r,q,days,vol,intensity,a,b); std::cout << fair_strike; return 0; } #include <> #include <iostream> rv_pair pricer::get_rand_by_marsaglia_polar_method() { double u1,u2,v1,v2,s; do { u1 = rand()/double(RAND_MAX); u2 = rand()/double(RAND_MAX); v1 = 2*u1-1; v2 = 2*u2-1; s = v1*v1+v2*v2; //ensuring that both v1 and v2 are within the unit circle } while(s > 1 && s != 0); double r1 = v1*sqrt(-2*log(s)/s); double r2 = v2*sqrt(-2*log(s)/s); return rv_pair(r1,r2); } Name: Evdokiya Ignatova 15 CID: 00656435
pricer::pricer(size_t no_steps, size_t no_paths) : no_steps_(no_steps), no_paths_(no_paths) { srand(5); } double pricer::price_variance_swap(const double s0, const double r,const double q, const size_t days,const double vol, const double intensity, const double a, const double b) { double expiry = days/; double dt = expiry/double(no_steps_); double ln_s0 = log(s0); double forecasted_var = 0; for (size_t i = 0; i < no_paths_; ++i) { double s0_1 = ln_s0; double s0_2 = ln_s0; double var_path1 = 0; double var_path2 = 0; for (size_t j=0; j < no_steps_; ++j) { rv_pair rands = get_rand_by_marsaglia_polar_method(); rv_pair antithetic_rands = rv_pair(,); double s1 = get_price(s0_1, r, q,vol,days,intensity,a,b,rands); double s2 = get_price(s0_2, r, q, vol,days,intensity,a,b,antithetic_rands); var_path1+=get_sqr_log_return(s1,s0_1); var_path2+=get_sqr_log_return(s2,s0_2); s0_1=s1; s0_2=s2; } forecasted_var += sqrt(var_path1/double(no_steps_-1)); forecasted_var += sqrt(var_path2/double(no_steps_-1)); } forecasted_var = (forecasted_var/(2*no_paths_)); return forecasted_var*std::sqrt() * 100; } double pricer::get_sqr_log_return(const double ln_s,const double ln_s0) { return pow(ln_s-ln_s0,2); } double pricer::get_price(const double ln_s,const double r,const double q,const double vol,const size_t days,const double intensity,const double a, const double b,const rv_pair rands) { //Euler approximation for the stock price //ln(s_1) = ln(s_0) + (r-(vol*vol)/2-intensity*m)*dt + vol*sqrt(dt)*rv_1 + (aN + b*sqrt(N)*rv_2) double expiry = days/; double dt = expiry/double(no_steps_); double sqrt_dt = sqrt(dt); Name: Evdokiya Ignatova 16 CID: 00656435
double drift = (r-(vol*vol)/-intensity*get_avg_jump_size(a,b)); double probability = poisson_draw(intensity,days); double jump = get_jump(a,b, probability, ); return ln_s + drift*dt + vol*sqrt_dt* + jump; } double pricer::get_avg_jump_size(const double a,const double b) { return std::exp(a+b*b/2)-1; } double pricer::get_jump(const double a,const double b,const double p,const double rand) { return a*p + b*sqrt(p)*rand; } double pricer::generate_uniform01_rv() { return rand()/double(RAND_MAX+1); } double pricer::poisson_draw(const double intensity,const size_t days) { //Using the inverse transform method for sampling from Poisson distribution (Glasserman p128) double theta = intensity*(days/); double p = 1/std::exp(theta); double p_bak = p; double f = p; double n = 0; double u = generate_uniform01_rv(); while (u > f) { ++n; p = (p*theta)/n; f += p; } return n; } #ifndef PRICER_H #define PRICER_H #include <utility> typedef std::pair<double,double> rv_pair; class pricer { public: pricer(size_t no_steps, size_t no_paths); double price_variance_swap(const double s0, const double r,const double q, const size_t days,const double vol, const double intensity, const double a, const double b); private: Name: Evdokiya Ignatova 17 CID: 00656435
double get_price(const double s,const double r,const double q,const double vol,const size_t days,const double intensity,const double a, const double b,const rv_pair rands); double get_sqr_log_return(const double ln_s,const double ln_s0); double poisson_draw(const double intensity,const size_t days); double get_jump(const double a,const double b,const double n,const double rand); double get_avg_jump_size(const double a,const double b); rv_pair get_rand_by_marsaglia_polar_method(); double pricer::generate_uniform01_rv(); const size_t no_steps_; const size_t no_paths_; }; #endif Python Code import imp_vol_data from imp_vol_data import cp_flag from varianceswapmodelling import price_variance_swap import realised_variance import indexprices_data import as plt import descriptive_statistics from datetime import date def calculate_descriptive_statistics(contract_maturity,pretty_print, bs_forecasted_var, mjd_forecasted_var, realised_var,dates, start_date, end_date): start_index = (start_date) end_index = (end_date) calculate_descriptive_statistics(contract_maturity,pretty_print, bs_forecasted_var, mjd_forecasted_var, realised_var, start_index, end_index) def calculate_descriptive_statistics(contract_maturity,pretty_print, fair_var_strikes_bs, fair_var_strikes_mjd, realised_var, start_index, end_index): #calculating desriptive statistics and root mean squared error for the given models within a specified time range (rmse_bs, mean_bs, std_bs, min_bs, max_bs) = (fair_var_strikes_bs,realised_var,start_index,end_index) (rmse_mjd, mean_mjd, std_mjd, min_mjd, max_mjd) = (fair_var_strikes_mjd,realised_var,start_index,end_index) with open("10years/", "a") as statistics_file: ('Descriptive Statistics for Maturity: ' + pretty_print +"\n") ( ' |Black Scholes | Merton Jump-Diffusion | '+"\n") Name: Evdokiya Ignatova 18 CID: 00656435
( 'Mean | ' + str(mean_bs) + ' | ' + str(mean_mjd) +' | '+"\n") ( 'StDev | ' + str(std_bs) + ' | ' + str(std_mjd) + ' | '+"\n") ( 'Min | ' + str(min_bs) + ' | ' + str(min_mjd) + ' | '+"\n") ( 'Max | ' + str(max_bs) + ' | ' + str(max_mjd) + ' | '+"\n") ( 'RMSE (%)| ' + str(rmse_bs*100) + ' | ' + str(rmse_mjd*100) + '| '+"\n") def price_dates(contract_maturity, pretty_print, rf, q): dates = [] fair_var_strikes_bs = [] fair_var_strikes_mjd = [] strikes = [] dates_adjclose_prices = {} realised_variances = [] for day_data in (): dates_adjclose_prices[] = _close_price #forecast realised variance for day_data in (): if ( == contract_maturity) and (_flag == ): (dates_adjclose_prices[]) () #Black Scholes Model k_bs = price_variance_swap(dates_adjclose_prices[], rf, q, , _volatility, 0, 0, 0) (k_bs) print str(contract_maturity) + 'bs/' + () + '/' + str(k_bs) #Merton Jump-Diffusion Model k_mjd = price_variance_swap(dates_adjclose_prices[], rf, q, , _volatility, 0, 0, 0) (k_mjd) print str(contract_maturity) + 'mjd/' + () + '/' + str(k_mjd) #calculate realised variance for i in range(len(dates)): date_window = strikes[i:(i+contract_maturity+1)] if len(date_window) == (contract_maturity+1): ((date_window)) Name: Evdokiya Ignatova 19 CID: 00656435
max_len = len(realised_variances) calculate_descriptive_statistics(contract_maturity, pretty_print, fair_var_strikes_bs[0:max_len], fair_var_strikes_mjd[0:max_len], realised_variances, 0, max_len) #dates[0:max_len], #date(1996,01,02), #date(1999,12,31)) return (dates[0:max_len], fair_var_strikes_bs[0:max_len], fair_var_strikes_mjd[0:max_len], realised_variances) def main(): #read each row in the CSV file maturities = {21:'1 month', 42:'2 months', 63:'3 months', 84:'4 months', 105:'5 months', 126:'6 months', 252:'1 year'} for maturity in [21, 63, 126]: #,42,63,84,105,126,252]: print str(maturity) (dates, fair_var_strikes_bs, fair_var_strikes_mjd, realised) = price_dates(maturity,(maturity), r, q) fig = () (dates, fair_var_strikes_bs, label='BS - ' + str((maturity))) #(dates, fair_var_strikes_mjd, label='MJD - ' + str((maturity))) (dates, realised, label='Actual- ' + str((maturity))) ('Annualized volatility in %') ('Date') labels= ((), 'xticklabels') (labels, rotation=30) () #() ('10years/graph%'% maturity, dpi=200) main() import csv from datetime import date #format yyyymmdd def parse_date(str_date): yr = int(str_date[0:4]) mm = int(str_date[4:6]) dd = int(str_date[6:8]) return date(yr,mm,dd) class cp_flag: CALL='C' PUT='P' #type represeting each row in the csv file class imp_vol_day_data: def __init__(self, csvRow): Name: Evdokiya Ignatova 20 CID: 00656435
= parse_date(csvRow['date']) = int(csvRow['days']) _volatility = float(csvRow['impl_volatility']) _flag = csvRow['cp_flag'] __data_cache__ = None def read(): global __data_cache__ if not __data_cache__: __data_cache__ = [] impliedvol = (open('data/snp500/', 'rb'), dialect='excel') for row in impliedvol: day_data = imp_vol_day_data(row) (day_data) return __data_cache__ import csv from datetime import date #format dd/mm/yyyy def parse_date(str_date): dd = int(str_date[0:2]) mm = int(str_date[3:5]) yr = int(str_date[6:10]) return date(yr,mm,dd) #type represeting each row in the csv file class index_price_day_data: def __init__(self, csvRow): = parse_date(csvRow['date']) _close_price = float(csvRow['adj_close']) __data_cache__ = None def read(): global __data_cache__ if not __data_cache__: __data_cache__ = [] indexprices = (open('data/snp500/', 'rb'), dialect='excel') for row in indexprices: day_data = index_price_day_data(row) (day_data) return __data_cache__ import math import numpy def calculate(forecasted_vols,actual_vols, start_index,end_index): differences = [] sum_squared_differences = 0 Name: Evdokiya Ignatova 21 CID: 00656435
for forecasted,actual in [(forecasted,actual) for forecasted in forecasted_vols[start_index:end_index] for actual in actual_vols[start_index:end_index]]: difference = actual/100 - forecasted/100 sum_squared_differences += difference**2 (difference) #root mean squared error rmse = (sum_squared_differences/len(differences)) #mean mean = (differences) #std std = (differences) #min min = (differences) #max max = (differences) return (rmse, mean, std, min, max) import imp_vol_data from imp_vol_data import cp_flag from varianceswapmodelling import price_variance_swap import realised_variance import descriptive_statistics import indexprices_data import as plt import numpy as np from import curve_fit class input_params: def __init__(self, date, impliedvol, price, rf, q, expiry): = date _volatility = impliedvol = price = rf = q = expiry def __str__(self): return str("input_params") + str((,_volatility,,,,)) def get_data(contract_maturity, rf, q): dates = [] prices = [] dates_adjclose_prices = {} for day_data in (): dates_adjclose_prices[] = _close_price x = [] for day_data in (): if ( == contract_maturity) and (_flag == ): Name: Evdokiya Ignatova 22 CID: 00656435
(input_params(, _volatility, dates_adjclose_prices[],rf,q,contract_maturity)) return x def realised_vol(x, contract_maturity): realised_volatility = [] #calculate realised variance for i in range(len(x)): date_window = [] for j in x[i:(i+contract_maturity+1)]: () if len(date_window) == (contract_maturity+1): (float((date_window))) return (realised_volatility) def forecast_vol_mjd(x, scaling_mjd, lambda_mjd, mean_mjd, sigma_mjd): forecasted_vars_mjd = [] for data in x: vol_mjd = price_variance_swap(, , , , _volatility*scaling_mjd, lambda_mjd, mean_mjd, sigma_mjd) (vol_mjd) return (forecasted_vars_mjd) __counter__ = 0 def calibrate(s_start,s_end, i_start,i_end, m_start,m_end, std_start,std_end, rf, q): global __counter__ maturity = 63 x = get_data(maturity, rf, q); realised_volatility = realised_vol(x, maturity) with open("", "a") as myfile: for scale in range(s_start,s_stop, ): for intensity in [i_start,i_end,]: for mean in [m_start,m_end,]: for std in [std_start, std_end,]: forecast = forecast_vol_mjd(x, scale, intensity, mean, std) (rmse_err, mean_err, std_err, min_err, max_err) = (forecast[0:len(realised_volatility)],realised_volatility,0,len(realised_volatility)) __counter__ += 1 log = (str(__counter__) + " -- " + str(rmse_err) + " (rmse) -- " " scaling_mjd:"+ str(scale)+ ", lambda_mjd:"+ str(intensity)+ ", mean_mjd:" + str(mean)+ ", sigma_mjd:"+ str(std) + ", maturity: " + str(maturity)) print log (log + "\n") calibrate() Name: Evdokiya Ignatova 23 CID: 00656435