Skip to content Skip to sidebar Skip to footer

Cython Program Is Slower Than Plain Python (10m Options 3.5s Vs 3.25s Black Scholes) - What Am I Missing?

Okay here's my first Cython program below, the code to price European options on futures (Black Scholes without a dividend). It runs in 3.5s on 10M options, versus the code I post

Solution 1:

I added the following lines before your functions in your cython code and I got a faster result from Cython than Python 2.7

@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)

My results for 10M points

%timeit PyBlack(BlackPnL, Black_S, Black_Texpiry, Black_strike, Black_volatility, Black_IR, Black_callput)
1 loops, best of 3: 3.49 s per loop

and

%timeit CyBlack(BlackPnL, Black_S, Black_Texpiry, Black_strike, Black_volatility, Black_IR, Black_callput)
1 loops, best of 3: 2.12 s per loop

EDIT

CyBlack.pyx

from numpy cimport ndarray
cimport numpy as np
cimport cython

cdefexternfrom"math.h":
    double exp(double)
    double sqrt(double)
    double log(double)
    double fabs(double)

cdefdouble a1 = 0.254829592
cdefdouble a2 = -0.284496736
cdefdouble a3 =  1.421413741
cdefdouble a4 = -1.453152027
cdefdouble a5 =  1.061405429
cdefdouble p =  0.3275911@cython.boundscheck(False)@cython.wraparound(False)@cython.cdivision(True)
cdefinline double erf(double x):
    cdefint sign = 1if (x < 0):
        sign = -1
    x = fabs(x)

    cdefdouble t = 1.0/(1.0 + p*x)
    cdefdouble y = 1.0 - (((((a5*t + a4)*t) + a3)*t + a2)*t + a1)*t*exp(-x*x)

    return sign*y

@cython.boundscheck(False)@cython.wraparound(False)@cython.cdivision(True)
cdefdouble std_norm_cdf(double x):
    return0.5*(1+erf(x/sqrt(2.0)))

@cython.boundscheck(False)@cython.wraparound(False)@cython.cdivision(True)
cpdefCyBlack(ndarray[np.float64_t, ndim=1] BlackPnL, ndarray[np.float64_t, ndim=1] Black_S, ndarray[np.float64_t, ndim=1] Black_Texpiry, ndarray[np.float64_t, ndim=1] Black_strike, ndarray [np.float64_t, ndim=1] Black_volatility, ndarray[np.float64_t, ndim=1] Black_IR, ndarray[np.int64_t, ndim=1] Black_callput):

    cdefPy_ssize_t i
    cdefPy_ssize_t N = BlackPnL.shape[0]
    cdefdouble d1, d2


    for i inrange(N):
        d1 = ((log(Black_S[i] / Black_strike[i]) + Black_Texpiry[i] * Black_volatility[i] **2 / 2)) / (Black_volatility[i] * sqrt(Black_Texpiry[i]))
        d2 = d1 - Black_volatility[i] * sqrt(Black_Texpiry[i])
        BlackPnL[i] = exp(-Black_IR[i] * Black_Texpiry[i]) * (Black_callput[i] * Black_S[i] * std_norm_cdf(Black_callput[i] * d1) - Black_callput[i] * Black_strike[i] * std_norm_cdf(Black_callput[i] * d2)) 

    return BlackPnL

setup.py

try:
    from setuptools import setup
    from setuptools import Extension
except ImportError:
    from distutils.core import setup
    from distutils.extension import Extension

from Cython.Distutils import build_ext
import numpy as np

ext_modules = [Extension("CyBlack",["CyBlack.pyx"])]

setup(
    name= 'Generic model class',
    cmdclass = {'build_ext': build_ext},
    include_dirs = [np.get_include()],
    ext_modules = ext_modules)

Post a Comment for "Cython Program Is Slower Than Plain Python (10m Options 3.5s Vs 3.25s Black Scholes) - What Am I Missing?"