ENH bbands #202 ENH core added ordered and chunksize args ENH chunksize optimizing

This commit is contained in:
Kevin Johnson
2021-03-09 12:47:13 -08:00
parent 6df58b04fa
commit 0277894337
5 changed files with 37 additions and 19 deletions
+2 -1
View File
@@ -83,7 +83,7 @@ $ pip install pandas_ta
Latest Version
--------------
Best choice! Version: *0.2.45b*
Best choice! Version: *0.2.47b*
```sh
$ pip install -U git+https://github.com/twopirllc/pandas-ta
```
@@ -715,6 +715,7 @@ article in the June, 1994 issue of Technical Analysis of Stocks & Commodities Ma
## **Updated Indicators**
* _Average True Range_ (**atr**): The default ```mamode``` is now "**RMA**" and with the same ```mamode``` options as TradingView. See ```help(ta.atr)```.
* _Bollinger Bands_ (**bbands**): New argument ```ddoff``` to control the Degrees of Freedom. Default is 0. See ```help(ta.bbands)```.
* _Decreasing_ (**decreasing**): New argument ```strict``` checks if the series is continuously decreasing over period ```length```. Default: ```False```. See ```help(ta.decreasing)```.
* _Increasing_ (**increasing**): New argument ```strict``` checks if the series is continuously increasing over period ```length```. Default: ```False```. See ```help(ta.increasing)```.
* _Trend Return_ (**trend_return**): Returns a DataFrame now instead of Series with pertinenet trade info for a _trend_. An example can be found in the [AI Example Notebook](https://github.com/twopirllc/pandas-ta/tree/master/examples/AIExample.ipynb). The notebook is still a work in progress and open to colloboration.
+20 -10
View File
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
from dataclasses import dataclass, field
from datetime import datetime
from math import log as mlog
from multiprocessing import cpu_count, Pool
from time import perf_counter
from typing import List, Tuple
@@ -582,6 +583,8 @@ class AnalysisIndicators(BasePandasObject):
# cpus = cpu_count()
# Ensure indicators are appended to the DataFrame
kwargs["append"] = True
all_ordered = kwargs.pop("ordered", False)
mp_chunksize = kwargs.pop("chunksize", self.cores)
# Initialize
initial_column_count = len(self._df.columns)
@@ -657,11 +660,14 @@ class AnalysisIndicators(BasePandasObject):
use_multiprocessing = False
if use_multiprocessing:
if verbose:
print(f"[i] Multiprocessing: {self.cores} of {cpu_count()} cores.")
_total_ta = len(ta)
pool = Pool(self.cores)
# Some magic to optimize chunksize for speed based on total ta indicators
_chunksize = mp_chunksize - 1 if mp_chunksize > _total_ta else int(mlog(_total_ta)) + 1
if verbose:
print(f"[i] Multiprocessing: {self.cores} of {cpu_count()} cores of {_total_ta} indicators.")
results = None
if mode["custom"]:
# Create a list of all the custom indicators into a list
custom_ta = [(
@@ -671,15 +677,21 @@ class AnalysisIndicators(BasePandasObject):
) for ind in ta]
# Custom multiprocessing pool. Must be ordered for Chained Strategies
# May fix this to cpus if Chaining/Composition if it remains
# inconsistent
results = pool.imap(self._mp_worker, custom_ta, self.cores)
results = pool.imap(self._mp_worker, custom_ta, _chunksize)
else:
default_ta = [(ind, tuple(), kwargs) for ind in ta]
# All and Categorical multiprocessing pool. Speed over Order.
results = pool.imap_unordered(self._mp_worker, default_ta, self.cores)
# All and Categorical multiprocessing pool.
if all_ordered:
results = pool.imap(self._mp_worker, default_ta, _chunksize) # Order over Speed
else:
results = pool.imap_unordered(self._mp_worker, default_ta, _chunksize) # Speed over Order
if results is None:
print(f"[X] ta.strategy('{name}') has no results.")
return
pool.close()
pool.join()
else:
# Without multiprocessing:
if verbose:
@@ -705,9 +717,7 @@ class AnalysisIndicators(BasePandasObject):
if verbose:
print(f"[i] Total indicators: {len(ta)}")
print(
f"[i] Columns added: {len(self._df.columns) - initial_column_count}"
)
print(f"[i] Columns added: {len(self._df.columns) - initial_column_count}")
if timed:
print(f"[i] Runtime: {ftime}")
+6 -5
View File
@@ -5,21 +5,21 @@ from pandas_ta.statistics import stdev
from pandas_ta.utils import get_offset, verify_series
def bbands(close, length=None, std=None, mamode=None, offset=None, **kwargs):
def bbands(close, length=None, std=None, mamode=None, ddof=0, offset=None, **kwargs):
"""Indicator: Bollinger Bands (BBANDS)"""
# Validate arguments
close = verify_series(close)
length = int(length) if length and length > 0 else 5
std = float(std) if std and std > 0 else 2.0
mamode = mamode if isinstance(mamode, str) else "sma"
ddof = int(ddof) if ddof >= 0 and ddof < length else 1
offset = get_offset(offset)
# Calculate Result
standard_deviation = stdev(close=close, length=length)
standard_deviation = stdev(close=close, length=length, ddof=ddof)
deviations = std * standard_deviation
mid = ma(mamode, close, length=length, **kwargs)
lower = mid - deviations
upper = mid + deviations
@@ -74,11 +74,11 @@ Sources:
Calculation:
Default Inputs:
length=5, std=2, mamode="sma"
length=5, std=2, mamode="sma", ddof=0
EMA = Exponential Moving Average
SMA = Simple Moving Average
STDEV = Standard Deviation
stdev = STDEV(close, length)
stdev = STDEV(close, length, ddof)
if "ema":
MID = EMA(close, length)
else:
@@ -94,6 +94,7 @@ Args:
length (int): The short period. Default: 5
std (int): The long period. Default: 2
mamode (str): Two options: "sma" or "ema". Default: "sma"
ddof (int): Degrees of Freedom to use. Default: 0
offset (int): How many periods to offset the result. Default: 0
Kwargs:
+1 -1
View File
@@ -18,7 +18,7 @@ setup(
"pandas_ta.volatility",
"pandas_ta.volume"
],
version=".".join(("0", "2", "46b")),
version=".".join(("0", "2", "47b")),
description=long_description,
long_description=long_description,
author="Kevin Johnson",
+8 -2
View File
@@ -67,6 +67,11 @@ class TestStrategyMethods(TestCase):
self.category = "All"
self.data.ta.strategy(verbose=verbose, timed=strategy_timed)
def test_all_ordered(self):
self.category = "All"
self.data.ta.strategy(ordered=True, verbose=verbose, timed=strategy_timed)
self.category = "All Ordered" # Rename for Speed Table
@skipUnless(verbose, "verbose mode only")
def test_all_strategy(self):
self.data.ta.strategy(pandas_ta.AllStrategy, verbose=verbose, timed=strategy_timed)
@@ -76,12 +81,13 @@ class TestStrategyMethods(TestCase):
self.category = "All"
self.data.ta.strategy(self.category, verbose=verbose, timed=strategy_timed)
@skipUnless(verbose, "verbose mode only")
# @skipUnless(verbose, "verbose mode only")
def test_all_multiparams_strategy(self):
self.category = "All"
self.data.ta.strategy(self.category, length=10, verbose=verbose, timed=strategy_timed)
self.data.ta.strategy(self.category, length=50, verbose=verbose, timed=strategy_timed)
self.data.ta.strategy(self.category, fast=5, verbose=verbose, timed=strategy_timed)
self.data.ta.strategy(self.category, fast=5, slow=10, verbose=verbose, timed=strategy_timed)
self.category = "All Multiruns with diff Args" # Rename for Speed Table
# @skip
def test_candles_category(self):