Skip to content

Merge all extensitons into one extension #132

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 5, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -2,8 +2,10 @@ docs/html
docs/.tadoc.org.html

*.pyc
build
build/
dist/
*.so
.*
*~
*.egg-info/

24 changes: 12 additions & 12 deletions DEVELOPMENT
Original file line number Diff line number Diff line change
@@ -12,34 +12,34 @@ Here's the full list of make commands (see the Makefile file):
make build # builds and places libs in the project directory; required for testing
make clean # cleans the local build files
make install # installs talib system-wide
make generate: # generates a fresh func.pyx file. Requires talib and TA-Lib to both be installed
make generate: # generates a fresh _func.pxi, _stream.pxi file. Requires talib and TA-Lib to both be installed
make perf # run performance profiling
make test # run tests

The source code is comprised of one python package, located in the talib
directory, which itself has three Cython modules: func, abstract, and
common.
directory, which itself has one Cython module (_ta_lib) which consists of
four parts: _common, _func, _abstract and _stream.

talib/common.pyx
An internal-use module for functionality shared between func and abstract.
talib/_common.pxi
An internal-use file for functionality shared between func and abstract.

talib/func.pyx
This file is generated automatically by tools/generate.py and any changes made
talib/_func.pxi
This file is generated automatically by tools/generate_func.py and any changes made
to it directly will get overwritten!

talib/abstract.pyx
talib/_abstract.pxi
This file contains the code for interfacing with the TA-Lib abstract interface
and wrapping it into a pythonic Function class.

talib/libta_lib.pxd
talib/_ta_lib.pyx
This "Cython header file" defines the C-level functions, variables and types we
need to use in the above pyx files.

talib/stream.pyx
talib/_stream.pxi
This file contains code for interfacing a "streaming" interface to TA-Lib.

tools/generate.py
A script that generates and prints func.pyx to stdout. Gets information
tools/generate_func.py,generate_stream.py
Scripts that generate and print _func.pxi or _stream.pxi to stdout. Gets information
about all functions from the C headers of the installed TA-Lib.

If you are interested in developing new indicator functions or whatnot on
11 changes: 9 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
.PHONY: build

build:
python setup.py build_ext --inplace

install:
python setup.py install

generate:
python tools/generate_func.py > talib/func.pyx
talib/_func.pxi: tools/generate_func.py
python tools/generate_func.py > talib/_func.pxi

talib/_stream.pxi: tools/generate_stream.py
python tools/generate_stream.py > talib/_stream.pxi

generate: talib/_func.pxi talib/_stream.pxi

clean:
rm -rf build talib/func*.so talib/abstract*.so talib/common*.so talib/stream*.so talib/*.pyc
17 changes: 8 additions & 9 deletions setup.py
Original file line number Diff line number Diff line change
@@ -80,16 +80,15 @@
if has_cython:
cmdclass['build_ext'] = build_ext

ext_modules = []
for name in ['common', 'func', 'abstract', 'stream']:
ext = Extension(
'talib.%s' % name,
[('talib/%s.pyx' if has_cython else 'talib/%s.c') % name],
include_dirs = include_dirs,
library_dirs = lib_talib_dirs,
libraries = [lib_talib_name]
ext_modules = [
Extension(
'talib._ta_lib',
['talib/_ta_lib.pyx' if has_cython else 'talib/_ta_lib.c'],
include_dirs=include_dirs,
library_dirs=lib_talib_dirs,
libraries=[lib_talib_name]
)
ext_modules.append(ext)
]

setup(
name = 'TA-Lib',
21 changes: 12 additions & 9 deletions talib/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@

import atexit

from . import common
from . import abstract
from . import stream
from .common import MA_Type, __ta_version__
from .common import _ta_set_unstable_period as set_unstable_period
from .common import _ta_get_unstable_period as get_unstable_period
from .func import *
from ._ta_lib import (
_ta_initialize, _ta_shutdown, MA_Type, __ta_version__,
_ta_set_unstable_period as set_unstable_period,
_ta_get_unstable_period as get_unstable_period,
__TA_FUNCTION_NAMES__
)

func = __import__("_ta_lib", globals(), locals(), __TA_FUNCTION_NAMES__, level=1)
for func_name in __TA_FUNCTION_NAMES__:
globals()[func_name] = getattr(func, func_name)

__version__ = '0.4.10'

@@ -18,8 +21,8 @@
# functions are called. Finally, when the python process exits, we shutdown
# the underlying TA-Lib.

common._ta_initialize()
atexit.register(common._ta_shutdown)
_ta_initialize()
atexit.register(_ta_shutdown)

__function_groups__ = {
'Cycle Indicators': [
23 changes: 5 additions & 18 deletions talib/abstract.pyx → talib/_abstract.pxi
Original file line number Diff line number Diff line change
@@ -2,9 +2,6 @@
This file Copyright (c) 2013 Brian A Cappello <briancappello at gmail>
'''
import math

from . import func as func_c
from .common import _ta_check_success, MA_Type
try:
from collections import OrderedDict
except ImportError: # handle python 2.6 and earlier
@@ -14,11 +11,9 @@ import numpy
import sys

cimport numpy as np
cimport libta_lib as lib

lib.TA_Initialize()
cimport _ta_lib as lib
# NOTE: _ta_check_success, MA_Type is defined in _common.pxi

__FUNCTION_NAMES = set(func_c.__all__)

__INPUT_ARRAYS_DEFAULTS = {'open': None,
'high': None,
@@ -90,11 +85,9 @@ class Function(object):
- FunctionInstance([input_arrays,] [param_args_andor_kwargs]) # calls set_function_args and returns self.outputs
"""

def __init__(self, function_name, *args, **kwargs):
def __init__(self, function_name, func_object, *args, **kwargs):
# make sure the function_name is valid and define all of our variables
self.__name = function_name.upper()
if self.__name not in __FUNCTION_NAMES:
raise Exception('%s not supported by TA-LIB.' % self.__name)
self.__namestr = self.__name
self.__name = str2bytes(self.__name)
self.__info = None
@@ -109,6 +102,7 @@ class Function(object):
# finish initializing: query the TALIB abstract interface and set arguments
self.__initialize_function_info()
self.set_function_args(*args, **kwargs)
self.func_object = func_object

def __initialize_function_info(self):
# function info
@@ -386,7 +380,7 @@ class Function(object):
args.append(value)

# Use the func module to actually call the function.
results = func_c.__getattribute__(self.__namestr)(*args)
results = self.func_object(*args)
if isinstance(results, np.ndarray):
keys = self.__outputs.keys()
if not isinstance(keys, list):
@@ -682,10 +676,3 @@ cdef int __ta_getLookback(lib.TA_ParamHolder *holder):
retCode = lib.TA_GetLookback(holder, &lookback)
_ta_check_success('TA_GetLookback', retCode)
return lookback

# Configure all the available TA-Lib functions to be exported as
# an abstract function wrapper for convenient import.
for name in __FUNCTION_NAMES:
exec "%s = Function('%s')" % (name, name)

__all__ = ['Function'] + list(__FUNCTION_NAMES)
5 changes: 2 additions & 3 deletions talib/common.pyx → talib/_common.pxi
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@

cimport libta_lib as lib
from libta_lib cimport TA_RetCode, TA_FuncUnstId
cimport _ta_lib as lib
from _ta_lib cimport TA_RetCode, TA_FuncUnstId

__ta_version__ = lib.TA_GetVersionString()

9 changes: 4 additions & 5 deletions talib/func.pyx → talib/_func.pxi
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ cimport numpy as np
from numpy import nan
from cython import boundscheck, wraparound

from .common cimport _ta_check_success
# _ta_check_success: defined in _common.pxi

cdef double NaN = nan

@@ -14,10 +14,9 @@ cdef extern from "numpy/arrayobject.h":

np.import_array() # Initialize the NumPy C API

cimport libta_lib as lib
from libta_lib cimport TA_RetCode
cimport _ta_lib as lib
from _ta_lib cimport TA_RetCode

lib.TA_Initialize()

@wraparound(False) # turn off relative indexing from end of lists
@boundscheck(False) # turn off bounds-checking for entire function
@@ -11243,4 +11242,4 @@ def WMA( np.ndarray real not None , int timeperiod=-2**31 ):
_ta_check_success("TA_WMA", retCode)
return outreal

__all__ = ["ACOS","AD","ADD","ADOSC","ADX","ADXR","APO","AROON","AROONOSC","ASIN","ATAN","ATR","AVGPRICE","BBANDS","BETA","BOP","CCI","CDL2CROWS","CDL3BLACKCROWS","CDL3INSIDE","CDL3LINESTRIKE","CDL3OUTSIDE","CDL3STARSINSOUTH","CDL3WHITESOLDIERS","CDLABANDONEDBABY","CDLADVANCEBLOCK","CDLBELTHOLD","CDLBREAKAWAY","CDLCLOSINGMARUBOZU","CDLCONCEALBABYSWALL","CDLCOUNTERATTACK","CDLDARKCLOUDCOVER","CDLDOJI","CDLDOJISTAR","CDLDRAGONFLYDOJI","CDLENGULFING","CDLEVENINGDOJISTAR","CDLEVENINGSTAR","CDLGAPSIDESIDEWHITE","CDLGRAVESTONEDOJI","CDLHAMMER","CDLHANGINGMAN","CDLHARAMI","CDLHARAMICROSS","CDLHIGHWAVE","CDLHIKKAKE","CDLHIKKAKEMOD","CDLHOMINGPIGEON","CDLIDENTICAL3CROWS","CDLINNECK","CDLINVERTEDHAMMER","CDLKICKING","CDLKICKINGBYLENGTH","CDLLADDERBOTTOM","CDLLONGLEGGEDDOJI","CDLLONGLINE","CDLMARUBOZU","CDLMATCHINGLOW","CDLMATHOLD","CDLMORNINGDOJISTAR","CDLMORNINGSTAR","CDLONNECK","CDLPIERCING","CDLRICKSHAWMAN","CDLRISEFALL3METHODS","CDLSEPARATINGLINES","CDLSHOOTINGSTAR","CDLSHORTLINE","CDLSPINNINGTOP","CDLSTALLEDPATTERN","CDLSTICKSANDWICH","CDLTAKURI","CDLTASUKIGAP","CDLTHRUSTING","CDLTRISTAR","CDLUNIQUE3RIVER","CDLUPSIDEGAP2CROWS","CDLXSIDEGAP3METHODS","CEIL","CMO","CORREL","COS","COSH","DEMA","DIV","DX","EMA","EXP","FLOOR","HT_DCPERIOD","HT_DCPHASE","HT_PHASOR","HT_SINE","HT_TRENDLINE","HT_TRENDMODE","KAMA","LINEARREG","LINEARREG_ANGLE","LINEARREG_INTERCEPT","LINEARREG_SLOPE","LN","LOG10","MA","MACD","MACDEXT","MACDFIX","MAMA","MAVP","MAX","MAXINDEX","MEDPRICE","MFI","MIDPOINT","MIDPRICE","MIN","MININDEX","MINMAX","MINMAXINDEX","MINUS_DI","MINUS_DM","MOM","MULT","NATR","OBV","PLUS_DI","PLUS_DM","PPO","ROC","ROCP","ROCR","ROCR100","RSI","SAR","SAREXT","SIN","SINH","SMA","SQRT","STDDEV","STOCH","STOCHF","STOCHRSI","SUB","SUM","T3","TAN","TANH","TEMA","TRANGE","TRIMA","TRIX","TSF","TYPPRICE","ULTOSC","VAR","WCLPRICE","WILLR","WMA"]
__TA_FUNCTION_NAMES__ = ["ACOS","AD","ADD","ADOSC","ADX","ADXR","APO","AROON","AROONOSC","ASIN","ATAN","ATR","AVGPRICE","BBANDS","BETA","BOP","CCI","CDL2CROWS","CDL3BLACKCROWS","CDL3INSIDE","CDL3LINESTRIKE","CDL3OUTSIDE","CDL3STARSINSOUTH","CDL3WHITESOLDIERS","CDLABANDONEDBABY","CDLADVANCEBLOCK","CDLBELTHOLD","CDLBREAKAWAY","CDLCLOSINGMARUBOZU","CDLCONCEALBABYSWALL","CDLCOUNTERATTACK","CDLDARKCLOUDCOVER","CDLDOJI","CDLDOJISTAR","CDLDRAGONFLYDOJI","CDLENGULFING","CDLEVENINGDOJISTAR","CDLEVENINGSTAR","CDLGAPSIDESIDEWHITE","CDLGRAVESTONEDOJI","CDLHAMMER","CDLHANGINGMAN","CDLHARAMI","CDLHARAMICROSS","CDLHIGHWAVE","CDLHIKKAKE","CDLHIKKAKEMOD","CDLHOMINGPIGEON","CDLIDENTICAL3CROWS","CDLINNECK","CDLINVERTEDHAMMER","CDLKICKING","CDLKICKINGBYLENGTH","CDLLADDERBOTTOM","CDLLONGLEGGEDDOJI","CDLLONGLINE","CDLMARUBOZU","CDLMATCHINGLOW","CDLMATHOLD","CDLMORNINGDOJISTAR","CDLMORNINGSTAR","CDLONNECK","CDLPIERCING","CDLRICKSHAWMAN","CDLRISEFALL3METHODS","CDLSEPARATINGLINES","CDLSHOOTINGSTAR","CDLSHORTLINE","CDLSPINNINGTOP","CDLSTALLEDPATTERN","CDLSTICKSANDWICH","CDLTAKURI","CDLTASUKIGAP","CDLTHRUSTING","CDLTRISTAR","CDLUNIQUE3RIVER","CDLUPSIDEGAP2CROWS","CDLXSIDEGAP3METHODS","CEIL","CMO","CORREL","COS","COSH","DEMA","DIV","DX","EMA","EXP","FLOOR","HT_DCPERIOD","HT_DCPHASE","HT_PHASOR","HT_SINE","HT_TRENDLINE","HT_TRENDMODE","KAMA","LINEARREG","LINEARREG_ANGLE","LINEARREG_INTERCEPT","LINEARREG_SLOPE","LN","LOG10","MA","MACD","MACDEXT","MACDFIX","MAMA","MAVP","MAX","MAXINDEX","MEDPRICE","MFI","MIDPOINT","MIDPRICE","MIN","MININDEX","MINMAX","MINMAXINDEX","MINUS_DI","MINUS_DM","MOM","MULT","NATR","OBV","PLUS_DI","PLUS_DM","PPO","ROC","ROCP","ROCR","ROCR100","RSI","SAR","SAREXT","SIN","SINH","SMA","SQRT","STDDEV","STOCH","STOCHF","STOCHRSI","SUB","SUM","T3","TAN","TANH","TEMA","TRANGE","TRIMA","TRIX","TSF","TYPPRICE","ULTOSC","VAR","WCLPRICE","WILLR","WMA"]
338 changes: 162 additions & 176 deletions talib/stream.pyx → talib/_stream.pxi

Large diffs are not rendered by default.

250,401 changes: 250,401 additions & 0 deletions talib/_ta_lib.c

Large diffs are not rendered by default.

File renamed without changes.
4 changes: 4 additions & 0 deletions talib/_ta_lib.pyx
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
include "_common.pxi"
include "_func.pxi"
include "_abstract.pxi"
include "_stream.pxi"
20,518 changes: 0 additions & 20,518 deletions talib/abstract.c

This file was deleted.

25 changes: 25 additions & 0 deletions talib/abstract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import talib._ta_lib as _ta_lib
from ._ta_lib import Function as _Function, __TA_FUNCTION_NAMES__, _get_defaults_and_docs


_func_obj_mapping = {
func_name: getattr(_ta_lib, func_name)
for func_name in __TA_FUNCTION_NAMES__
}


def Function(function_name, *args, **kwargs):
func_name = function_name.upper()
if func_name not in _func_obj_mapping:
raise Exception('%s not supported by TA-LIB.' % func_name)

return _Function(
func_name, _func_obj_mapping[func_name], *args, **kwargs
)


for func_name in __TA_FUNCTION_NAMES__:
globals()[func_name] = Function(func_name)


__all__ = ["Function", "_get_defaults_and_docs"] + __TA_FUNCTION_NAMES__
5,519 changes: 0 additions & 5,519 deletions talib/common.c

This file was deleted.

2 changes: 1 addition & 1 deletion talib/common.pxd
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
from libta_lib cimport TA_RetCode
from _ta_lib cimport TA_RetCode
cpdef _ta_check_success(str function_name, TA_RetCode ret_code)
138,741 changes: 0 additions & 138,741 deletions talib/func.c

This file was deleted.

102,155 changes: 0 additions & 102,155 deletions talib/stream.c

This file was deleted.

6 changes: 6 additions & 0 deletions talib/stream.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import talib._ta_lib as _ta_lib
from ._ta_lib import __TA_FUNCTION_NAMES__


for func_name in __TA_FUNCTION_NAMES__:
globals()[func_name] = getattr(_ta_lib, "stream_%s" % func_name)
9 changes: 4 additions & 5 deletions tools/generate_func.py
Original file line number Diff line number Diff line change
@@ -51,7 +51,7 @@
from numpy import nan
from cython import boundscheck, wraparound
from .common cimport _ta_check_success
# _ta_check_success: defined in _common.pxi
cdef double NaN = nan
@@ -63,10 +63,9 @@
np.import_array() # Initialize the NumPy C API
cimport libta_lib as lib
from libta_lib cimport TA_RetCode
cimport _ta_lib as lib
from _ta_lib cimport TA_RetCode
lib.TA_Initialize()
""")

# cleanup variable names to make them more pythonic
@@ -338,4 +337,4 @@ def cleanup(name):
print('')
print('')

print('__all__ = [%s]' % ','.join(['\"%s\"' % name for name in names]))
print('__TA_FUNCTION_NAMES__ = [%s]' % ','.join(['\"%s\"' % name for name in names]))
24 changes: 5 additions & 19 deletions tools/generate_stream.py
Original file line number Diff line number Diff line change
@@ -48,25 +48,12 @@
# print headers
print("""\
cimport numpy as np
from numpy import nan
from cython import boundscheck, wraparound
cimport _ta_lib as lib
from _ta_lib cimport TA_RetCode
# NOTE: _ta_check_success, NaN are defined in common.pxi
# NumPy C API is initialize in _func.pxi
from .common cimport _ta_check_success
cdef double NaN = nan
cdef extern from "numpy/arrayobject.h":
int PyArray_TYPE(np.ndarray)
object PyArray_EMPTY(int, np.npy_intp*, int, int)
int PyArray_FLAGS(np.ndarray)
object PyArray_GETCONTIGUOUS(np.ndarray)
np.import_array() # Initialize the NumPy C API
cimport libta_lib as lib
from libta_lib cimport TA_RetCode
lib.TA_Initialize()
""")

# cleanup variable names to make them more pythonic
@@ -96,7 +83,7 @@ def cleanup(name):

print('@wraparound(False) # turn off relative indexing from end of lists')
print('@boundscheck(False) # turn off bounds-checking for entire function')
print('def %s(' % shortname, end=' ')
print('def stream_%s(' % shortname, end=' ')
docs = [' %s(' % shortname]
i = 0
for arg in args:
@@ -302,4 +289,3 @@ def cleanup(name):
print('')
print('')

print('__all__ = [%s]' % ','.join(['\"%s\"' % name for name in names]))