Skip to content
All library documents

Debugging Discrete Asian Option Pricing Against a Vendor Model

Article Quant Q&A · Author: reidungsplid

Summary

The document describes an attempt to reproduce a vendor price for a discrete arithmetic average price Asian call using the Haug, Haug and Margrabe approximation and Curran’s approximation. It lays out the inputs, reports the author’s calculated values and the vendor’s differing value, and includes VBA implementing the arithmetic Asian approximations and generalized Black–Scholes pricing. The central lesson from the answer is to validate the implementation methodically rather than infer the cause from one price comparison.

Suggested checks include reproducing a discrete geometric Asian formula from an established reference implementation and pricing text before returning to the more involved arithmetic case. The answer also recommends boundary tests such as zero volatility, a very short averaging period, and deep out-of-the-money options to check limiting behavior. The post does not identify the specific source of the discrepancy or establish which price is correct; differences may reflect code errors, model interpretation, or differing assumptions, and vendor implementation details are unavailable.

Key ideas

  • A single mismatch does not establish whether the implementation or the vendor assumptions are responsible.
  • Validate analytical geometric Asian pricing against a trusted reference before debugging arithmetic approximations.
  • Boundary cases can reveal errors by checking whether the option converges to known limiting behavior.
  • The supplied VBA contains both Asian approximations and generalized Black–Scholes calculations for comparison.

Tags

Full text
# Wrong pricing of Asian Option


# Wrong pricing of Asian Option












Issue short: I have values for Asian Options which I'm trying to replicate using a self-build vba calculator. The values I have to hit is from FinCAD and I'm using a discrete arithmetic average rate option based on Haug, Haug and Margrabe and also trying the Curran version (implemented in VBA). All code below:

More information: I'm sure we calculate using the informations differently since my value is quite different from he's. Underneath is the exact input used:

- Asian Call Option (average price not strike)





- Underlying price (per 05-04-2017): 515.25







I use working days (in my country) so:

- Time to next average point (t1): 15 days (from 06-04-2017 to 01-05-2017)

- Time to maturity (T): 35 days (from 06-04-2017 to 31-05-2017)

My values (after using 252):

- Asian Value (Haug, Haug and Margrabe): 12.7763

- Asian Value (Curran): 12.7753



He's value:

- 18.64

I simply can't understand the difference. It's not just about the days used. Maybe it's the volatility. Also because my BS European value is lower than he's value and that should not be the case. I have also validated my values according to free available calculators on www. I just got the info that FinCAD is using their function, aaGeo_Asian, so I tried a geometric version but still don't get they numbers. I do not have information on the specifics in their function. However it could look like they also use projected future values and not "just" the current price of the underlying.

```
Public Function DiscreteAsianHHM(runFlag As String, CallPutFlag As String, 
TimeFlag As String, ContinuousFlag As String, S As Double, SA As Double, X 
As Double, _
          input_t1 As Double, input_t As Double, n As Double, m As Double, 
input_r As Double, input_b As Double, v As Double) As Double

Dim d1 As Double, d2 As Double, h As Double, EA As Double, EA2 As Double
Dim vA As Double, OptionValue As Double
Dim t1 As Double, T As Double
Dim r As Double, b As Double

'Making sure of the chosen input time (years/days)
t1 = TimeConvert(TimeFlag, input_t1)
T = TimeConvert(TimeFlag, input_t)

'Converting to continious compounding rate
r = CCRConvert(ContinuousFlag, input_r)
b = CCRConvert(ContinuousFlag, input_b)

' Calculate either Asian (A) or plain European (E) by BS formula
If runFlag = "A" Then

    h = (T - t1) / (n - 1)

    If b = 0 Then
        EA = S
    Else
        EA = S / n * Exp(b * t1) * (1 - Exp(b * h * n)) / (1 - Exp(b * h))
    End If

   'If we are in the averaging period and way ITM
    If m > 0 Then
        If SA > n / m * X Then   ' Exercise is certain for call, put must be 
    out-of-the-money

            If CallPutFlag = "Put" Then
                DiscreteAsianHHM = 0
            ElseIf CallPutFlag = "Call" Then
                SA = SA * m / n + EA * (n - m) / n
                DiscreteAsianHHM = (SA - X) * Exp(-r * T)
            End If
            Exit Function

       End If
    End If

    If m = n - 1 Then ' Only one fix left use Black-Scholes weighted with 
    time

         X = n * X - (n - 1) * SA
         DiscreteAsianHHM = GBlackScholes(CallPutFlag, S, X, T, r, b, v) * 1 
         / n
         Exit Function
    End If

    If b = 0 Then
         EA2 = S * S * Exp(v * v * t1) / (n * n) _
            * ((1 - Exp(v * v * h * n)) / (1 - Exp(v * v * h)) _
           + 2 / (1 - Exp(v * v * h)) * (n - (1 - Exp(v * v * h * n)) / (1 - 
    Exp(v * v * h))))
    Else

         EA2 = S * S * Exp((2 * b + v * v) * t1) / (n * n) _
            * ((1 - Exp((2 * b + v * v) * h * n)) / (1 - Exp((2 * b + v * v) 
         * h)) _
            + 2 / (1 - Exp((b + v * v) * h)) * ((1 - Exp(b * h * n)) / (1 - 
          Exp(b * h)) _
            - (1 - Exp((2 * b + v * v) * h * n)) / _
            (1 - Exp((2 * b + v * v) * h))))
    End If

    vA = Sqr((Log(EA2) - 2 * Log(EA)) / T)

    OptionValue = 0

    'If we are in the averaging period we need to adjust the strike price
    If m > 0 Then
        X = n / (n - m) * X - m / (n - m) * SA
    End If

    d1 = (Log(EA / X) + vA ^ 2 / 2 * T) / (vA * Sqr(T))
    d2 = d1 - vA * Sqr(T)

    If CallPutFlag = "Call" Then
        OptionValue = Exp(-r * T) * (EA * CND(d1) - X * CND(d2))
    ElseIf (CallPutFlag = "Put") Then
        OptionValue = Exp(-r * T) * (X * CND(-d2) - EA * CND(-d1))
    End If

    DiscreteAsianHHM = OptionValue * (n - m) / n
    ElseIf runFlag = "E" Then
    'Generalized BS model
    DiscreteAsianHHM = GBlackScholes(CallPutFlag, S, X, T, r, b, v)
    End If

    End Function

Public Function TimeConvert(TimeFlag As String, input_t As Double) As Double

If TimeFlag = "Days" Then
    TimeConvert = input_t / 252
Else
    TimeConvert = input_t
End If

End Function

'The generalized Black and Scholes formula
 Public Function GBlackScholes(CallPutFlag As String, S As Double, X _
            As Double, T As Double, r As Double, b As Double, v As Double) 
 As Double

Dim d1 As Double, d2 As Double
'I thought this was a mistake but note that q=r-b. r is risk free rate, b is 
 cost of carry and q is dividend
d1 = (Log(S / X) + (b + v ^ 2 / 2) * T) / (v * Sqr(T))
d2 = d1 - v * Sqr(T)

If CallPutFlag = "Call" Then
    GBlackScholes = S * Exp((b - r) * T) * CND(d1) - X * Exp(-r * T) * CND(d2)
ElseIf CallPutFlag = "Put" Then
    GBlackScholes = X * Exp(-r * T) * CND(-d2) - S * Exp((b - r) * T) * CND(-d1)
End If

End Function

Public Function CCRConvert(ContinuousFlag As String, rate As Double) As 
Double

If ContinuousFlag = "Continuous" Then
    CCRConvert = rate
ElseIf ContinuousFlag = "Annual" Then
    CCRConvert = Log(1 + rate)
ElseIf ContinuousFlag = "Semi-annual" Then
    CCRConvert = 2 * Log(1 + rate / 2)
ElseIf ContinuousFlag = "Quarterly" Then
    CCRConvert = 4 * Log(1 + rate / 4)
ElseIf ContinuousFlag = "Monthly" Then
    CCRConvert = 12 * Log(1 + rate / 12)
ElseIf ContinuousFlag = "Daily" Then
    CCRConvert = 252 * Log(1 + rate / 252)
End If

End Function

'Using the build in cummulative normal distribution
 Function CND(X As Double) As Double
 CND = WorksheetFunction.Norm_Dist(X, 0, 1, True)
 End Function
```

## Answer by SmallChess (score 1)

https://quant.stackexchange.com/a/34045

Not possible for us to debug your code to find out the cause. Possible reasons:

- You have a bug

- You don't have a bug but your understanding of the model is incorrect

- Both your code and FinCAD are correct, the difference is due to assumptions

I don't think FinCAD would make a mistake in such simple model, they have a team of PhD quants for model validation.

I should share with you what I'd do if I were you:

- You mentioned you failed to replicate for geometric Asian option. Are you talking about Haug, Haug and Margrable? It's just an analytical formula, so there shouldn't be an issue. Check QuantLib's implementation at: https://github.com/lballabio/QuantLib/blob/9618244fde50546b3ee813dfed76937b01058586/ql/pricingengines/asian/analytic_discr_geom_av_price.cpp. Can you use the code replicate your results and FinCAD?

- Check your analytical geometric Asian with "Complete Guide To Option Pricing". I post a screenshot of the book for you. The book has a pseudocode for you to compare your results. You should not expect to replicate FinCAD if you can't replicate the book. Similarly, the book has a section for Curran's Approximation.

- When you test a model, try off with boundary conditions. Don't use normal values until your code works with boundary conditions. Possible ideas: deep out-of-the call, shorten your average period to very small upon maturity (European option), zero volatility, zero risk-free rate etc. Make sure your option value is zero if there's no hope of exercising. Make sure your option behaves like a spot if there's absolutely chance of exercising.

- Once you can fix your code for discrete geometric, you can then move on to more complicated arithmetic.

Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.