mirror of
https://github.com/wassname/pandas-ta.git
synced 2026-08-16 11:25:01 +08:00
Merge pull request #1 from twopirllc/performance-indicators
added performance indicators with basic tests
This commit is contained in:
+4
-1
@@ -123,4 +123,7 @@ ta_extension.ipynb
|
||||
Charts.ipynb
|
||||
pandas_pips
|
||||
reqs.txt
|
||||
requirements.txt
|
||||
requirements.txt
|
||||
|
||||
test_indicator_statistics.py
|
||||
test_indicator_statistics_ext.py
|
||||
@@ -6,6 +6,78 @@ Technical Analysis (TA) is an easy to use library that is built upon Python's Pa
|
||||
This version contains both the orignal code branch as well as a newly refactored branch with the option to use [Pandas DataFrame Extension](https://pandas.pydata.org/pandas-docs/stable/extending.html) mode.
|
||||
All the indicators return a named Series or a DataFrame in uppercase underscore parameter format. For example, MACD(fast=12, slow=26, signal=9) will return a DataFrame with columns: ['MACD_12_26_9', 'MACDH_12_26_9', 'MACDS_12_26_9'].
|
||||
|
||||
## New Changes
|
||||
|
||||
* At 70+ indicators.
|
||||
* Abbreviated Indicator names as listed below.
|
||||
* *Extended Pandas DataFrame* as 'ta'. See examples below.
|
||||
* Parameter names are more consistent.
|
||||
* Former indicators still exist and are renamed with '_depreciated' append to it's name. For example, 'average_true_range' is now 'average_true_range_depreciated'.
|
||||
* Refactoring indicators into categories similar to [TA-lib](https://github.com/mrjbq7/ta-lib/tree/master/docs/func_groups).
|
||||
|
||||
### What is a Pandas DataFrame Extension?
|
||||
|
||||
A [Pandas DataFrame Extension](https://pandas.pydata.org/pandas-docs/stable/extending.html), extends a DataFrame allowing one to add more functionality and features to Pandas to suit your needs. As such, it is now easier to run Technical Analysis on existing Financial Time Series without leaving the current DataFrame. This extension by default returns the Indicator result or, inclusively, it can append the result to the existing DataFrame by including the parameter
|
||||
'append=True' in the method call. See examples below.
|
||||
|
||||
|
||||
# Getting Started and Examples
|
||||
|
||||
## **Quick Start** using the DataFrame Extension
|
||||
|
||||
```python
|
||||
import pandas as pd
|
||||
import pandas_ta as ta
|
||||
|
||||
# Load data
|
||||
df = pd.read_csv('symbol.csv', sep=',')
|
||||
|
||||
# Calculate Returns and append to the df DataFrame
|
||||
df.ta.log_return(cumulative=True, append=True)
|
||||
df.ta.percent_return(cumulative=True, append=True)
|
||||
|
||||
# New Columns with results
|
||||
df.columns
|
||||
|
||||
# Take a peek
|
||||
df.tail()
|
||||
|
||||
# vv Continue Post Processing vv
|
||||
```
|
||||
|
||||
## Module and Indicator Help
|
||||
|
||||
```python
|
||||
import pandas as pd
|
||||
import pandas_ta as ta
|
||||
|
||||
# Help about this, 'ta', extension
|
||||
help(pd.DataFrame().ta)
|
||||
|
||||
# List of all indicators
|
||||
pd.DataFrame().ta.indicators()
|
||||
|
||||
# Help about the log_return indicator
|
||||
help(ta.log_return)
|
||||
|
||||
# Help about the log_return indicator as a DataFrame Extension
|
||||
help(pd.DataFrame().ta.log_return)
|
||||
```
|
||||
|
||||
|
||||
|
||||
# Technical Analysis Indicators (by Category)
|
||||
|
||||
## _Performance_ (2)
|
||||
|
||||
Use parameter: cumulative=**True** for cumulative results.
|
||||
|
||||
* _Log Return_: **log_return**
|
||||
* _Percent Return_: **percent_return**
|
||||
|
||||
| _Percent Return_ (Cumulative) with _Simple Moving Average_ (SMA) |
|
||||
|:--------:|
|
||||
|  |
|
||||
|
||||
|
||||
# Inspiration
|
||||
|
||||
+26
-7
@@ -1,10 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import time
|
||||
import pandas as pd
|
||||
|
||||
from .utils import *
|
||||
from pandas.core.base import PandasObject
|
||||
|
||||
from .utils import *
|
||||
from .performance import *
|
||||
|
||||
|
||||
class BasePandasObject(PandasObject):
|
||||
@@ -122,12 +122,10 @@ class AnalysisIndicators(BasePandasObject):
|
||||
|
||||
return indicator
|
||||
else:
|
||||
# self.help()
|
||||
pass
|
||||
self.help()
|
||||
|
||||
except:
|
||||
# self.help()
|
||||
pass
|
||||
self.help()
|
||||
|
||||
|
||||
def _append(self, result=None, **kwargs):
|
||||
@@ -209,6 +207,7 @@ class AnalysisIndicators(BasePandasObject):
|
||||
header = f"pandas.ta - Technical Analysis Indicators"
|
||||
helper_methods = ['indicators', 'constants'] # Public non-indicator methods
|
||||
exclude_methods = kwargs.pop('exclude', None)
|
||||
as_list = kwargs.pop('as_list', False)
|
||||
ta_indicators = list((x for x in dir(pd.DataFrame().ta) if not x.startswith('_') and not x.endswith('_')))
|
||||
|
||||
for x in helper_methods:
|
||||
@@ -218,6 +217,9 @@ class AnalysisIndicators(BasePandasObject):
|
||||
for x in exclude_methods:
|
||||
ta_indicators.remove(x)
|
||||
|
||||
if as_list:
|
||||
return ta_indicators
|
||||
|
||||
total_indicators = len(ta_indicators)
|
||||
s = f"{header}\nTotal Indicators: {total_indicators}\n"
|
||||
if total_indicators > 0:
|
||||
@@ -225,4 +227,21 @@ class AnalysisIndicators(BasePandasObject):
|
||||
# print(f"{s}Abbreviations:\n {abbr_list}")
|
||||
print(f"{s}Abbreviations:\n {abbr_list}")
|
||||
else:
|
||||
print(s)
|
||||
print(s)
|
||||
|
||||
|
||||
|
||||
|
||||
def log_return(self, close=None, length=None, cumulative=False, percent=False, offset=None, **kwargs):
|
||||
close = self._get_column(close, 'close')
|
||||
result = log_return(close=close, length=length, cumulative=cumulative, percent=percent, offset=offset, **kwargs)
|
||||
self._append(result, **kwargs)
|
||||
# print(f"result:\n{result}")
|
||||
return result
|
||||
|
||||
|
||||
def percent_return(self, close=None, length=None, cumulative=False, percent=False, offset=None, **kwargs):
|
||||
close = self._get_column(close, 'close')
|
||||
result = percent_return(close=close, length=length, cumulative=cumulative, percent=percent, offset=offset, **kwargs)
|
||||
self._append(result, **kwargs)
|
||||
return result
|
||||
@@ -0,0 +1,114 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
from .utils import get_offset, verify_series
|
||||
|
||||
|
||||
def log_return(close, length=None, cumulative=False, offset=None, **kwargs):
|
||||
"""Indicator: Log Return"""
|
||||
# Validate Arguments
|
||||
close = verify_series(close)
|
||||
length = int(length) if length and length > 0 else 1
|
||||
offset = get_offset(offset)
|
||||
|
||||
# Calculate Result
|
||||
log_return = np.log(close).diff(periods=length)
|
||||
|
||||
if cumulative:
|
||||
log_return = log_return.cumsum()
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
log_return = log_return.shift(offset)
|
||||
|
||||
# Name & Category
|
||||
log_return.name = f"{'CUM' if cumulative else ''}LOGRET_{length}"
|
||||
log_return.category = 'performance'
|
||||
|
||||
return log_return
|
||||
|
||||
|
||||
def percent_return(close, length=None, cumulative=False, offset=None, **kwargs):
|
||||
"""Indicator: Percent Return"""
|
||||
# Validate Arguments
|
||||
close = verify_series(close)
|
||||
length = int(length) if length and length > 0 else 1
|
||||
offset = get_offset(offset)
|
||||
|
||||
# Calculate Result
|
||||
pct_return = close.pct_change(length)
|
||||
|
||||
if cumulative:
|
||||
pct_return = pct_return.cumsum()
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
pct_return = pct_return.shift(offset)
|
||||
|
||||
# Name & Category
|
||||
pct_return.name = f"{'CUM' if cumulative else ''}PCTRET_{length}"
|
||||
pct_return.category = 'performance'
|
||||
|
||||
return pct_return
|
||||
|
||||
|
||||
|
||||
log_return.__doc__ = \
|
||||
"""Log Return
|
||||
|
||||
Calculates the logarithmic return of a Series.
|
||||
See also: help(df.ta.log_return) for additional **kwargs a valid 'df'.
|
||||
|
||||
Sources:
|
||||
https://stackoverflow.com/questions/31287552/logarithmic-returns-in-pandas-dataframe
|
||||
|
||||
Calculation:
|
||||
Default Inputs:
|
||||
length=1, cummulative=False
|
||||
LOGRET = log( close.diff(periods=length) )
|
||||
CUMLOGRET = LOGRET.cumsum() if cummulative
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
length (int): It's period. Default: 20
|
||||
cummulative (bool): If True, returns the cummulative returns. Default: False
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
|
||||
Kwargs:
|
||||
fillna (value, optional): pd.DataFrame.fillna(value)
|
||||
fill_method (value, optional): Type of fill method
|
||||
|
||||
Returns:
|
||||
pd.Series: New feature generated.
|
||||
"""
|
||||
|
||||
|
||||
percent_return.__doc__ = \
|
||||
"""Percent Return
|
||||
|
||||
Calculates the percent return of a Series.
|
||||
See also: help(df.ta.percent_return) for additional **kwargs a valid 'df'.
|
||||
|
||||
Sources:
|
||||
https://stackoverflow.com/questions/31287552/logarithmic-returns-in-pandas-dataframe
|
||||
|
||||
Calculation:
|
||||
Default Inputs:
|
||||
length=1, cummulative=False
|
||||
PCTRET = close.pct_change(length)
|
||||
CUMPCTRET = PCTRET.cumsum() if cummulative
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
length (int): It's period. Default: 20
|
||||
cummulative (bool): If True, returns the cummulative returns. Default: False
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
|
||||
Kwargs:
|
||||
fillna (value, optional): pd.DataFrame.fillna(value)
|
||||
fill_method (value, optional): Type of fill method
|
||||
|
||||
Returns:
|
||||
pd.Series: New feature generated.
|
||||
"""
|
||||
@@ -6,7 +6,7 @@ long_description = "A Python 3 Pandas Extension of Technical Analysis Indicators
|
||||
setup(
|
||||
name = "pandas_ta",
|
||||
packages = ["pandas_ta"],
|
||||
version = "0.0.3a",
|
||||
version = "0.0.4a",
|
||||
description=long_description,
|
||||
long_description=long_description,
|
||||
author = "Kevin Johnson",
|
||||
@@ -28,5 +28,16 @@ setup(
|
||||
'Intended Audience :: Financial and Insurance Industry',
|
||||
'Topic :: Office/Business :: Financial :: Investment',
|
||||
],
|
||||
# zip_safe=False,
|
||||
package_data={
|
||||
'data': ['data/*.csv'],
|
||||
},
|
||||
install_requires=['pandas'],
|
||||
|
||||
# List additional groups of dependencies here (e.g. development dependencies).
|
||||
# You can install these using the following syntax, for example:
|
||||
# $ pip install -e .[dev,test]
|
||||
extras_require = {
|
||||
'dev': ['ta-lib', 'jupyterlab'],
|
||||
'test': ['ta-lib'],
|
||||
},
|
||||
)
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
from unittest import TestCase
|
||||
import numpy.testing as npt
|
||||
import pandas.util.testing as pdt
|
||||
from pandas import DataFrame, read_csv, Series
|
||||
|
||||
from pandas_ta import performance
|
||||
|
||||
|
||||
class TestPerformace(TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.data = read_csv('data/sample.csv', index_col=0, parse_dates=True, infer_datetime_format=False, keep_date_col=True)
|
||||
cls.close = cls.data['close']
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
del cls.data
|
||||
del cls.close
|
||||
|
||||
|
||||
def setUp(self):
|
||||
self.performance = performance
|
||||
|
||||
def tearDown(self):
|
||||
del self.performance
|
||||
|
||||
|
||||
def test_log_return(self):
|
||||
log_return = self.performance.log_return(self.close)
|
||||
self.assertIsInstance(log_return, Series)
|
||||
self.assertEqual(log_return.name, 'LOGRET_1')
|
||||
|
||||
cumlog_return = self.performance.log_return(self.close, cumulative=True)
|
||||
self.assertEqual(cumlog_return.name, 'CUMLOGRET_1')
|
||||
|
||||
def test_percent_return(self):
|
||||
percent_return = self.performance.percent_return(self.close)
|
||||
self.assertIsInstance(percent_return, Series)
|
||||
self.assertEqual(percent_return.name, 'PCTRET_1')
|
||||
|
||||
cumpercent_return = self.performance.percent_return(self.close, cumulative=True)
|
||||
self.assertEqual(cumpercent_return.name, 'CUMPCTRET_1')
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
from unittest import TestCase
|
||||
import numpy.testing as npt
|
||||
import pandas.util.testing as pdt
|
||||
from pandas import DataFrame, read_csv, Series
|
||||
|
||||
import pandas_ta as ta
|
||||
|
||||
|
||||
class TestPerformaceExtension(TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.data = read_csv('data/sample.csv', index_col=0, parse_dates=True, infer_datetime_format=False, keep_date_col=True)
|
||||
cls.close = cls.data['close']
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
del cls.data
|
||||
del cls.close
|
||||
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
|
||||
def test_log_return_ext(self):
|
||||
self.data.ta.log_return(append=True)
|
||||
self.assertIsInstance(self.data, DataFrame)
|
||||
self.assertEqual(self.data.columns[-1], 'LOGRET_1')
|
||||
|
||||
self.data.ta.log_return(append=True, cumulative=True)
|
||||
self.assertIsInstance(self.data, DataFrame)
|
||||
self.assertEqual(self.data.columns[-1], 'CUMLOGRET_1')
|
||||
|
||||
def test_percent_return_ext(self):
|
||||
self.data.ta.percent_return(append=True)
|
||||
self.assertIsInstance(self.data, DataFrame)
|
||||
self.assertEqual(self.data.columns[-1], 'PCTRET_1')
|
||||
|
||||
self.data.ta.percent_return(append=True, cumulative=True)
|
||||
self.assertIsInstance(self.data, DataFrame)
|
||||
self.assertEqual(self.data.columns[-1], 'CUMPCTRET_1')
|
||||
|
||||
# Example
|
||||
# pta_sma = self.data[self.data.columns[-1]]
|
||||
# tal_sma = tal.SMA(self.close)
|
||||
# pdt.assert_series_equal(pta_sma, tal_sma)
|
||||
Reference in New Issue
Block a user