Debugging a Finite Difference Call Option Valuation
Summary
The document presents Python code intended to value a European call or put using a time and asset-price grid. It sets the payoff at expiration, then attempts to step backward through the grid while estimating option sensitivities and applying boundary conditions. The example provides enough detail to identify a key indexing problem: the loop reads column k+1 even though k advances through the final time column, so the access eventually exceeds the grid bounds and raises the shown IndexError.
The code labels its approach implicit, but its update uses values from a future column without first solving the coupled system that an implicit finite-difference method requires. It also refers to global volatility and rate variables rather than the function parameters. These issues mean the example is a debugging prompt, not a validated pricing method; it gives no corrected implementation, convergence evidence, or comparison with a benchmark price.
Key ideas
- The code initializes a payoff grid and attempts to propagate option values across time steps.
- The reported error is caused by an out-of-range time-column access using k+1.
- A genuinely implicit finite-difference update requires solving a system of equations at each time step.
- The function uses global rate and volatility variables instead of its corresponding parameters.
Tags
Full text
# Error in Call Option Valuation using Implicit Finite Difference implemented in Python
# Error in Call Option Valuation using Implicit Finite Difference implemented in Python
I am trying to valuate call option using implicit Finite difference method (Forward Marching) implemented in Python. However I am getting the error in the code. Following is the code I have developed:
```
import pandas as pd
import numpy as np
#Set max row, columns to 200
pd.set_option('max_rows', 200)
pd.set_option('max_columns', 200)
#specify the parameters
#time to maturity
T = 1
#strike price
K = 100
#riskfree rate
r = .05
#volatility
vol = .20
#Flag = 1 for call, -1 for puts
Flag = 1
#number of steps
steps = 20
#asset step size
ds = 2* K / steps
#time step size for stability
dt = (0.9/vol**2/steps**2)
#time steps
time_steps = int(T / dt) + 1
#time step size
dt = T / time_steps
#Create asset steps i*ds
s = np.arange(0,(steps+1)*ds,ds)
#Create time steps k*dt
t = T-np.arange(time_steps*dt,-dt,-dt)
grid = np.zeros((len(s),len(t)))
#Subsume the grid points into a dataframe with asset price as index and time steps as columns
grid = pd.DataFrame(grid, index=s, columns=t)
print(grid)
#Set Final or Initial condition at Expiration
if Flag == 1:
grid.iloc[:,0] = np.maximum(s - K, 0)
else:
grid.iloc[:,0] = np.maximum(K - s, 0)
def implicitFiniteDifference_ForwardMarching(K, Volatility, Rate, TTM, steps, Flag=1):
# Specify Flag as 1 for calls and -1 for puts
ds = 2*K/steps # asset step size
dt = 0.9/Volatility**2/steps**2 # for stability
time_steps = int(TTM / dt) + 1 # time step size
dt = TTM/time_steps # time step
s = np.arange(0,(steps+1)*ds,ds)
t = TTM-np.arange(time_steps*dt,-dt,-dt)
# Initialize the grid with zeros
grid = np.zeros((len(s),len(t)))
grid = pd.DataFrame(grid, index=s, columns=t)
# Set boundary condition at Expiration
grid.iloc[:,0] = np.maximum(Flag * (s - K), 0)
for k in range(1, len(t)):
for i in range(1,len(s)-1):
delta = (grid.iloc[i+1,k+1] - grid.iloc[i-1,k+1]) / (2*ds)
gamma = (grid.iloc[i+1,k+1]-2*grid.iloc[i,k+1]+grid.iloc[i-1,k+1]) / (ds**2)
theta = (-0.5* vol**2 * s[i]**2 * gamma) - (r*s[i]*delta) + (r*grid.iloc[i,k-1])
grid.iloc[i,k] = grid.iloc[i,k-1] - dt*theta
# Set boundary condition at S = 0 and S = infinity
grid.iloc[0,k] = grid.iloc[0,k-1] * (1-r*dt)
grid.iloc[len(s)-1,k] = abs(2*(grid.iloc[len(s)-2,k]) - grid.iloc[len(s)-3,k])
# round grid values to 4 decimal places
return np.around(grid,4)
#Call the function for pricing call
fdmcall = implicitFiniteDifference_ForwardMarching(100,0.2,0.05,1,40,Flag=1)
print(fdmcall)
```
Error starts like this:
```
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-4-9af6f8d89957> in <module>()
90
91 #Call the function for pricing call
---> 92 fdmcall = implicitFiniteDifference_ForwardMarching(100,0.2,0.05,1,40,Flag=1)
93
94 print(fdmcall)
<ipython-input-4-9af6f8d89957> in implicitFiniteDifference_ForwardMarching(K, Volatility, Rate, TTM, steps, Flag)
77 for k in range(1, len(t)):
78 for i in range(1,len(s)-1):
---> 79 delta = (grid.iloc[i+1,k+1] - grid.iloc[i-1,k+1]) / (2*ds)
80 gamma = (grid.iloc[i+1,k+1]-2*grid.iloc[i,k+1]+grid.iloc[i-1,k+1]) / (ds**2)
81 theta = (-0.5* vol**2 * s[i]**2 * gamma) - (r*s[i]*delta) + (r*grid.iloc[i,k-1])
```
then lots of computer-specific stack trace, then:
```
2137 len_axis = len(self.obj._get_axis(axis))
2138 if key >= len_axis or key < -len_axis:
-> 2139 raise IndexError("single positional indexer is out-of-bounds")
2140
2141 def _getitem_tuple(self, tup):
IndexError: single positional indexer is out-of-bounds
```
```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.