Building an IV Surface: Parity Forward, Black-76, 25-Delta Wings

How do you turn a noisy option chain into one clean volatility number? In this episode of Inside Kestrel we build an implied volatility surface from scratch: a put-call parity forward, Black-76 inversion, ATM IV, 25-delta risk reversal and butterfly, and constant-maturity IV.

Intro

One Bad Quote

Imagine a screen full of option quotes, and exactly one of them is wrong. A stale price, a wide spread, a fat finger. If your volatility number moves because of that single quote, it was never a measurement. In this episode we build an implied volatility surface that refuses to be fooled.

  • One bad quote
  • One stable number

Where We Are

This is episode thirteen of Inside Kestrel. Last time, in episode twelve, we built Black-Scholes, the Greeks, and implied volatility by bisection. Today we use that solver as a black box, and build everything around it: the forward, the smile, the wings, and the term structure.

  • Ep 12: the solver
  • Ep 13: the surface

Chain In, Four Numbers Out

By the end, a raw option chain will become four numbers per expiry: at-the-money implied volatility, a risk reversal, a butterfly, and a constant-maturity implied volatility. The code lives in pricing slash iv surface dot cpp. It is pure math with no input or output, which makes it easy to test.

  • ATM IV
  • Risk reversal
  • Butterfly
  • Constant maturity

The Problem

Noise Is Normal

Indian index option chains are noisy. Deep strikes are thinly traded, spreads are wide, and last traded prices can be minutes old. A surface built naively from every quote inherits all of that noise, and it shows up as kinks in the smile.

  • Thin deep strikes
  • Wide spreads
  • Stale last prices

Spot vs Forward

There is a second problem. Spot is not the right reference price for an option. Options on an index settle against where the index will be at expiry, so the relevant anchor is the forward, which includes interest and carry. Using spot quietly tilts every strike's moneyness.

  • Spot is today
  • Forward is expiry

Solver Stays Off the Feed

One design note. The surface is computed by a separate md-client app called kestrel ivsurface. Solving implied volatility for a whole chain costs real CPU time, and we never want a slow solver to delay the market data feed. So it runs in its own process, and the math stays pure.

  • Separate process
  • Pure math, no I/O

Forward by Parity

Parity Gives a Forward

Start with put-call parity. For a given strike, a call minus a put equals the discounted forward minus the discounted strike. Rearranged, each strike gives its own estimate of the forward: F sub k equals K plus e to the r T times the call price minus the put price.

  • F_k = K + e^(rT)(C - P)

Nearest Strikes, Both Sides

We do not use every strike. We take the two times parityStrikesEachSide plus one strikes nearest spot that have both a call and a put. Near the money, both options trade, so both prices are meaningful and the estimate is tight.

  • 2n+1 strikes near spot
  • Call and put both required

Median Beats Mean

Now combine the estimates. Take strikes 22700, 22800 and 22900. Parity gives forwards of 22851, 22853, and 22990, because the last strike has one bad quote. The mean is 22898, dragged sixty points away. The median is 22853, completely unmoved.

  • Mean: 22898
  • Median: 22853

Outlier Slides Away

The intuition: a mean lets one value pull with unlimited force, while a median only cares about rank. A single outlier, however extreme, can move the median by at most one neighbour. That is exactly the property we want when we cannot tell which quote is wrong.

  • Mean follows the outlier
  • Median ignores it

Fallback: Spot Times Carry

If no strike has both sides, we fall back to spot times e to the r T, and mark the source as spot. When parity does work, the forward source records whether the prices were mids, last traded prices, or a mixture. Downstream code can then decide how much to trust the result.

  • Else S e^(rT)
  • forwardSource: mid, ltp, mixed

Simplified Excerpt

Here is the logic, simplified. For the nearest strikes with both sides, compute F sub k. Forward is the median of those, otherwise spot times e to the r T. It is short, and every line has a reason.

  • Simplified pseudo-code

OTM Options and Black-76

One Option Per Strike

Next, for each strike we pick one option. If K is at or above the forward, use the call; otherwise use the put. If that side is missing, use the other one. Out-of-the-money options are the liquid ones, and their prices are mostly time value, so a small price error becomes a small volatility error.

  • K >= F: call
  • K < F: put

Intrinsic Hides Volatility

In-the-money options are mostly intrinsic value, and intrinsic value tells you nothing about volatility. Their spreads are wide and they trade rarely. A rupee of error on a deep in-the-money quote can swing the implied volatility wildly, so we simply do not use them unless nothing else exists.

  • ITM: mostly intrinsic
  • OTM: mostly time value

Reuse the Solver

Now invert the price. Black-76 prices options on a forward. The trick in Kestrel is reuse: undiscount the option price by multiplying with e to the r T, then call the ordinary Black-Scholes solver with spot set to the forward and the rate set to zero. No second solver, no second set of bugs.

  • price76 = price * e^(rT)
  • spot = F, rate = 0

Simplified Excerpt

In simplified form: price76 equals option price times e to the r T, then iv equals implied volatility of price76, with spot equal to F, strike K, rate zero, and time T. That is the whole bridge from forwards to the solver we already trust.

  • Two lines, one bridge

Two Rejection Rules

Two rejection rules protect the surface. If a price is at or below intrinsic value, no positive volatility can produce it, so the strike is dropped. And if the solved implied volatility is at or below one thousandth, that is a degenerate answer, so it is dropped as well. Better a gap than a lie.

  • Price <= intrinsic: drop
  • IV <= 1e-3: drop

Delta Under Black-76

To place strikes on a delta axis we need delta. For Black-76, call delta is N of d one, where d one equals the log of F over K, plus s squared over two, all divided by s, and s is volatility times root T. Put delta is then the call delta minus one.

  • d1 = [ln(F/K) + s²/2] / s
  • s = σ√T

ATM IV

The Smile Against ln(K/F)

Now we have a cloud of strikes, each with an implied volatility. To compare them, we plot against log-moneyness, the natural log of K over F. Zero means exactly at the forward. Negative is below, positive is above. Symmetric moves in price become symmetric distances on this axis.

  • x = ln(K/F)
  • x = 0 is the forward

Bracket and Interpolate

At-the-money volatility is the smile evaluated at zero. Find the two strikes that bracket the forward, one below and one above, and interpolate linearly in log-moneyness between them. The forward almost never lands on a strike, so this interpolation is how we read the value at the exact centre.

  • Two strikes around F
  • Linear in ln(K/F)
  • Evaluate at 0

A Shifted Center

This is where using spot instead of the forward hurts. If spot is 22800 but the forward is 22853, a spot-centred smile is shifted. You would read the volatility at the wrong point on the curve, and the error is systematic, not random. It would leak into every risk reversal and butterfly we compute next.

  • Wrong center, wrong ATM
  • Bias flows into wings

25-Delta Wings

Remap the Axis

Strikes are a poor language for comparing smiles across expiries and days, because the same strike means different things as time and volatility change. Delta is a better ruler: it measures how far out of the money an option is, in probability-like terms. So we re-map the smile onto a delta axis.

  • Strike axis becomes delta axis
  • Markers at ±0.25

Find the 25-Delta Points

We compute a delta for every strike, using its own implied volatility. The call side targets call delta 0.25. The put side targets put delta minus 0.25, which is call delta minus one, so a call delta of 0.75. We walk along the smile in delta space and interpolate linearly between the two points that bracket each target.

  • Call delta 0.25
  • Put delta -0.25 = call delta - 1

rr25 Measures Skew

Now the first wing statistic. The risk reversal is call implied volatility at 25 delta minus put implied volatility at 25 delta. It measures skew: whether the market pays more for upside or downside protection. A negative number means the put wing is richer. It is a description of the smile, not a prediction.

  • rr25 = callIv25 - putIv25

bf25 Measures Curvature

The second statistic is the butterfly: the average of the two wing volatilities minus the at-the-money volatility. If the wings sit above the centre, the smile is curved, and the butterfly is positive. It measures curvature, while the risk reversal measures tilt.

  • bf25 = avg wings - ATM

Level, Tilt, Bend

Together, ATM, risk reversal and butterfly summarise a smile in three numbers. ATM sets the level, the risk reversal tilts it, and the butterfly bends it. Because they are defined on delta and not strike, they can be compared from one day to the next without the strikes changing meaning.

  • ATM: level
  • rr25: tilt
  • bf25: bend

Constant Maturity

Fixed Horizon, Moving Expiries

Everything so far is for one expiry. But expiries roll: next week's option becomes this week's, and the time to expiry shrinks every day. To track volatility at a fixed horizon, say thirty days, we must blend two expiries. The question is what exactly to interpolate.

  • Expiries at 7 and 35 days
  • Target: 30 days

Variance Adds Up

The answer is total variance, w equals sigma squared times T. Variance is additive in time: the variance over the first week plus the variance over the following weeks is the variance over the whole stretch. Volatility has no such property, so a straight line in volatility has no clean meaning.

  • w = σ² T
  • Variance is additive in time

Compute w1 and w2

Take a seven-day implied volatility of fourteen percent and a thirty-five-day implied volatility of thirteen percent. Total variance at seven days is 0.14 squared times 7 over 365.25, which is 0.0003756. At thirty-five days it is 0.13 squared times 35 over 365.25, which is 0.0016194.

  • w1 = 0.0003756
  • w2 = 0.0016194

w(30) Gives 13.04%

Now interpolate linearly in T. Thirty days is twenty-three days past the first expiry, out of a twenty-eight day gap. So w of thirty equals 0.0003756 plus 0.0012438 times 23 over 28, which is 0.0013973. Dividing by T, thirty over 365.25, and taking the square root gives thirteen point zero four percent.

  • w(30) = 0.0013973
  • σ = 13.04%

Two Views of One Line

Look at the same line in volatility space. The straight line in variance becomes a curve in volatility, and it sits at 13.04 percent. Naive linear interpolation of volatility would give 13.18 percent. The gap looks small here, but the variance method is the one consistent with how risk accumulates over time.

  • Variance: straight
  • Volatility: bends
  • 13.04% vs 13.18%

Keep Variance Monotone

There is a deeper reason. Total variance should never decrease as maturity grows, otherwise a calendar spread would be free money, which is called calendar arbitrage. Interpolating volatility directly can produce points that break that rule. Interpolating variance between two valid points keeps it monotone.

  • Total variance must not fall
  • Variance interpolation keeps order

Simplified Excerpt

The simplified code: w of T equals w one plus w two minus w one, times T minus T one over T two minus T one. Then sigma equals the square root of w over T. Outside the two bracketing expiries, we use flat extrapolation: just return the nearest expiry's volatility.

  • Interpolate w
  • Then sigma = sqrt(w/T)
  • Flat outside

Pitfalls

Mistake One: ITM Quotes

Let us collect the mistakes. First, using in-the-money options. They are wide, illiquid and mostly intrinsic, so they inject noise into the smile. Out-of-the-money options, call above the forward and put below, give the cleanest information per quote.

  • Wide and illiquid
  • Use the OTM side

Mistakes Two and Three

Second, using spot instead of the forward, which shifts the whole smile. And third, a close cousin: averaging forward estimates instead of taking the median, which lets one bad quote move the anchor for every strike. Both mistakes are quiet. Nothing crashes. The numbers just drift.

  • Spot instead of forward
  • Mean instead of median

Don't Extend the Line

Fourth, extrapolating beyond the last expiry. There is no data out there, and a line extended into emptiness can imply absurd volatilities. Kestrel uses flat extrapolation outside the bracketing expiries, which is a modest, honest choice that does not pretend to know more than the chain says.

  • No data beyond last expiry
  • Flat extrapolation

Recap

Recap: The Pipeline

Recap. Estimate the forward from put-call parity and take the median, falling back to spot times e to the r T. Use the out-of-the-money option at each strike, undiscount it, and reuse the solver with spot equal to F and rate zero. Read ATM at zero log-moneyness, and the wings at 25 delta, giving risk reversal and butterfly.

  • Median parity forward
  • OTM + Black-76
  • ATM, rr25, bf25
  • Variance interpolation

Next: Backtest Metrics

Everything here is educational, and the numbers are illustrative, not advice. In the next episode we measure a backtest properly: Sharpe, Sortino and drawdown, done right.

  • Episode 14
  • Sharpe, Sortino, drawdown