Skip to content

Build ta-lib from source if the library is not found #111

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

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
9 changes: 6 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
*.pyc
build
build/
dist/
*.so
.*
*~

*.sw[op]
.cache/
*.o
*.egg-info/
14 changes: 14 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---

language: python
python:
- 2.7

cache: pip

install:
- pip install wheel
- pip install -r dev-requirements.txt

script:
- python setup.py test
11 changes: 11 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
include README.md
include AUTHORS
include CHANGELOG
include COPYRIGHT
include DEVELOPMENT
include LICENSE
include requirements.txt
recursive-include vendor *
recursive-include talib *.py *.pyx *.pxi *.pxd *.c
global-exclude *.o *.so *.pyc
prune .git
4 changes: 4 additions & 0 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Cython==0.24.1
numpy
pandas
pytest
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
numpy
118 changes: 94 additions & 24 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,32 @@
#!/usr/bin/env python

import sys
import glob
import os
import warnings

from distutils.dist import Distribution
from setuptools.command.test import test as TestCommand


class PyTest(TestCommand):
user_options = [('pytest-args=', 'a', "Arguments to pass to py.test")]

def initialize_options(self):
TestCommand.initialize_options(self)
self.pytest_args = ['tests']

def finalize_options(self):
TestCommand.finalize_options(self)
self.test_args = []
self.test_suite = True

def run_tests(self):
# import here, cause outside the eggs aren't loaded
import pytest
errno = pytest.main(self.pytest_args)
sys.exit(errno)


display_option_names = Distribution.display_option_names + ['help', 'help-commands']
query_only = any('--' + opt in sys.argv for opt in display_option_names) or len(sys.argv) < 2 or sys.argv[1] == 'egg_info'
Expand All @@ -20,8 +42,10 @@

from distutils.extension import Extension

lib_talib_name = 'ta_lib' # the underlying C library's name

lib_talib_name = 'ta_lib' # the underlying C library's name
sources = []
libraries = []
platform_supported = False
for prefix in ['darwin', 'linux', 'bsd', 'sunos']:
if prefix in sys.platform:
Expand Down Expand Up @@ -73,33 +97,78 @@
break
except OSError:
pass
libraries = [lib_talib_name]
else:
warnings.warn('Cannot find ta-lib library, installation may fail.')
warnings.warn(
"Cannot find ta-lib library, Try to build from source. "
"Installation may fail."
)
# find vendor/ta-lib -name "*.h" -exec dirname {} \; | sort | uniq
vendor_dir = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"vendor",
)
vendor_include_dir = os.path.join(
vendor_dir,
"include",
)
vendor_talib_dir = os.path.join(
vendor_dir,
"ta-lib",
)
talib_include_dirs = [
("include", ),
("src", "ta_abstract"),
("src", "ta_abstract", "frames"),
("src", "ta_common"),
("src", "ta_func"),
]
include_dirs.append(os.path.join(vendor_include_dir))
include_dirs.extend((
os.path.join(vendor_talib_dir, *path_args)
for path_args in talib_include_dirs
))

cmdclass = {}
talib_source_dirs = [
("ta_abstract", ),
("ta_abstract", "frames"),
("ta_abstract", "tables"),
("ta_common", ),
("ta_func", )
]
for path_args in talib_source_dirs:
source_dir = os.path.join(vendor_talib_dir, "src", *path_args)
sources.extend(glob.glob(os.path.join(source_dir, "*.c")))
sources.remove(
os.path.join(vendor_talib_dir, "src", "ta_abstract", "excel_glue.c")
)
libraries = []
lib_talib_dirs = []

cmdclass = {"test": PyTest}
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.c_ta_lib',
["talib/c_ta_lib.pyx" if has_cython else "talib/c_ta_lib.c"] + sources,
include_dirs=include_dirs,
library_dirs=lib_talib_dirs,
libraries=libraries
)
ext_modules.append(ext)
]


setup(
name = 'TA-Lib',
version = '0.4.10',
description = 'Python wrapper for TA-Lib',
author = 'John Benediktsson',
author_email = '[email protected]',
url = 'http://github.com/mrjbq7/ta-lib',
download_url = 'https://github.com/mrjbq7/ta-lib/releases',
classifiers = [
name='TA-Lib',
version='0.4.10',
description='Python wrapper for TA-Lib',
author='John Benediktsson',
author_email='[email protected]',
url='http://github.com/mrjbq7/ta-lib',
download_url='https://github.com/mrjbq7/ta-lib/releases',
classifiers=[
"License :: OSI Approved :: BSD License",
"Development Status :: 4 - Beta",
"Operating System :: Unix",
Expand All @@ -116,8 +185,9 @@
"Intended Audience :: Science/Research",
"Intended Audience :: Financial and Insurance Industry",
],
packages = ['talib'],
ext_modules = ext_modules,
cmdclass = cmdclass,
requires = ['numpy'],
packages=['talib'],
ext_modules=ext_modules,
cmdclass=cmdclass,
requires=['numpy'],
tests_require=["pytest"],
)
16 changes: 9 additions & 7 deletions talib/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@

import atexit

from . import common
from .c_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__
)
from func import *
from . import abstract
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 *

__version__ = '0.4.10'

Expand All @@ -17,8 +19,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': [
Expand Down
23 changes: 5 additions & 18 deletions talib/abstract.pyx → talib/_abstract.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -14,11 +11,9 @@ import numpy
import sys

cimport numpy as np
cimport libta_lib as lib

lib.TA_Initialize()
cimport c_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,
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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)
8 changes: 5 additions & 3 deletions talib/common.pyx → talib/_common.pxi
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
cimport c_ta_lib as lib
from numpy import nan
from c_ta_lib cimport TA_RetCode, TA_FuncUnstId

cimport libta_lib as lib
from libta_lib cimport TA_RetCode, TA_FuncUnstId

cdef double NaN = nan
__ta_version__ = lib.TA_GetVersionString()


cpdef _ta_check_success(str function_name, TA_RetCode ret_code):
if ret_code == lib.TA_SUCCESS:
return True
Expand Down
22 changes: 3 additions & 19 deletions talib/func.pyx → talib/_func.pxi
Original file line number Diff line number Diff line change
@@ -1,23 +1,9 @@
cimport numpy as np
from numpy import nan
from cython import boundscheck, wraparound
cimport c_ta_lib as lib
from c_ta_lib cimport TA_RetCode
# NOTE: _ta_check_success, NaN is defined in _common.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()

@wraparound(False) # turn off relative indexing from end of lists
@boundscheck(False) # turn off bounds-checking for entire function
Expand Down Expand Up @@ -11242,5 +11228,3 @@ def WMA( np.ndarray real not None , int timeperiod=-2**31 ):
retCode = lib.TA_WMA( 0 , endidx , <double *>(real_data+begidx) , timeperiod , &outbegidx , &outnbelement , <double *>(outreal_data+lookback) )
_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"]
Loading