I am using the QuantLib developers example to try and price a TY option. The Delta is pretty close but the price and gamma are way off (almost by a factor of 2).

Am I using the model wrong or is the model wrong?

Here is the code

import QuantLib as ql
import math
calendar = ql.UnitedStates()
bussiness_convention = ql.ModifiedFollowing
settlement_days = 0
day_count = ql.ActualActual()

interest_rate = 25/10000
calc_date = ql.Date(1,7,2021)
yield_curve = ql.FlatForward(calc_date, 
ql.Settings.instance().evaluationDate = calc_date
option_maturity_date = ql.Date(23,7,2021)
strike = 133
spot = 132.40625 # futures price
volatility = 3.896/100
flavor = ql.Option.Call

discount = yield_curve.discount(option_maturity_date)
strikepayoff = ql.PlainVanillaPayoff(flavor, strike)
T = yield_curve.dayCounter().yearFraction(calc_date, 
stddev = volatility*math.sqrt(T)

black = ql.BlackCalculator(strikepayoff, 
print("Option Price: " + str(black.value() ))
print("Delta: " + str(black.delta(spot) ))
print("Gamma: " + str(black.gamma(spot) ))
print("Theta: "+  str(black.theta(spot, T) ))
print("Vega: "+  str(black.vega(T) ))

and the output

Category Value
Option Price 0.2638741114188638
Delta 0.3216355274081426
Gamma 0.28294608317127584
Theta -3.7640249885989223
Vega 11.648484397370504

and here is the screenshot of BBG enter image description here

  • 1
    $\begingroup$ I think your calculations are correct, at least for Black model. Do you know what is the model BBG uses? I was thinking that maybe it is cash gamma in BBG rather thatn ordinary gamma, but it isn't right either. BBG gamma looks like gamma(0.2829)∗futures(132.40625)∗0.01=0.37, but the formula for cash gamma is different. $\endgroup$
    – emot
    Commented Jul 1, 2021 at 16:07

1 Answer 1


Short answer:

  • Gamma is computed differently;
  • price is quoted by the exchange in a way QuantLib does not compute

Long answer: BBG's DES page computes Gamma as 1% chg in underlying - there is also no flexibility with the DES page and frequently this is not the best calc they offer.

However you can load any listed option in their OTC pricers to get listed mode. TYQ1C 133.00 COMB Comdty OVME loads the ticker (next to the underlying). You compute it the "wrong" way around. This ticker is quoted in price (see OMON or HP)- so IVOL is a result, not an input. Price (share) will be color coded as it uses listed price.

In terms of Gamma - click on Settings (in OVME) - User Settings - Pricing - Greeks section - Gamma - set to 1 unit underly chg and you get ~27. On the same page, you may see fraction of days ticked. So expiry is in minutes not full days (and its only 21 left). I think the API fields (DES) do that too, but generally BBG is stronger with OV pricers and MARS than this FLDS API stuff (but is very close here, so should be fine).

I cannot comment on quantlib, but is this really a PDE solver? That is an American option. The code ql.PlainVanillaPayoff makes me wonder if that is not simply standard Black? I may be wrong and am too lazy to try on my end now. In any case, PDE solvers are not trivial and will impose some differences.


Thanks @mmencke. Actually did not see you referenced the qlib documentation anyways Danny. It shows it is standard Black. That said, with this contract - there is little to no difference theoretically. You could hack a BS American pricer (if you have one) by including an artificial dividend equal to r and using the future price as the underlying price.

I honestly did not look at this properly and just quickly responded as I knew the gamma setting and that price is a market quote. I tried in OVME now and it is essentially identical. While all of the above still applies, understanding the quotation of these is the tricky part and not something qlib cares about. It is just Black after all (and has no reference to what contract this is). Technically there is also the distinction between price and yield vol but BBG offers only price vol for TYA which coincides with Black. You can have a look at EDA Cmdty on OVDV and OVME to see yield vol, both in lognormal and normal space.

Shares displayed in OVME are the value of 1 point. The price quote is in points and fractions of points with par on the basis of 100 points. In your screenshot, the price is 0'17 and Tick Value is USD 15.625. Hence, what you see on OVME for the quoted price on that day is

  • Price (Share): 00'17 (what is quoted)
  • Price (Total): Price (Share)*Tick Value = 281.25
  • Price (%): Price (Total) per share / Underlying Price => $(281.25/1000)/132-13 =0.002124$

What qlib displays is actually neither of this. It is Price (Total) per share = $263.9/1000 = 0.2639$ in the screenshot below. I was manually overriding OVME to use your inputs. Hence price is no longer 00'17 but 00'16 7/8 (it now solves for price like in your example). The screenshot on the right uses a higher notional, so that you see the exact decimals - and how close the two are $236895.16/1000000=0.26389516$. enter image description here

Now essentially everything matches.

For the rest, Vega is just scaling and Theta is most certainly not textbook theta in Bloomberg. It is customary to compute theta as true one-day theta (kind of bump and re-price by decreasing time to expiry , keeping all else equal) because textbook theta can exceed the actual market value of an option if the time to expiry is short, as shown in this answer.

  • $\begingroup$ The BlackCalculator returns the value of an European option as you suspected. There is an example here on how to price an American option using a binomial tree. There is a bunch of other approaches in the QuantLib C++ code (analytical approximations, Finite Difference Methods and Monte Carlo), but I am not sure which functions are exposed in Python. $\endgroup$
    – mmencke
    Commented Jul 2, 2021 at 8:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.