1

ORIGINAL ERROR FOUND -> from CyBlack.CyBlack import CyBlack then pass *numpy_value as inputs. A new issue has arisen so creating a new post for that. Cython program with numpy arrays does not allow vectorized inputs (only accepts length 1 arrays), how to fix?

I am new to Cython and tried converting the Black (Black Scholes without a stock dividend) over from Python to Cython. After getting it to compile, it doesn't let me actually use the function. I'm sure someone with more experience can look at this easily and figure out why. The error I get after compiling and importing the function from CyBlack import CyBlack and calling CyBlack(BlackPnL, Black_S, Black_Texpiry, Black_strike, Black_volatility, Black_IR, Black_callput) is TypeError: 'module' object is not callable: So here's the code:

from numpy cimport ndarray
cimport numpy as np
cimport cython

cdef extern from "math.h":
    double exp(double)
    double sqrt(double)
    double pow(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)
cdef 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.float64_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

Thanks for any help here! I can post python fake data if you need something to test off of - although just calling it with any data will expose the error... Something points me to the variables not being exposed to Python from the C code.

Adding my setup.py here so others can build this typing: python setup.py build_ext --inplace built with VS2015 for Python 3.5 64bit Windows.

from distutils.core import setup
from Cython.Build import cythonize

setup(ext_modules = cythonize("CyBlack.pyx"), include_dirs =["C://Program Files (x86)//Microsoft Visual Studio 14.0//VC//include", "C://Program Files (x86)//Windows Kits//10//Include//10.0.1.0240.0//ucrt", "C://Program Files (x86)//Microsoft Visual Studio 14.0//VC//lib//amd64", "C://Anaconda3//Lib//site-packages//numpy//core//include", "C://Program Files (x86)//Microsoft Visual Studio 14.0//VC//lib//amd64"])
6
  • It sounds like this CyBlack module might actually be embedded in a CyBlack package. Your CyBlack function is cdef'ed instead of cpdef'ed, so it's not going to be accessible through any Python import. Commented May 10, 2016 at 23:53
  • I cpdef'd it and still the same issue... Commented May 11, 2016 at 0:07
  • Could you post the result of from CyBlack import CyBlack; print(CyBlack.__file__)? This should output the path to the module causing the error. Commented May 11, 2016 at 1:01
  • What's your directory structure (i.e. is your module in a directory called cyBlack)? Commented May 11, 2016 at 7:53
  • Yes in a directory called CyBlack. It imports without error it just doesn't let you send arguments to the function Commented May 11, 2016 at 12:49

2 Answers 2

2

I managed to get (something like it) working in the following way:

C:/dev/tmp/CyBlack/
                   __init__.py
                   setup.py
                   CyBlack.pyx

Where CyBlack.pyx is just like yours, except with CyBlack function being cpdef'd. setup.py contains:

from distutils.core import setup
import numpy
from Cython.Build import cythonize

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

setup(
    ext_modules=cythonize("CyBlack.pyx"),
    include_dirs=['.', numpy.get_include()],
    extra_compile_args=extra_compile_args
)

Running then:

C:\dev\tmp\CyBlack> python .\setup.py build_ext --compiler=msvc --inplace

Will produce C:/dev/tmp/CyBlack/CyBlack.pyd, and I then managed to run the code from Python:

>>> from sys import path
>>> path.insert(0, "C:/dev/tmp")
>>> from CyBlack.CyBlack import CyBlack
>>> CyBlack(*[np.array([1.0]) for _ in xrange(7)]) # I'm too lazy to put proper values here...
array([ 0.14087021])

This was done with Python 2.7, and overall setup might be slightly different, but hopefully, that might help you getting a minimum working example and trace back how to make yours run correctly.

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

3 Comments

thank you for posting the running example. I actually found the buried module at the same time you did coincidentally. The only issue now is that the function is not allowing numpy vectors to be processed (kind of defeats the purpose of having an internal loop) as I thought that was the point of declaring numpy array types in the cython block.
I had issues passing in nd vectors as well, which I suspect come from the use of the C log and sqrt rather than the (vectorised) numpy ones; not sure if this is what is causing it
I added the [i] indexing to the code above which should allow 1 value at a time to be passed to log and sqrt, but no help. Thinking I've changed this into another question and should just accept your answer and repost part 2...
-2

Instead of

from CyBlack import CyBlack

Why don't you just do

import CyBlack

?

2 Comments

That's actually what I tried first... doesn't work.
I'm guessing there's probably a submodule/function called CyBlack inside the CyBlack module. Therefore, if you just did import CyBlack then you would probably need to use CyBlack.CyBlack() whenever you wanted to use it in the code, if it is in fact a function.

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.