Matt - 1 year ago 82

Python Question

FIXED: see updated code below.

This is my first Cython attempt and have a working build but it doesn't allow numpy array (vectors) as inputs, which is my real purpose here. It is the Black model (Black Scholes for European option pricing without a dividend). It will only accept length 1 arrays as inputs (if I try to calculate with length 2 arrays it errors:

`TypeError: CyBlack() takes exactly 7 positional arguments (14 given)`

`(70 given)`

`from CyBlack.CyBlack import CyBlack`

`CyBlack(BlackPnL, Black_S, Black_Texpiry, Black_strike, Black_volatility, Black_IR, Black_callput)`

`CyBlack.pyx`

`from numpy cimport ndarray`

cimport numpy as np

cimport cython

cdef extern from "math.h":

double exp(double)

double sqrt(double)

double log(double)

double erf(double)

cdef double std_norm_cdf(double x):

return 0.5*(1+erf(x/sqrt(2.0)))

@cython.boundscheck(False)

cpdef CyBlack(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):

cdef Py_ssize_t i

cdef Py_ssize_t N = BlackPnL.shape[0]

cdef double d1, d2

for i in range(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

Here is the

`setup.py`

`python setup.py build_ext --inplace`

`from distutils.core import setup`

from Cython.Build import cythonize

import numpy

extra_compile_args = ['/EHsc', '/openmp', '/favor:INTEL64']

setup(

ext_modules=cythonize("CyBlack.pyx"),

include_dirs=['.', numpy.get_include()],

extra_compile_args=extra_compile_args)

The above compiles and works after using the fix on the variable type (Black_callput was actually an

`int64`

Answer Source

There were two issues here:

`TypeError: CyBlack() takes exactly 7 positional arguments (14 given)`

This was caused by the fact that you were unpacking your input arrays using the

`*`

("splat") operator. You needed to pass them in as 7 separate arguments instead.`ValueError: Buffer dtype mismatch, expected 'float64_t' but got 'long long'`

:This error was telling you that one of the input arrays had a C type of

`long long`

(which is a 64 bit integer), rather than`float64_t`

as specified in your input type declarations. You needed to cast all of your input arrays to`np.float64`

.