2

I have an option pricing model (very simple Black Scholes) that works fine with data in this fashion:

In [18]:
BS2(100.,100.,1.,.001,.3)

Out[18]:
11.96762435837207

the function is here:

Black Sholes Function

def BS2(S,X,T,r,v):
    d1 = (log(S/X)+(.001+v*v/2)*T)/(v*sqrt(T))
    d2 = d1-v*sqrt(T)
    return (S*CND(d1)-X*exp(-.001*T)*CND(d2))

I do not think it matters for this question, but BS2 calls this:

Cumulative normal distribution function

def CND(X):
    (a1,a2,a3,a4,a5) = (0.31938153, -0.356563782, 1.781477937, 
     -1.821255978, 1.330274429)
    L = abs(X)
    K = 1.0 / (1.0 + 0.2316419 * L)
    w = 1.0 - 1.0 / sqrt(2*pi)*exp(-L*L/2.) * (a1*K + a2*K*K + a3*pow(K,3) +
    a4*pow(K,4) + a5*pow(K,5))
    if X<0:
        w = 1.0-w
    return w

I tried to modify the working BS function to accept data from a df but seem to have done something wrong:

def BS(df):
    d1 = (log(S/X)+(.001+v*v/2)*T)/(v*sqrt(T))
    d2 = d1-v*sqrt(T)
    return pd.Series((S*CND(d1)-X*exp(-.001*T)*CND(d2)))

my data is very straight forward:

In [13]:
df

Out[13]:
    S    X   T    r    v
0  100  100  1  0.001  0.3
1   50   50  1  0.001  0.3

and are all float64

In [14]:

df.dtypes
Out[14]:
S    float64
X    float64
T    float64
r    float64
v    float64
dtype: object

I aslo tried assigning the df variables to a name before sending to BS2 (I did this way and without this assignment:

S=df['S']
X=df['X']
T=df['T']
r=df['r']
v=df['v']

at the risk of sending too much info, here is the error message:

In [18]:

BS(df)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-18-745e7dd0eb2c> in <module>()
----> 1 BS(df)

<ipython-input-17-b666a39cd530> in BS(df)
  3 def BS(df):
  4     CallPutFlag='c'
----> 5     d1 = (log(S/X)+(.001+v*v/2)*T)/(v*sqrt(T))
  6     d2 = d1-v*sqrt(T)
  7     cp = ((S*CND(d1)-X*exp(-.001*T)*CND(d2)))

C:\Users\camcompco\AppData\Roaming\Python\Python34\site-   packages\pandas\core\series.py in wrapper(self)
 74             return converter(self.iloc[0])
 75         raise TypeError(
---> 76             "cannot convert the series to {0}".format(str(converter)))
 77     return wrapper
 78 

TypeError: cannot convert the series to <class 'float'>

any assistance would be greatly appreciated.

John

2 Answers 2

1

I think it would be easier to use dataframe.apply()

http://pandas.pydata.org/pandas-docs/dev/generated/pandas.DataFrame.apply.html

then the syntax would be df.apply(func, axis = 1) to apply the function func to each row.

The answer to this question is similar:

Apply function to each row of pandas dataframe to create two new columns

Sign up to request clarification or add additional context in comments.

2 Comments

Hi JohnE, while I think the speed in this particular instance won't be an issue, I do see the need for more efficient code in the future when I am looking at back-testing algorithms. Would you mind elaborating via an simple example, on what you mean? Again, the approach JonD provided is fine for now, just wondering for "knowledge sake". thanks to both of you
Nice answer and I upvoted but one quick caveat: this could be slow on larger datasets. A harder (but more efficient) approach would be to vectorize the functions. @John I added an answer showing this explicitly.
0

@JonD's answer is good, but here's an alternate answer that will be faster if you dataframe has more than a few rows:

from scipy.stats import norm

def BS2(df):
    d1 = (np.log(df.S/df.X)+(.001+df.v*df.v/2)*df['T'])/(df.v*np.sqrt(df['T']))
    d2 = d1-df.v*np.sqrt(df['T'])
    return (df.S*norm.cdf(d1)-df.X*np.exp(-.001*df['T'])*norm.cdf(d2))

Changes:

  1. Main point is to vectorize the function. Syntax-wise the main change is to explicitly use numpy versions of sqrt, log, and exp. Otherwise you don't have to change much because numpy/pandas support basic math operations in an elementwise manner.
  2. Replaced user-written CND with norm.cdf from scipy. Much faster b/c built in functions are almost always as fast as possible.
  3. This is minor, but I went with shortcut notation on df.X and others, but df['T'] needs to be written out since df.T would be interpreted as df.transpose(). I guess this is a good example of why you should avoid the shortcut notation but I'm lazy...

Btw, if you want even more speed, the next thing to try would be to do it in numpy rather than pandas. You could also check if others have already written Black-Scholes functions/libraries (probably, though I don't know anything about it).

1 Comment

Just changed the code to your suggestions, worked like a charm!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.