Based on this text about FX options on pages 139, 141 and 145 I'm trying to compute the delta of a down and out call with the strike below the barrier. Here is a quick and dirty Python code (I assume 0 interest rates and ignore the rebate for simplicity):

from scipy.stats import norm
from math import log, sqrt
def delta(ttm,S,K,H,sig):
    x1  = ((sig*sqrt(ttm))**-1) * (log(S/H)+(0.5*sig**2)*ttm)
    y1  = ((sig*sqrt(ttm))**-1) * (log(H/S)+(0.5*sig**2)*ttm)
    mu  = -0.5*sig**2    
    lam = 1+(mu*sig**-2)

    E   = S*((H/S)**(2*lam))*norm.cdf(y1)-K*((H/S)**(2*lam-2))*norm.cdf(y1-sig*sqrt(ttm))     

    dDdS = norm.cdf(x1)-K*(norm.pdf(x1)/(sig*sqrt(ttm)))*(1-(K/H))

    dEdS = (2/S)*(1-lam)*E-((H/S)**(2*lam))*norm.cdf(y1) \
                         - ((H/S)**(2*lam))*(norm.pdf(y1)/(sig*sqrt(ttm)))*((K/H)-1)             
    return dDdS -dEdS

#args: ttm,spot,strike,barrier,vol
>> -193.12173389762643        #this looks bad
>> 0.6447696223910977


My question is not about the code. I'm pretty sure it is correct but really wonder why the results are so strange? Can this delta really become negative (I think no), or is the formula wrong? Maybe someone else already read the mentioned text and can comment?

  • $\begingroup$ My intuition is that the delta should be non-negative. See e.g. quant.stackexchange.com/questions/30177 - though this answer doesn't list a result that explicitly covers barrier options. Although you say not to check the code I can see a few mistakes in it already at first glance. 1) The expression for $\mu$ seems to have the wrong sign. 2) In $\partial D / \partial S$, you a missing brackets around $\sigma \sqrt{\tau}$ in the denominator. There are probably more.. Also - your last two lines don't make sense to me. You show a different result for the same inputs? $\endgroup$ – LocalVolatility Feb 25 '17 at 12:51
  • $\begingroup$ Seems like either your code or the formulas are wrong after all. Using my own pricer, I get a value of 65.16667 and a delta of 1.2863. $\endgroup$ – LocalVolatility Feb 25 '17 at 12:57
  • $\begingroup$ I see that you changed the the last two lines now. The results you get there are the ultimate hint that either the formulas or the code are wrong. As the Black-Scholes model has constant returns to scale, when multiplying spot, strike and barrier by the same factor then a) the price should scale by that same factor and b) the delta should stay unchanged. $\endgroup$ – LocalVolatility Feb 25 '17 at 13:01
  • $\begingroup$ Mhh thank you for the two hints in the code. The last line was a copy and paste error, sry. Actually I recoded these few lines a few times and still receive strange results. The pricing works, it's just the delta. And your delta looks rather like what I was expecting. Do you have any reference for a different formula that I can try? $\endgroup$ – Tim Feb 25 '17 at 13:10
  • $\begingroup$ Yes, that's what I also thought is very wrong. I edited the function calls for the small mistakes in the code. $\endgroup$ – Tim Feb 25 '17 at 13:16


In order to answer you question regarding the computation of the delta, I need to take a brief detour into pricing first. When the underlying asset follows a geometric Brownian motion, then barrier options can be easily priced using the method of images; see e.g. Buchen (2001). The notation I use is very similar to the one in my paper Zhang and Thul (2017) and I refer to its appendix A and B for details (sorry for the plug).

Using this approach, we can show that the price of a down-and-out call option with a barrier above the strike is given by

\begin{equation} \tilde{V}(S, \tau) = \mathcal{A}_B^+(S, \tau) - K \mathcal{B}_B^+(S, \tau) - \stackrel{B}{\mathcal{I}} \left\{ \mathcal{A}_B^+(S, \tau) - K \mathcal{B}_B^+(S, \tau) \right\}, \end{equation}


\begin{eqnarray} \mathcal{A}_\xi^s (S, \tau) & = & S e^{-\delta \tau} \mathcal{N} \left( s d_1 \right),\\ \mathcal{B}_\xi^s (S, \tau) & = & e^{-r \tau} \mathcal{N} \left( s d_0 \right),\\ d_\eta & = & \frac{1}{\sigma \sqrt{\tau}} \left( \ln \left( \frac{S}{\xi} \right) + \left( r - \delta + \left( \eta - \frac{1}{2} \right) \sigma^2 \right) \tau \right),\\ \stackrel{B}{\mathcal{I}} \left\{ \tilde{V}(S, \tau) \right\} & = & \left( \frac{S}{B} \right)^{2 \alpha} \tilde{V} \left( \frac{B^2}{S}, \tau \right),\\ \alpha & = & \frac{1}{2} - \frac{r - \delta}{\sigma^2}. \end{eqnarray}

Here, $\mathcal{A}_\xi^s(S, \tau)$ if the valuation function of an asset binary option that pays off one unit of the underlying asset if $s S_T > s \xi$ where $s \in \{ -1, +1 \}$ indicates a put or call. Similarly, $\mathcal{B}_\xi^s(S, \tau)$ is the valuation function of a bond binary option that pays off one currency unit. $\stackrel{B}{\mathcal{I}}$ is called the image operator.

To get the derivatives, we use that

\begin{eqnarray} \frac{\partial}{\partial S} \mathcal{A}_\xi^s(S, \tau) & = & e^{-\delta \tau} \mathcal{N} \left( s d_1 \right) + s S e^{-\delta \tau} \mathcal{N}' \left( s d_1 \right) \frac{\partial d_1}{\partial S},\\ \frac{\partial}{\partial S} \mathcal{B}_\xi^s(S, \tau) & = & s e^{-r \tau} \mathcal{N}' \left( s d_0 \right) \frac{\partial d_0}{\partial S},\\ \frac{\partial}{\partial S} d_\eta & = & \frac{1}{S \sigma \sqrt{\tau}},\\ \frac{\partial}{\partial S} \stackrel{B}{\mathcal{I}} \left\{ \tilde{V}(S, \tau) \right\} & = & \left( \frac{S}{B} \right)^{2 \alpha} \left( \frac{2 \alpha}{S} \tilde{V} \left( \frac{B^2}{S}, \tau \right) - \frac{B^2}{S^2} \frac{\partial \tilde{V}}{\partial S} \left( \frac{B^2}{S}, \tau \right) \right). \end{eqnarray}

I did not go through the tedious task of checking if this actually agrees with the formula that you referenced.


import numpy
import scipy.stats as stats

def assetBinary1D(maturity, xi, phi, spot, rate, dividend, volatility):
    totalVolatility = volatility * numpy.sqrt(maturity)
    dPlus = (numpy.log(spot / xi) + (rate - dividend + 0.5 * volatility**2) * maturity) / totalVolatility
    dPlusCDF = stats.norm.cdf(phi * dPlus)
    discountFactorDividend = numpy.exp(-dividend * maturity)
    value = spot * discountFactorDividend * dPlusCDF
    derivative = discountFactorDividend * (dPlusCDF + phi * spot * stats.norm.pdf(phi * dPlus) / (spot * totalVolatility))
    return (value, derivative)

def bondBinary1D(maturity, xi, phi, spot, rate, dividend, volatility):
    totalVolatility = volatility * numpy.sqrt(maturity)
    dMinus = (numpy.log(spot / xi) + (rate - dividend - 0.5 * volatility**2) * maturity) / totalVolatility
    discountFactorRate = numpy.exp(-rate * maturity)
    value = discountFactorRate * stats.norm.cdf(phi * dMinus)
    derivative = phi * discountFactorRate * stats.norm.pdf(phi * dMinus) / (spot * totalVolatility)
    return (value, derivative);

def imageOperator(valueFunction, barrier, spot, rate, dividend, volatility):
    alpha = 0.5 - (rate - dividend) / volatility**2
    imageFactor = (spot / barrier)**(2.0 * alpha)
    value, derivative = valueFunction(barrier**2 / spot)
    value2 = imageFactor * value
    derivative2 = imageFactor * (2.0 * alpha / spot * value - (barrier / spot)**2 * derivative)
    return (value2, derivative2)

# attention: only for barriers above the strike!
def downAndOutCall(maturity, strike, barrier, spot, rate, dividend, volatility):
    def valueFunction(spot):
        value, derivative = assetBinary1D(maturity, barrier, 1.0, spot, rate, dividend, volatility)
        value2, derivative2 = bondBinary1D(maturity, barrier, 1.0, spot, rate, dividend, volatility)
        return (value - strike * value2, derivative - strike * derivative2)
    value, derivative = valueFunction(spot)
    value2, derivative2 = imageOperator(valueFunction, barrier, spot, rate, dividend, volatility)
    return (value - value2, derivative - derivative2)

This yields

downAndOutCall(0.2, 1300.0, 1350.0, 1400.0, 0.0, 0.0, 0.2)
>> (65.16660154600855, 1.2863311571074099)


Down-and-out call delta.

The delta is, just like the slope of the payoff function, non-negative everywhere.


Full source code can be found on GitHub.


Buchen, Peter W. (2001) "Image Options and the Road to Barriers," Risk Magazine, Vol. 14, No. 9, pp. 127-130

Zhang, Ally Quan and Matthias Thul (2017) "How Much is the Gap? Efficient Jump-Risk Adjusted Valuation of Leverage Certificates," Quantitative Finance, forthcoming, available on SSRN

  • $\begingroup$ Thank you for these references. I'll need some time to digest. I left out one lil detail. In case the barrier is hit, my barrier option should still pay a rebate which is determined as the difference between barrier and strike. Does this rebate affect the delta (intuitively I think no)? $\endgroup$ – Tim Feb 25 '17 at 13:53
  • $\begingroup$ It does affect the delta. The rebate in isolation is a one-touch binary option which has a non-zero delta. The valuation framework that I referenced is able to handle such rebates - see appendix C. $\endgroup$ – LocalVolatility Feb 25 '17 at 13:56
  • $\begingroup$ I find your paper very interesting and I'm still reading it (which will take a while). Would you mind to include a function for the pay-at-hit-rebate from Proposition 2.1 in the code for illustrative purposes? $\endgroup$ – Tim Feb 25 '17 at 19:14
  • $\begingroup$ Oh I think there's a slight mistake in the formula above. There's a s (or phi as you denote it in the code to differentiate between put and call) missing around the value function. However, this answer is very helpful to me and I would be glad to see the pay-at-hit-rebate. Thank you so much for sharing! $\endgroup$ – Tim Feb 25 '17 at 20:38
  • $\begingroup$ The $s$ is not missing in the valuation function. The notation is probably confusing though. $\mathcal{A}_B^+$ is used to indicate that $\xi = B$ and $s = +1$. Sure - I will add the rebate function later. $\endgroup$ – LocalVolatility Feb 25 '17 at 20:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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