- volatilityMan
**Posts:**108**Joined:**

HiIm currently doing some FFT pricing on Bates model. However, I have a small error (it seems so) somewhere in Bates model when calculating FFT prices. Could anyone please plug in these parameter values and see if you get the same result.1) European call ITM(kappa, theta,sigmaV,rho,v0,lambda,muS,sigmaS,r,T,S0,K)=(2.86,0.062,0.60,-0.96,0.040,0.21,-0.15,0.18,0,31/365,1325,1300)2) European call OTM(kappa, theta,sigmaV,rho,v0,lambda,muS,sigmaS,r,T,S0,K)=(2.86,0.062,0.60,-0.96,0.040,0.21,-0.15,0.18,0,31/365,1325,1700)These are my results1) FFTprice = 49.7677 and Strike = 1298.72) FFTprice = 0.0557 and Strike = 1701.5Thanks!

- volatilityMan
**Posts:**108**Joined:**

Sorry, the right output is 1) FFTprice = 48.3429 and Strike = 1298.72) FFTprice = 0.0557 and Strike = 1701.5

- LocalVolatility
**Posts:**128**Joined:****Location:**Amsterdam-
**Contact:**

I get using the COS method:strike = 1298.70 --> price = 47.2426strike = 1701.50 --> price = 0.0349By the way - you could use QuantLib to generate some reference prices to test your implementation.

Last edited by LocalVolatility on August 25th, 2015, 10:00 pm, edited 1 time in total.

- volatilityMan
**Posts:**108**Joined:**

@LocalVolatility - Thanks for you help. I really appreciate it.I've never heard of QuantLib before. Although it looks C++ oriented, unfortunately. I need to have a corret FFT pricing mechanism as im currently calibrating in MATLAB. Heston and SVJJ models look more correct to me but its purely intuition based on eyeballing. Given:----------------------------------------------------------------------------------------------------------------------------- T=31/365S0=1325;r=0;K=[700 800 900 1000 1100 1200 1300 1400 1500 1600 1700 1800]------------------------------------------------------------------------------------------------------------------------------INPUT:Heston: [Kappa,Theta,Sigma,Rho,v0] = [7.66,0.057,0.93,-0.94,0.056] SVJ : [Kappa,Theta,SigmaV,Rho,v0,LambdaJ,muS] = [2.86,0.062,0.60,-0.96,0.040,0.21,-0.15,0.18]SVJJ: [Kappa,Theta,SigmaV,Rho,v0,LambdaJ,muS,SigmaS,RhoJ,muV] = [4.17, 0.043, 0.60, -1, 0.040, 0.67, 0.04, 0.05, -1, 0.098]OUTPUT:Heston ---> [624,99 524,99 425,01 325,17 226,20 131,32 50,68 5,11 0,02 0,02 0,018 0,017]SVJ ---> [625,00 525,03 425,15 325,48 226,47 130,54 48,34 4,29 0,198 0,102 0,05 0,03]SVJJ ---> [625,01 525,05 425,16 325,46 226,42 130,55 48,31 4,03 0,14 0,03 0,019 0,017]Obviously my FFT procedure for Bates model has an issue when calculating the price OTM for European call options. I've dealt with the issue for very long time and corrected and re-written the code over and over again but just can't get it right.

- LocalVolatility
**Posts:**128**Joined:****Location:**Amsterdam-
**Contact:**

Here are my reference prices for the market data you gave in your last post. I do not have an implementation of the SVJJ model.========== HESTON ==========strike = 700.00, price = 625.00006285strike = 800.00, price = 525.00127652strike = 900.00, price = 425.01690315strike = 1000.00, price = 325.15803885strike = 1100.00, price = 226.09963212strike = 1200.00, price = 130.88148726strike = 1300.00, price = 49.52000571strike = 1400.00, price = 3.95622021strike = 1500.00, price = 0.00010744strike = 1600.00, price = 0.00000000strike = 1700.00, price = 0.00000000strike = 1800.00, price = 0.00000000========== BATES ==========strike = 700.00, price = 625.00508218strike = 800.00, price = 525.03419568strike = 900.00, price = 425.14944325strike = 1000.00, price = 325.47426246strike = 1100.00, price = 226.37022768strike = 1200.00, price = 129.94017030strike = 1300.00, price = 46.33601615strike = 1400.00, price = 2.34053324strike = 1500.00, price = 0.17161033strike = 1600.00, price = 0.07947204strike = 1700.00, price = 0.03531019strike = 1800.00, price = 0.01516107 Here are some more reference Heston prices that I generated with QuantLib. Its C++ but should be self explanatory. Also, see this post for additional ones: http://wilmott.com/messageview.cfm?cati ... adid=90957.// test cases { maturity, strike, isCall, rate, dividend, initialVariance, kappa, theta, xi, rho, price }auto testCases = std::vector<std::tuple<double, double, bool, double, double, double, double, double, double, double, double>>{ // strongy negative correlation std::make_tuple(1.0, 60.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, -0.9, 3.5375112542450324e01), std::make_tuple(1.0, 70.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, -0.9, 2.7427325387430948e01), std::make_tuple(1.0, 80.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, -0.9, 2.0240629774258657e01), std::make_tuple(1.0, 90.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, -0.9, 1.4001324665222874e01), std::make_tuple(1.0, 100.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, -0.9, 8.8824387466328574e00), std::make_tuple(1.0, 110.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, -0.9, 5.0081726737803436e00), std::make_tuple(1.0, 120.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, -0.9, 2.4009298734285949e00), std::make_tuple(1.0, 130.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, -0.9, 9.2400724820119429e-01), std::make_tuple(1.0, 140.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, -0.9, 2.6936627355936693e-01), // moderate negative correlation std::make_tuple(1.0, 60.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, -0.5, 3.5074765499806006e01), std::make_tuple(1.0, 70.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, -0.5, 2.7134445847690039e01), std::make_tuple(1.0, 80.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, -0.5, 2.0093382375018251e01), std::make_tuple(1.0, 90.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, -0.5, 1.4167852267017899e01), std::make_tuple(1.0, 100.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, -0.5, 9.49176656236898e00), std::make_tuple(1.0, 110.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, -0.5, 6.0614501839125658e00), std::make_tuple(1.0, 120.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, -0.5, 3.7246253098818336e00), std::make_tuple(1.0, 130.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, -0.5, 2.2329225618621162e00), std::make_tuple(1.0, 140.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, -0.5, 1.3252129408205953e00), // zero correlation std::make_tuple(1.0, 60.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.0, 3.4607845802556248e01), std::make_tuple(1.0, 70.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.0, 2.662745409784813e01), std::make_tuple(1.0, 80.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.0, 1.9766651117073778e01), std::make_tuple(1.0, 90.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.0, 1.4255054713881307e01), std::make_tuple(1.0, 100.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.0, 1.0103607357588899e01), std::make_tuple(1.0, 110.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.0, 7.1263163282706969e00), std::make_tuple(1.0, 120.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.0, 5.0515627035382913e00), std::make_tuple(1.0, 130.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.0, 3.6212086227054741e00), std::make_tuple(1.0, 140.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.0, 2.6333395887436311e00), // moderate positive correlation std::make_tuple(1.0, 60.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.5, 3.4015315311571072e01), std::make_tuple(1.0, 70.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.5, 2.5883423769908831e01), std::make_tuple(1.0, 80.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.5, 1.9220977121174926e01), std::make_tuple(1.0, 90.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.5, 1.4198119835298456e01), std::make_tuple(1.0, 100.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.5, 1.0582242152205726e01), std::make_tuple(1.0, 110.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.5, 8.0126610520760728e00), std::make_tuple(1.0, 120.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.5, 6.1754756291903377e00), std::make_tuple(1.0, 130.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.5, 4.8427616388360146e00), std::make_tuple(1.0, 140.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.5, 3.8591360834472148e00), // very positive correlation std::make_tuple(1.0, 60.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.9, 3.3483238000382251e01), std::make_tuple(1.0, 70.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.9, 2.4955398530654449e01), std::make_tuple(1.0, 80.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.9, 1.851182250295102e01), std::make_tuple(1.0, 90.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.9, 1.4012573586875746e01), std::make_tuple(1.0, 100.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.9, 1.0869784621291856e01), std::make_tuple(1.0, 110.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.9, 8.6242390525055299e00), std::make_tuple(1.0, 120.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.9, 6.9778002853202032e00), std::make_tuple(1.0, 130.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.9, 5.7411815322366913e00), std::make_tuple(1.0, 140.0, true, 0.05, 0.1, 0.04, 3.0, 0.16, 1.0, 0.9, 4.7923089769902418e00)};double spot = 100.0;

Last edited by LocalVolatility on August 25th, 2015, 10:00 pm, edited 1 time in total.

- LocalVolatility
**Posts:**128**Joined:****Location:**Amsterdam-
**Contact:**

One more suggestion: You mentioned that you use MATLAB. Check the book by Kienitz and Wetterau - its very hands on and implementes the COS method. See http://www.mathworks.com/matlabcentral/ ... nmodelling for their code.

- volatilityMan
**Posts:**108**Joined:**

Again - thanks a lot @LocalVolatility! It's difficult to "see" how big an error - if so - it really is. When plotting simple IV's agains strikes everything seems OK. The link you posted to however, indicate that the prices should coincide all the way down to 4-5 decimals. I actually have the book by Kienitz and Wetterau. Together with the book by Rouah and Heston I would argue that they are the best ones out there wrt. pricing and calibration.

- LocalVolatility
**Posts:**128**Joined:****Location:**Amsterdam-
**Contact:**

I can't tell you the exact precision of the reference values that I gave you. But the error should be less than 1.0e-04. This is the tolerance that I use in my unit tests against the QuantLib values.

- volatilityMan
**Posts:**108**Joined:**

@LocalVolatilityI have to ask you another more practical question. When you price call options that are ITM (i.e. where K<S0) you would use the standard Carr-Madan procedure (equation (6) and (24) in their paper and (5.21) in Kienitz Wetterau book).But when you price call options that are OTM (i.e. K>S0 and we are therefore in the ITM Puts domain) you would instead turn to the Carr-Madan pricing formula for puts, right?? (The formula looks quite similar with a minor change to the Fourier transform (just after eq. (20) in Kienitz).I hope my question is clear

- volatilityMan
**Posts:**108**Joined:**

What i'm asking about is the following... If this is the option pricing formula for a call option... What does the option pricing formula then look like for the Put option??C(k_{u},T) = 1/(2*pi*sinh(alpha*k_{u})) SUM_{j=0,...,N-1} exp(-1*2*pi/N*j*u) * exp(ibv_{j}) * gamma(v_{j})*eta/3 * (3+(-1)^(j+1) - [1 zeros(N-2)])This is taken from Kienitz formula (5.24) and Carr-Madan just after equation (15).Im completely confused as the option pricing formula is stated in a way that seems irrelevant whether it's a call or put. Yet it states C(k_{u},T). But what about the characteristic function we normally work with? The characteristic function which defines a Heston model, Bates model and a SVJJ model??

Hi,the formulas are very similar... If you take the original Carr-Madan paper, they also derive the equation for the puts (when they give their hybrid solution using calls and puts for the calibration). Furthermore, the Carr-Madan method without FFT but with integration can be applied as fast and with the highest accuracy when you use the optimal damening parameter alpha.It is even the only method which works fine for all strikes - in fact COS has some problems. See the papers by Kahl and Lord.Another possibility to tune the stuff would be the control variate method by Joshi. We have applied the CM with Control Variates and that worked really fine.Best regards,Lapsi

Also, thanks so much for mentioning my book! BTW the code can be downloaded on the Mathworks website!There is also a new piece on ZABR model if you like!Best, Lapsi

- volatilityMan
**Posts:**108**Joined:**

@LapsiLago - thank you for your in depth and clarifying answers. I will try to be a little more clear in my formulation - My goal is pricing and calibration of european put and call option on Heston, Bates and SVJJ model- I am using out of the money call and out of the money put options only as these are essential in estimating jump parameters. OTM options contain most information about the tails of the distribution- I am using the OTM pricing formula from Carr Madan (1999):C(ku) = 1/(sinh(alpha*ku))*1/pi SUM_{j=1,...,N} [exp(-i*2*pi/N*(j-1)*(u-1))* exp(i*b*vj) * gamma * eta/3 * (3 + (-1)^j - delta)]Question: Is the pricing formula only described for OTM call options? Or does the same formula apply for OTM put options?I cannot see if the same formula is applied for BOTH call AND put options. Or if the formula only applies for OTM call options and therefore has to be modified in order to obtain OTM put prices. Essentialy, the term "C(ku)" is confusing me, as the formula is written using call price terminology. Yet at the same time is written to apply for put prices. Is it ONE formula for pricing both call and put options? Or should the above formula be somewhat modified when pricing OTM put?I am aware of the fact that Carr and Madan write "The use of FFT for calculating out-of-the-money option prices is similar to (24) [FFT and Simpson rule]. The only differences are that we replace exp(-alpha*ku) with a division by sinh(alpha*k) and the function call to psi(v) is replaced by a function call to gamma(v) defined in (15)".But it doesn't do me any good in fundamental understanding.

QuoteOriginally posted by: LapsilagoHi,the formulas are very similar... If you take the original Carr-Madan paper, they also derive the equation for the puts (when they give their hybrid solution using calls and puts for the calibration). Furthermore, the Carr-Madan method without FFT but with integration can be applied as fast and with the highest accuracy when you use the optimal damening parameter alpha.It is even the only method which works fine for all strikesI will quibble a bit with this. I believe (3.11) here works fine for all strikes, as well as its analogfor all the stoch. vol. models discussed in this thread. (Just add the initial variance state [$]V_0[$] to the char. func. argument). The correspondingformula for puts is found from the put/call parity relation given below the cited eqn. If I was attempting to get some FFT code working, first I would code (3.11) (and the one puts) and then use whichever one wasout-of-the-money for reference values.p.s. There is discussion in Rouah's book, as well as my own.

Last edited by Alan on August 29th, 2015, 10:00 pm, edited 1 time in total.

- volatilityMan
**Posts:**108**Joined:**

I have now implemented the FFT procedure for OTM options. I followed your advice, Alan. I simply implemented the FFT pricing formula for ITM call options, found the prices using Simpson's weights as described in eq. (3.44) in Rouah and (5.21) in Kienitz and Wetterau's book, before finally using put-call parity to extract the corresponding OTM put options. Now OTM puts were obtained I moved to step two. Here the FFT pricing formula for OTM call options were used i.e. eq. (3.58) i Rouah's book together with the implementation of eq. (5.24) in Kienitz and Wetterau. Things seem to work. Using the references as control described in the book by Rouah match. I would like to thank you all for helping me. Thanks to @LocalVolatility, @LapsiLago and @Alan. If anyone should need any advise or help on implementing the code, feel free to ask - i'll gladly assist

GZIP: On