mirror of
https://github.com/wassname/pandas-ta.git
synced 2026-06-27 16:10:07 +08:00
MAINT minor refactoring
This commit is contained in:
+89
-86
@@ -1,24 +1,92 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import importlib
|
||||
import os
|
||||
import sys
|
||||
from os.path import abspath, join, exists, basename, splitext
|
||||
from glob import glob
|
||||
import types
|
||||
import importlib
|
||||
import pandas_ta
|
||||
import pandas as pd
|
||||
from pandas_ta import AnalysisIndicators
|
||||
|
||||
def import_dir(dir_path, verbose=True):
|
||||
|
||||
def bind(function_name, function, method):
|
||||
"""
|
||||
Helper function to bind the function and class method defined in a custom
|
||||
indicator module to the active pandas_ta instance.
|
||||
|
||||
Args:
|
||||
function_name (str): The name of the indicator within pandas_ta
|
||||
function (fcn): The indicator function
|
||||
method (fcn): The class method corresponding to the passed function
|
||||
"""
|
||||
setattr(pandas_ta, function_name, function)
|
||||
setattr(AnalysisIndicators, function_name, method)
|
||||
|
||||
|
||||
def create_dir(path, create_categories=True, verbose=True):
|
||||
"""
|
||||
Helper function to setup a suitable folder structure for working with
|
||||
custom indicators. You only need to call this once whenever you want to
|
||||
setup a new custom indicators folder.
|
||||
|
||||
Args:
|
||||
path (str): Full path to where you want your indicator tree
|
||||
create_categories (bool): If True create category sub-folders
|
||||
verbose (bool): If True print verbose output of results
|
||||
"""
|
||||
|
||||
# ensure that the passed directory exists / is readable
|
||||
if not exists(dir_path):
|
||||
print(f"[X] Unable to read the directory '{dir_path}'.")
|
||||
if not exists(path):
|
||||
os.makedirs(path)
|
||||
if verbose:
|
||||
print(f"[i] Created main directory '{path}'.")
|
||||
|
||||
# list the contents of the directory
|
||||
# dirs = glob(abspath(join(path, '*')))
|
||||
|
||||
# optionally add any missing category subdirectories
|
||||
if create_categories:
|
||||
for sd in [*pandas_ta.Category]:
|
||||
d = abspath(join(path, sd))
|
||||
if not exists(d):
|
||||
os.makedirs(d)
|
||||
if verbose:
|
||||
dirname = basename(d)
|
||||
print(f"[i] Created an empty sub-directory '{dirname}'.")
|
||||
|
||||
|
||||
def get_module_functions(module):
|
||||
"""
|
||||
Helper function to get the functions of an imported module as a dictionary.
|
||||
|
||||
Args:
|
||||
module: python module
|
||||
|
||||
Returns:
|
||||
dict: module functions mapping
|
||||
{
|
||||
"func1_name": func1,
|
||||
"func2_name": func2,...
|
||||
}
|
||||
"""
|
||||
module_functions = {}
|
||||
|
||||
for name, item in vars(module).items():
|
||||
if isinstance(item, types.FunctionType):
|
||||
module_functions[name] = item
|
||||
|
||||
return module_functions
|
||||
|
||||
|
||||
def import_dir(path, verbose=True):
|
||||
# ensure that the passed directory exists / is readable
|
||||
if not exists(path):
|
||||
print(f"[X] Unable to read the directory '{path}'.")
|
||||
return
|
||||
|
||||
# list the contents of the directory
|
||||
dirs = glob(abspath(join(dir_path, '*')))
|
||||
dirs = glob(abspath(join(path, '*')))
|
||||
|
||||
# traverse full directory, importing all modules found there
|
||||
for d in dirs:
|
||||
@@ -31,20 +99,20 @@ def import_dir(dir_path, verbose=True):
|
||||
continue
|
||||
|
||||
# for each module found in that category (directory)...
|
||||
for module in glob(abspath(join(dir_path, dirname, '*.py'))):
|
||||
for module in glob(abspath(join(path, dirname, '*.py'))):
|
||||
module_name = splitext(basename(module))[0]
|
||||
|
||||
# ensure that the supplied path is included in our python path
|
||||
if d not in sys.path:
|
||||
sys.path.append(d)
|
||||
|
||||
# (re)load the indicator module
|
||||
# (re)load the indicator module
|
||||
module_functions = load_indicator_module(module_name)
|
||||
|
||||
# figure out which of the modules functions to bind to pandas_ta
|
||||
fcn_callable = module_functions.get(module_name, None)
|
||||
fcn_method_callable = module_functions.get(module_name + "_method", None)
|
||||
|
||||
|
||||
if fcn_callable == None:
|
||||
print(f"[X] Unable to find a function named '{module_name}' in the module '{module_name}.py'.")
|
||||
continue
|
||||
@@ -61,17 +129,18 @@ def import_dir(dir_path, verbose=True):
|
||||
if verbose:
|
||||
print(f"[i] Successfully imported the custom indicator '{module}' into category '{dirname}'.")
|
||||
|
||||
|
||||
import_dir.__doc__ = \
|
||||
"""
|
||||
Import a directory of custom indicators into pandas_ta
|
||||
|
||||
Args:
|
||||
dir_path (str): Full path to your indicator tree
|
||||
path (str): Full path to your indicator tree
|
||||
verbose (bool): If True verbose output of results
|
||||
|
||||
This method allows you to experiment and develop your own technical analysis
|
||||
indicators in a separate local directory of your choice but use them seamlessly
|
||||
together with the existing pandas_ta functions just like if they were part of
|
||||
indicators in a separate local directory of your choice but use them seamlessly
|
||||
together with the existing pandas_ta functions just like if they were part of
|
||||
pandas_ta.
|
||||
|
||||
If you at some late point would like to push them into the pandas_ta library
|
||||
@@ -85,7 +154,7 @@ A brief example of usage:
|
||||
>>> import pandas_ta as ta
|
||||
|
||||
2. Create an empty directory on your machine where you want to work with your
|
||||
indicators. Invoke pandas_ta.custom.import_dir once to pre-populate it with
|
||||
indicators. Invoke pandas_ta.custom.import_dir once to pre-populate it with
|
||||
sub-folders for all available indicator categories, e.g.:
|
||||
|
||||
>>> import os
|
||||
@@ -94,22 +163,22 @@ sub-folders for all available indicator categories, e.g.:
|
||||
>>> my_dir = abspath(join(expanduser("~"), "my_indicators"))
|
||||
>>> create_dir(my_dir)
|
||||
|
||||
3. You can now create your own custom indicator e.g. by copying existing
|
||||
ones from pandas_ta core module and modifying them.
|
||||
3. You can now create your own custom indicator e.g. by copying existing
|
||||
ones from pandas_ta core module and modifying them.
|
||||
|
||||
IMPORTANT: Each custom indicator should have a unique name and have both
|
||||
IMPORTANT: Each custom indicator should have a unique name and have both
|
||||
a) a function named exactly as the module, e.g. 'ni' if the module is ni.py
|
||||
b) a matching method used by AnalysisIndicators named as the module but
|
||||
ending with '_method'. E.g. 'ni_method'
|
||||
|
||||
In essence these modules should look exactly like the standard indicators
|
||||
In essence these modules should look exactly like the standard indicators
|
||||
available in categories under the pandas_ta-folder. The only difference will
|
||||
be an addition of a matching class method.
|
||||
|
||||
For an example of the correct structure, look at the example ni.py in the
|
||||
For an example of the correct structure, look at the example ni.py in the
|
||||
examples folder.
|
||||
|
||||
The ni.py indicator is a trend indicator so therefore we drop it into the
|
||||
The ni.py indicator is a trend indicator so therefore we drop it into the
|
||||
sub-folder named trend. Thus we have a folder structure like this:
|
||||
|
||||
~/my_indicators/
|
||||
@@ -131,18 +200,6 @@ If your custom indicator(s) loaded succesfully then it should behave exactly
|
||||
like all other native indicators in pandas_ta, including help functions.
|
||||
"""
|
||||
|
||||
def bind(function_name, function, method):
|
||||
"""
|
||||
Helper function to bind the function and class method defined in a custom
|
||||
indicator module to the active pandas_ta instance.
|
||||
|
||||
Args:
|
||||
function_name (str): The name of the indicator within pandas_ta
|
||||
function (fcn): The indicator function
|
||||
method (fcn): The class method corresponding to the passed function
|
||||
"""
|
||||
setattr(pandas_ta, function_name, function)
|
||||
setattr(AnalysisIndicators, function_name, method)
|
||||
|
||||
def load_indicator_module(module_name):
|
||||
"""
|
||||
@@ -165,58 +222,4 @@ def load_indicator_module(module_name):
|
||||
|
||||
# reload to refresh previously loaded module
|
||||
module = importlib.reload(module)
|
||||
return get_module_functions(module)
|
||||
|
||||
def get_module_functions(module):
|
||||
"""
|
||||
Helper function to get the functions of an imported module as a dictionary.
|
||||
|
||||
Args:
|
||||
module: python module
|
||||
|
||||
Returns:
|
||||
dict: module functions mapping
|
||||
{
|
||||
"func1_name": func1,
|
||||
"func2_name": func2,...
|
||||
}
|
||||
|
||||
"""
|
||||
module_functions = {}
|
||||
|
||||
for name, item in vars(module).items():
|
||||
if isinstance(item, types.FunctionType):
|
||||
module_functions[name] = item
|
||||
|
||||
return module_functions
|
||||
|
||||
def create_dir(dir_path, create_categories=True, verbose=True):
|
||||
"""
|
||||
Helper function to setup a suitable folder structure for working with
|
||||
custom indicators. You only need to call this once whenever you want to
|
||||
setup a new custom indicators folder.
|
||||
|
||||
Args:
|
||||
dir_path (str): Full path to where you want your indicator tree
|
||||
create_categories (bool): If True create category sub-folders
|
||||
verbose (bool): If True print verbose output of results
|
||||
"""
|
||||
|
||||
# ensure that the passed directory exists / is readable
|
||||
if not exists(dir_path):
|
||||
os.makedirs(dir_path)
|
||||
if verbose:
|
||||
print(f"[i] Created main directory '{dir_path}'.")
|
||||
|
||||
# list the contents of the directory
|
||||
dirs = glob(abspath(join(dir_path, '*')))
|
||||
|
||||
# optionally add any missing category subdirectories
|
||||
if create_categories:
|
||||
for sd in [*pandas_ta.Category]:
|
||||
d = abspath(join(dir_path, sd))
|
||||
if not exists(d):
|
||||
os.makedirs(d)
|
||||
if verbose:
|
||||
dirname = basename(d)
|
||||
print(f"[i] Created an empty sub-directory '{dirname}'.")
|
||||
return get_module_functions(module)
|
||||
Reference in New Issue
Block a user