Unified Calculation Handling in Greek Engine

High-Tech Greek Engine

Today I have been working on a nasty little problem that I believe is one of my own making. Maybe that's a little harsh… but certainly it's one I have allowed to exist. The problem is that the calculations in the greek engine aren't exactly self-consistent. For instance, if we have a simple AAPL option:

O:AAPL:20120317:530.00:P
Spot Bid Ask ImplVol Bid ImplVol Ask
504.32 130.25 133.20 190.2967 195.3674

so that if we run the following prices through the engine, we should get some reasonable matches:

Price ImplVol Bid ImplVol Ask
130.25 190.2967 190.4185
133.20 195.2464 195.3674

or reverse the engine to give you prices for different implied vols:

Implied Vol Bid Ask
190.2967 130.24 130.16
195.3674 133.25 133.18

OK… these are the results after I fixed the code. Before, the initial calculations were looking OK, but when I tried to calculate the implodes for the prices, we'd match on the bid-side, but not the ask-side. And when we tried to get prices for implied vols, the same would happen - we'd match on one side, and miss on the other. Very odd, and not good. After all, this is one data set. One engine. One FE Model.

So I started digging into the code to see what it was that might possibly be causing these differences. The first thing I noticed was that the logic and code flow of the engine wasn't as clean as it could have been. There were entirely different code paths for the different types of calculations. This wasn't necessary because the calculation type was a bit-flag that was passed into the one main calculator object's calculate() method.

This screamed out for a clean-up.

To be fair, I hadn't put it this way, but I had known this was the case, and hadn't cleaned anything up to this point. After all, it all seemed to go back to the same calculate() method - how different could it be? Well… it turns out that it could be very different - depending on the conditions.

So I started collapsing the code. One at a time, I'd take out a distinct code path, replace the hard-coded values with variables, and use the generic code path. I had to add a few variables, sure, but it wasn't too bad. After the first couple, the rest just fell into place. In the end, it was about 100+ less lines of code, and it only took about 30 mins to do.

The results were dramatic. As seen above (boy! I wish I'd kept the bad data!), the numbers match on the different forms of the calculation. This was a big win for me as it had been bothering the testing for a few days. I'm glad to be done with this one.