QuantLib Asian Option Engines: Finite Differences and Monte Carlo
Summary
The discussion compares QuantLib pricing approaches for geometric and arithmetic Asian options. It reports that the finite-difference Black–Scholes Asian engine supports discrete arithmetic averaging, not continuous geometric averaging. A discrete geometric option sampled frequently can approximate the continuous geometric contract, and the cited example reports close agreement between the analytic continuous-price engine and that discrete approximation. The finite-difference engine, however, rejects geometric averaging; switching to arithmetic averaging changes the contract and can materially change its price.
For a numerical geometric-price alternative, the answer suggests Monte Carlo pricing of a discrete geometric Asian option, again noting that it produces a value close to the analytic continuous-geometric result in the example. Another user’s code encounters a type error when constructing the Monte Carlo engine with a string random-number-generator setting; the excerpt gives no resolution to that error. The results are implementation guidance, not a general accuracy study, and the close approximation depends on the sampling setup and model assumptions.
Key ideas
- The described QuantLib finite-difference Asian engine supports discrete arithmetic averaging, not geometric averaging.
- Frequent discrete fixing dates can approximate continuous geometric averaging in the example.
- Changing from geometric to arithmetic averaging changes the payoff and may change the price substantially.
- Monte Carlo pricing of a discrete geometric Asian is offered as a numerical alternative.
- The reported price agreement is example-specific, and the separate constructor type error remains unresolved.
Tags
Full text
# Unable to find Price of Asian Option using Explicit Finite Difference Method by implementing QuantLib in Python
# Unable to find Price of Asian Option using Explicit Finite Difference Method by implementing QuantLib in Python
I am trying to find price of Continuous Geometric Average Asian Option using Finite Difference methodology in QuantLib Python. I am unable to do so. However, I am able to find price of the same option using closed form solution. Here is the code:
```
import QuantLib as ql
today = ql.Settings.instance().evaluationDate
averageType = ql.Average.Geometric
option_type = ql.Option.Call
strike = 100.0
exerciseDate = ql.TARGET().advance(today, 90, ql.Days)
payoff = ql.PlainVanillaPayoff(option_type, strike)
exercise = ql.EuropeanExercise(exerciseDate)
option = ql.ContinuousAveragingAsianOption(averageType, payoff, exercise)
initialValue = ql.QuoteHandle(ql.SimpleQuote(100))
sigma = 0.3
riskFreeTS = ql.YieldTermStructureHandle(ql.FlatForward(today, 0.03, ql.Actual365Fixed()))
volTS = ql.BlackVolTermStructureHandle(ql.BlackConstantVol(today, ql.NullCalendar(), sigma, ql.Actual365Fixed()))
stochProcess = ql.BlackScholesProcess(initialValue, riskFreeTS, volTS)
engine = ql.AnalyticContinuousGeometricAveragePriceAsianEngine(stochProcess)
option.setPricingEngine(engine)
price = option.NPV()
print(f"Option price: {price}")
```
Any help/advice would be greatly appreciated!!
## Answer by StackG (score 3, accepted)
https://quant.stackexchange.com/a/57754
QuantLib does have an FD pricing engine for asian options `ql.FdBlackScholesAsianEngine(stochProcess, tGrid=100, xGrid=100, aGrid=50)`, but I've just discovered it only prices Discrete, Arithmetic payoffs!
Moving from Continuous to Discrete (documented here) doesn't change the price of the option much, if you pass in something like `asianFixingDates = [ql.TARGET().advance(today, x, ql.Days) for x in range(1,91)]` which samples every day. Of course, this is a bit unrealistic, but it's good that we recover the continuous price from the analytic pricer in that limit (I get 4.187 vs. 4.184 from the original code when I make this change).
Unfortunately, running the FD pricer on this option gives me this error: `RuntimeError: Arithmetic averaging supported only`
Moving to an arithmetic averaging option does impact pricing significantly. However, in case that is of any use to you, I've included the changes required to your code at the bottom of this answer (changing the averaging to `ql.Average.Arithmetic`, and using a discrete option)
As an alternative if you need a numerical solver, you might consider `ql.MCDiscreteGeometricAPEngine` (documented here) which uses Monte Carlo instead to price the geometric option. You'll still need to price the discrete averaging option, but the price comes out very close to the analytic solution using something like this:
```
rng = "lowdiscrepancy" # could use "pseudorandom"
numPaths = 100000
engine = ql.MCDiscreteGeometricAPEngine(stochProcess, rng, requiredSamples=numPaths)
option.setPricingEngine(engine)
price = option.NPV()
print(f"Option price: {price}")
```
Price a discrete-averaging arithmetic asian using FD in QL:
```
import QuantLib as ql
today = ql.Settings.instance().evaluationDate
averageType = ql.Average.Arithmetic
option_type = ql.Option.Call
strike = 100.0
exerciseDate = ql.TARGET().advance(today, 90, ql.Days)
pastFixings = 0 # Empty because this is a new contract
asianFixingDates = [ql.TARGET().advance(today, x, ql.Days) for x in range(1,91)]
payoff = ql.PlainVanillaPayoff(option_type, strike)
exercise = ql.EuropeanExercise(exerciseDate)
option = ql.DiscreteAveragingAsianOption(averageType, 0.0, pastFixings, asianFixingDates, payoff, exercise)
initialValue = ql.QuoteHandle(ql.SimpleQuote(100))
sigma = 0.3
riskFreeTS = ql.YieldTermStructureHandle(ql.FlatForward(today, 0.03, ql.Actual365Fixed()))
volTS = ql.BlackVolTermStructureHandle(ql.BlackConstantVol(today, ql.NullCalendar(), sigma, ql.Actual365Fixed()))
stochProcess = ql.BlackScholesProcess(initialValue, riskFreeTS, volTS)
engine = ql.FdBlackScholesAsianEngine(stochProcess, tGrid=100, xGrid=100, aGrid=50)
option.setPricingEngine(engine)
price = option.NPV()
print(f"Option price: {price}")
```
## Answer by Desi_Quant (score 1)
https://quant.stackexchange.com/a/57757
Using MC Simulation, if I am trying to price Geometric Average Asian Option by running the following code:
```
import QuantLib as ql
today = ql.Settings.instance().evaluationDate
averageType = ql.Average.Geometric
option_type = ql.Option.Call
strike = 100.0
exerciseDate = ql.TARGET().advance(today, 90, ql.Days)
pastFixings = 0 # Empty because this is a new contract
asianFixingDates = [ql.TARGET().advance(today, x, ql.Days) for x in range(1,91)]
payoff = ql.PlainVanillaPayoff(option_type, strike)
exercise = ql.EuropeanExercise(exerciseDate)
option = ql.DiscreteAveragingAsianOption(averageType, 0.0, pastFixings, asianFixingDates, payoff, exercise)
initialValue = ql.QuoteHandle(ql.SimpleQuote(100))
sigma = 0.3
riskFreeTS = ql.YieldTermStructureHandle(ql.FlatForward(today, 0.03, ql.Actual365Fixed()))
volTS = ql.BlackVolTermStructureHandle(ql.BlackConstantVol(today, ql.NullCalendar(), sigma, ql.Actual365Fixed()))
process = ql.BlackScholesProcess(initialValue, riskFreeTS, volTS)
steps = 2
rng = "lowdiscrepancy"
numPaths = 500000
engine = ql.MCDiscreteGeometricAPEngine(process, rng, steps, requiredSamples=numPaths)
option.setPricingEngine(engine)
price = option.NPV()
print(f"Option price: {price}")
```
I am getting the following error:
```
runfile('C:/Users/nitin.kapai/Documents/Exam_v1/QuantLib Code/Asian_Discrete_Geometric_MC_Simulation_QuantLib.py', wdir='C:/Users/nitin.kapai/Documents/Exam_v1/QuantLib Code')
Traceback (most recent call last):
File "C:\Users\nitin.kapai\Documents\Exam_v1\QuantLib Code\Asian_Discrete_Geometric_MC_Simulation_QuantLib.py", line 34, in <module>
engine = ql.MCDiscreteGeometricAPEngine(process, rng, steps, requiredSamples=numPaths)
File "C:\Users\nitin.kapai\Anaconda3\lib\site-packages\QuantLib\QuantLib.py", line 12996, in MCDiscreteGeometricAPEngine
seed)
File "C:\Users\nitin.kapai\Anaconda3\lib\site-packages\QuantLib\QuantLib.py", line 12968, in __init__
_QuantLib.MCLDDiscreteGeometricAPEngine_swiginit(self, _QuantLib.new_MCLDDiscreteGeometricAPEngine(*args, **kwargs))
TypeError: in method 'new_MCLDDiscreteGeometricAPEngine', argument 2 of type 'bool'
```
```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.