mirror of
https://github.com/wassname/pandas-ta.git
synced 2026-09-12 12:40:39 +08:00
MAINT pvo vwap vwma refactor DOC readme ENH extra val
This commit is contained in:
@@ -145,8 +145,9 @@ Pandas TA is used by Applications and Services like
|
||||
|
||||
<br/>
|
||||
|
||||
[Open BB](https://openbb.co/) (previously Gamestonk Terminal)
|
||||
[Open BB](https://openbb.co/)
|
||||
-------------------
|
||||
#### Previously **Gamestonk Terminal**
|
||||
> OpenBB is a leading open source investment analysis company.
|
||||
We represent millions of investors who want to leverage state-of-the-art data science and machine learning technologies to make sense of raw unrefined data. Our mission is to make investment research effective, powerful and accessible to everyone.
|
||||
|
||||
@@ -158,7 +159,7 @@ We represent millions of investors who want to leverage state-of-the-art data sc
|
||||
|
||||
<br/>
|
||||
|
||||
[VectorBT Pro & Open Source](https://vectorbt.pro/)
|
||||
[VectorBT Pro](https://vectorbt.pro/)
|
||||
-------------------
|
||||
> vectorbt PRO is the next-generation engine for backtesting, algorithmic trading, and research. It's a high-performance, actively-developed, commercial successor to the vectorbt library, one of the world's most innovative open-source backtesting engines. The PRO version extends the standard library with new impressive features and useful enhancements for professionals.
|
||||
|
||||
@@ -280,7 +281,7 @@ Back to [Contents](#contents)
|
||||
|
||||
# **Issues and Contributions**
|
||||
|
||||
Contributions, feedback, and bug squashing are integral to the success of this library. If something you can fix, _please_ do. Your contributon helps everyone!
|
||||
Contributions, feedback, and bug squashing are integral to the success of this library. If you see something you can fix, _please_ do. Your contributon helps us all!
|
||||
* :stop_sign: _Please_ **DO NOT** email me personally with Pandas TA Bugs, Issues or Feature Requests that are best handled with Github [Issues](https://github.com/twopirllc/pandas-ta/issues).
|
||||
|
||||
<br/>
|
||||
@@ -289,7 +290,7 @@ Contributions, feedback, and bug squashing are integral to the success of this l
|
||||
--------------------------------------
|
||||
1. Some bugs and features may already be be fixed or implemented in either the [Latest Version](#latest-version) or the the [Development Version](#development-version). _Please_ try them first.
|
||||
1. If the _Latest_ or _Development_ Versions do not resolve the bug or address the Issue, try searching both _Open_ and _Closed_ Issues **before** opening a new Issue.
|
||||
1. When you creating a new Issue, please be as **detailed** as possible **with** reproducible code, links if any, applicable screenshots, errors, logs, and data samples.
|
||||
1. When creating a new Issue, please be as **detailed** as possible **with** reproducible code, links if any, applicable screenshots, errors, logs, and data samples.
|
||||
* You **will** be asked again for skipping form questions.
|
||||
* Do you have correlation analysis to back your claim?
|
||||
|
||||
@@ -853,7 +854,7 @@ Back to [Contents](#contents)
|
||||
|
||||
<br/>
|
||||
|
||||
### **Momentum** (42)
|
||||
### **Momentum** (41)
|
||||
* _Awesome Oscillator_: **ao**
|
||||
* _Absolute Price Oscillator_: **apo**
|
||||
* _Bias_: **bias**
|
||||
@@ -878,7 +879,6 @@ Back to [Contents](#contents)
|
||||
* _Pretty Good Oscillator_: **pgo**
|
||||
* _Percentage Price Oscillator_: **ppo**
|
||||
* _Psychological Line_: **psl**
|
||||
* _Percentage Volume Oscillator_: **pvo**
|
||||
* _Quantitative Qualitative Estimation_: **qqe**
|
||||
* _Rate of Change_: **roc**
|
||||
* _Relative Strength Index_: **rsi**
|
||||
@@ -910,7 +910,7 @@ Back to [Contents](#contents)
|
||||
|
||||
<br/>
|
||||
|
||||
### **Overlap** (37)
|
||||
### **Overlap** (35)
|
||||
|
||||
* _Bill Williams Alligator_: **alligator**
|
||||
* _Arnaud Legoux Moving Average_: **alma**
|
||||
@@ -948,9 +948,6 @@ Back to [Contents](#contents)
|
||||
* _Triple Exponential Moving Average_: **tema**
|
||||
* _Triangular Moving Average_: **trima**
|
||||
* _Variable Index Dynamic Average_: **vidya**
|
||||
* _Volume Weighted Average Price_: **vwap**
|
||||
* **Requires** the DataFrame index to be a DatetimeIndex
|
||||
* _Volume Weighted Moving Average_: **vwma**
|
||||
* _Weighted Closing Price_: **wcp**
|
||||
* _Weighted Moving Average_: **wma**
|
||||
* _Zero Lag Moving Average_: **zlma**
|
||||
@@ -1084,7 +1081,7 @@ Back to [Contents](#contents)
|
||||
|
||||
<br/>
|
||||
|
||||
### **Volume** (16)
|
||||
### **Volume** (19)
|
||||
|
||||
* _Accumulation/Distribution Index_: **ad**
|
||||
* _Accumulation/Distribution Oscillator_: **adosc**
|
||||
@@ -1097,10 +1094,14 @@ Back to [Contents](#contents)
|
||||
* _Negative Volume Index_: **nvi**
|
||||
* _On-Balance Volume_: **obv**
|
||||
* _Positive Volume Index_: **pvi**
|
||||
* _Percentage Volume Oscillator_: **pvo**
|
||||
* _Price-Volume_: **pvol**
|
||||
* _Price Volume Rank_: **pvr**
|
||||
* _Price Volume Trend_: **pvt**
|
||||
* _Volume Profile_: **vp**
|
||||
* _Volume Weighted Average Price_: **vwap**
|
||||
* **Requires** the DataFrame index to be a DatetimeIndex
|
||||
* _Volume Weighted Moving Average_: **vwma**
|
||||
* _Worden Brothers Time Segmented Value_: **wb_tsv**
|
||||
|
||||
<br/>
|
||||
@@ -1114,7 +1115,7 @@ Back to [Contents](#contents)
|
||||
<br/>
|
||||
|
||||
# **Backtesting**
|
||||
While Pandas TA is not a backtesting application, Pandas TA does provide _two_ methods to help generate trading signals for backtesting purposes: **Trend Signals** (```ta.tsignals()```) and **Cross Signals** (```ta.xsignals()```). Both Signal methods return a DataFrame with columns for the Trend, Trades, Entries and Exits.
|
||||
While Pandas TA is not a backtesting application, it does provide _two_ trend methods that generate trading signals for backtesting purposes: **Trend Signals** (```ta.tsignals()```) and **Cross Signals** (```ta.xsignals()```). Both Signal methods return a DataFrame with columns for the signal's Trend, Trades, Entries and Exits.
|
||||
|
||||
A simple manual backtest using **Trend Signals** can be found in the [TA Analysis Notebook](https://github.com/twopirllc/pandas-ta/blob/main/examples/TA_Analysis.ipynb) starting at _Trend Creation_ cell.
|
||||
|
||||
@@ -1123,14 +1124,14 @@ A simple manual backtest using **Trend Signals** can be found in the [TA Analysi
|
||||
Trend Signals
|
||||
-------------
|
||||
* Useful for signals based on trends or **states**.
|
||||
* Examples
|
||||
* _Examples_
|
||||
* **Golden Cross**: ```df.ta.sma(length=50) > df.ta.sma(length=200)```
|
||||
* **Positive MACD Histogram**: ```df.ta.macd().iloc[:,1] > 0```
|
||||
|
||||
Cross Signals
|
||||
-------------
|
||||
* Useful for Signal Crossings or **events**.
|
||||
* Examples
|
||||
* _Examples_
|
||||
* RSI crosses above 30 and then below 70
|
||||
* ZSCORE crosses above -2 and then below 2.
|
||||
|
||||
@@ -1144,14 +1145,11 @@ _Ideally_ a backtesting application like [**vectorbt**](https://polakowo.io/vect
|
||||
Trend Signal Example
|
||||
--------------------
|
||||
```python
|
||||
import pandas as pd
|
||||
import pandas_ta as ta
|
||||
import vectorbt as vbt
|
||||
|
||||
df = pd.DataFrame()
|
||||
|
||||
# requires 'yfinance' installed
|
||||
df = df.ta.ticker("AAPL", timed=True)
|
||||
df = ta.df.ta.ticker("AAPL", timed=True)
|
||||
|
||||
# Create the "Golden Cross"
|
||||
df["GC"] = df.ta.sma(50, append=True) > df.ta.sma(200, append=True)
|
||||
@@ -1167,6 +1165,31 @@ print(pf.stats())
|
||||
print(pf.returns_stats())
|
||||
```
|
||||
|
||||
<br/>
|
||||
|
||||
Cross Signal Example
|
||||
--------------------
|
||||
```python
|
||||
import pandas_ta as ta
|
||||
import vectorbt as vbt
|
||||
|
||||
# requires 'yfinance' installed
|
||||
df = ta.df.ta.ticker("AAPL", timed=True)
|
||||
|
||||
# Signal when RSI crosses above 30 and later below 70
|
||||
rsi = df.ta.rsi(append=True)
|
||||
|
||||
# Create Cross Signals
|
||||
rsi_long = ta.xsignals(rsi, 20, 80, above=True)
|
||||
|
||||
# Create the Signals Portfolio
|
||||
pf = vbt.Portfolio.from_signals(df.Close, entries=rsi_long.TS_Entries, exits=rsi_long.TS_Exits, freq="D", init_cash=100_000, fees=0.0025, slippage=0.0025)
|
||||
|
||||
# Print Portfolio Stats and Return Stats
|
||||
print(pf.stats())
|
||||
print(pf.returns_stats())
|
||||
```
|
||||
|
||||
Back to [Contents](#contents)
|
||||
|
||||
<br/>
|
||||
|
||||
@@ -64,13 +64,16 @@ def cdl_pattern(
|
||||
pd.DataFrame: one column for each pattern.
|
||||
"""
|
||||
# Validate Arguments
|
||||
open_ = v_series(open_)
|
||||
high = v_series(high)
|
||||
low = v_series(low)
|
||||
close = v_series(close)
|
||||
open_ = v_series(open_, 1)
|
||||
high = v_series(high, 1)
|
||||
low = v_series(low, 1)
|
||||
close = v_series(close, 1)
|
||||
offset = v_offset(offset)
|
||||
scalar = v_scalar(scalar, 100)
|
||||
|
||||
if open_ is None or high is None or low is None or close is None:
|
||||
return
|
||||
|
||||
# Patterns that implemented in pandas-ta
|
||||
pta_patterns = {"doji": cdl_doji, "inside": cdl_inside}
|
||||
|
||||
|
||||
@@ -37,12 +37,15 @@ def ha(
|
||||
pd.DataFrame: ha_open, ha_high,ha_low, ha_close columns.
|
||||
"""
|
||||
# Validate
|
||||
open_ = v_series(open_)
|
||||
high = v_series(high)
|
||||
low = v_series(low)
|
||||
close = v_series(close)
|
||||
open_ = v_series(open_, 1)
|
||||
high = v_series(high, 1)
|
||||
low = v_series(low, 1)
|
||||
close = v_series(close, 1)
|
||||
offset = v_offset(offset)
|
||||
|
||||
if open_ is None or high is None or low is None or close is None:
|
||||
return
|
||||
|
||||
# Calculate
|
||||
m = close.size
|
||||
df = DataFrame({
|
||||
|
||||
+27
-24
@@ -607,6 +607,8 @@ class AnalysisIndicators(object):
|
||||
|
||||
# If All or a Category, exclude user list if any
|
||||
user_excluded = kwargs.pop("exclude", [])
|
||||
if isinstance(user_excluded, str) and len(user_excluded) > 1:
|
||||
user_excluded = [user_excluded]
|
||||
if mode["all"] or mode["category"]:
|
||||
excluded += user_excluded
|
||||
|
||||
@@ -634,7 +636,8 @@ class AnalysisIndicators(object):
|
||||
if "length" in kwds and kwds["length"] > self._df.shape[0]:
|
||||
_ = True
|
||||
if _: removal.append(kwds)
|
||||
if len(removal) > 0: [ta.remove(x) for x in removal]
|
||||
if len(removal) > 0:
|
||||
[ta.remove(x) for x in removal]
|
||||
|
||||
verbose = kwargs.pop("verbose", False)
|
||||
if verbose:
|
||||
@@ -1028,11 +1031,6 @@ class AnalysisIndicators(object):
|
||||
result = psl(close=close, open_=open_, length=length, scalar=scalar, drift=drift, offset=offset, **kwargs)
|
||||
return self._post_process(result, **kwargs)
|
||||
|
||||
def pvo(self, fast=None, slow=None, signal=None, scalar=None, offset: Int = None, **kwargs: DictLike):
|
||||
volume = self._get_column(kwargs.pop("volume", "volume"))
|
||||
result = pvo(volume=volume, fast=fast, slow=slow, signal=signal, scalar=scalar, offset=offset, **kwargs)
|
||||
return self._post_process(result, **kwargs)
|
||||
|
||||
def qqe(self, length=None, smooth=None, factor=None, mamode=None, offset: Int = None, **kwargs: DictLike):
|
||||
close = self._get_column(kwargs.pop("close", "close"))
|
||||
result = qqe(close=close, length=length, smooth=smooth, factor=factor, mamode=mamode, offset=offset, **kwargs)
|
||||
@@ -1330,24 +1328,6 @@ class AnalysisIndicators(object):
|
||||
result = vidya(close=close, length=length, offset=offset, **kwargs)
|
||||
return self._post_process(result, **kwargs)
|
||||
|
||||
def vwap(self, anchor=None, offset: Int = None, **kwargs: DictLike):
|
||||
high = self._get_column(kwargs.pop("high", "high"))
|
||||
low = self._get_column(kwargs.pop("low", "low"))
|
||||
close = self._get_column(kwargs.pop("close", "close"))
|
||||
volume = self._get_column(kwargs.pop("volume", "volume"))
|
||||
|
||||
if not self.datetime_ordered():
|
||||
volume.index = self._df.index
|
||||
|
||||
result = vwap(high=high, low=low, close=close, volume=volume, anchor=anchor, offset=offset, **kwargs)
|
||||
return self._post_process(result, **kwargs)
|
||||
|
||||
def vwma(self, volume=None, length=None, offset: Int = None, **kwargs: DictLike):
|
||||
close = self._get_column(kwargs.pop("close", "close"))
|
||||
volume = self._get_column(kwargs.pop("volume", "volume"))
|
||||
result = vwma(close=close, volume=volume, length=length, offset=offset, **kwargs)
|
||||
return self._post_process(result, **kwargs)
|
||||
|
||||
def wcp(self, offset: Int = None, **kwargs: DictLike):
|
||||
high = self._get_column(kwargs.pop("high", "high"))
|
||||
low = self._get_column(kwargs.pop("low", "low"))
|
||||
@@ -1768,6 +1748,11 @@ class AnalysisIndicators(object):
|
||||
result = pvi(close=close, volume=volume, length=length, initial=initial, signed=signed, offset=offset, **kwargs)
|
||||
return self._post_process(result, **kwargs)
|
||||
|
||||
def pvo(self, fast=None, slow=None, signal=None, scalar=None, offset: Int = None, **kwargs: DictLike):
|
||||
volume = self._get_column(kwargs.pop("volume", "volume"))
|
||||
result = pvo(volume=volume, fast=fast, slow=slow, signal=signal, scalar=scalar, offset=offset, **kwargs)
|
||||
return self._post_process(result, **kwargs)
|
||||
|
||||
def pvol(self, volume=None, offset: Int = None, **kwargs: DictLike):
|
||||
close = self._get_column(kwargs.pop("close", "close"))
|
||||
volume = self._get_column(kwargs.pop("volume", "volume"))
|
||||
@@ -1786,6 +1771,24 @@ class AnalysisIndicators(object):
|
||||
result = pvt(close=close, volume=volume, offset=offset, **kwargs)
|
||||
return self._post_process(result, **kwargs)
|
||||
|
||||
def vwap(self, anchor=None, offset: Int = None, **kwargs: DictLike):
|
||||
high = self._get_column(kwargs.pop("high", "high"))
|
||||
low = self._get_column(kwargs.pop("low", "low"))
|
||||
close = self._get_column(kwargs.pop("close", "close"))
|
||||
volume = self._get_column(kwargs.pop("volume", "volume"))
|
||||
|
||||
if not self.datetime_ordered():
|
||||
volume.index = self._df.index
|
||||
|
||||
result = vwap(high=high, low=low, close=close, volume=volume, anchor=anchor, offset=offset, **kwargs)
|
||||
return self._post_process(result, **kwargs)
|
||||
|
||||
def vwma(self, volume=None, length=None, offset: Int = None, **kwargs: DictLike):
|
||||
close = self._get_column(kwargs.pop("close", "close"))
|
||||
volume = self._get_column(kwargs.pop("volume", "volume"))
|
||||
result = vwma(close=close, volume=volume, length=length, offset=offset, **kwargs)
|
||||
return self._post_process(result, **kwargs)
|
||||
|
||||
def wb_tsv(self, length=None, signal=None, offset: Int = None, **kwargs: DictLike):
|
||||
close = self._get_column(kwargs.pop("close", "close"))
|
||||
volume = self._get_column(kwargs.pop("volume", "volume"))
|
||||
|
||||
+5
-5
@@ -49,9 +49,9 @@ Category: Dict[str, ListStr] = {
|
||||
"momentum": [
|
||||
"ao", "apo", "bias", "bop", "brar", "cci", "cfo", "cg", "cmo",
|
||||
"coppock", "cti", "er", "eri", "fisher", "inertia", "kdj", "kst",
|
||||
"macd", "mom", "pgo", "ppo", "psl", "pvo", "qqe", "roc", "rsi",
|
||||
"rsx", "rvgi", "slope", "smi", "squeeze", "squeeze_pro", "stc",
|
||||
"stoch", "stochf", "stochrsi", "td_seq", "trix", "tsi", "uo", "willr"
|
||||
"macd", "mom", "pgo", "ppo", "psl", "qqe", "roc", "rsi", "rsx",
|
||||
"rvgi", "slope", "smi", "squeeze", "squeeze_pro", "stc", "stoch",
|
||||
"stochf", "stochrsi", "td_seq", "trix", "tsi", "uo", "willr"
|
||||
],
|
||||
# Overlap
|
||||
"overlap": [
|
||||
@@ -59,7 +59,7 @@ Category: Dict[str, ListStr] = {
|
||||
"hma", "hwma", "ichimoku", "jma", "kama", "linreg", "mama",
|
||||
"mcgd", "midpoint", "midprice", "ohlc4", "pwma", "rma", "sinwma",
|
||||
"sma", "smma", "ssf", "ssf3", "supertrend", "swma", "t3", "tema",
|
||||
"trima", "vidya", "vwap", "vwma", "wcp", "wma", "zlma"
|
||||
"trima", "vidya", "wcp", "wma", "zlma"
|
||||
],
|
||||
# Performance
|
||||
"performance": ["log_return", "percent_return"],
|
||||
@@ -87,7 +87,7 @@ Category: Dict[str, ListStr] = {
|
||||
# Note: "vp" or "Volume Profile" is excluded since it does not return a Time Series
|
||||
"volume": [
|
||||
"ad", "adosc", "aobv", "cmf", "efi", "eom", "kvo", "mfi", "nvi",
|
||||
"obv", "pvi", "pvol", "pvr", "pvt", "wb_tsv"
|
||||
"obv", "pvi", "pvo", "pvol", "pvr", "pvt", "vwap", "vwma", "wb_tsv"
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ from .mom import mom
|
||||
from .pgo import pgo
|
||||
from .ppo import ppo
|
||||
from .psl import psl
|
||||
from .pvo import pvo
|
||||
from .qqe import qqe
|
||||
from .roc import roc
|
||||
from .rsi import rsi
|
||||
|
||||
@@ -50,7 +50,7 @@ def bop(
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
if Imports["talib"] and mode_tal:
|
||||
if Imports["talib"] and mode_tal and close.size:
|
||||
from talib import BOP
|
||||
bop = BOP(open_, high, low, close)
|
||||
else:
|
||||
|
||||
@@ -47,8 +47,8 @@ def dm(
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 14)
|
||||
high = v_series(high)
|
||||
low = v_series(low)
|
||||
high = v_series(high, length)
|
||||
low = v_series(low, length)
|
||||
|
||||
if high is None or low is None:
|
||||
return
|
||||
@@ -58,7 +58,7 @@ def dm(
|
||||
drift = v_drift(drift)
|
||||
offset = v_offset(offset)
|
||||
|
||||
if Imports["talib"] and mode_tal:
|
||||
if Imports["talib"] and mode_tal and high.size and low.size:
|
||||
from talib import MINUS_DM, PLUS_DM
|
||||
pos = PLUS_DM(high, low, length)
|
||||
neg = MINUS_DM(high, low, length)
|
||||
|
||||
@@ -1,8 +1,27 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# from numpy.ma import diff as np_ma_diff
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta._typing import Array, DictLike, Int
|
||||
from pandas_ta.maps import Imports
|
||||
from pandas_ta.utils import v_offset, v_pos_default, v_series, v_talib
|
||||
from pandas_ta.utils import (
|
||||
# np_prepend,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_series,
|
||||
v_talib
|
||||
)
|
||||
|
||||
|
||||
try:
|
||||
from numba import njit
|
||||
except ImportError:
|
||||
def njit(_): return _
|
||||
|
||||
|
||||
# Mockup
|
||||
# @njit
|
||||
# def np_mom(x: Array, n: Int):
|
||||
# return np_prepend(np_ma_diff(x, n), n)
|
||||
|
||||
|
||||
def mom(
|
||||
|
||||
@@ -1,15 +1,29 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat
|
||||
from pandas_ta._typing import Array, DictLike, Int, IntFloat
|
||||
from pandas_ta.maps import Imports
|
||||
from pandas_ta.utils import (
|
||||
np_shift,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_scalar,
|
||||
v_series,
|
||||
v_talib
|
||||
)
|
||||
from .mom import mom
|
||||
from .mom import mom#, np_mom
|
||||
|
||||
|
||||
# try:
|
||||
# from numba import njit
|
||||
# except ImportError:
|
||||
# def njit(_): return _
|
||||
|
||||
|
||||
# Mockup
|
||||
# @njit
|
||||
# def np_roc(x: Array, n: Int, k: IntFloat):
|
||||
# result = k * np_mom(x, n) / np_shift(x, n)
|
||||
# return result
|
||||
|
||||
|
||||
def roc(
|
||||
|
||||
@@ -31,8 +31,6 @@ from .t3 import t3
|
||||
from .tema import tema
|
||||
from .trima import trima
|
||||
from .vidya import vidya
|
||||
from .vwap import vwap
|
||||
from .vwma import vwma
|
||||
from .wcp import wcp
|
||||
from .wma import wma
|
||||
from .zlma import zlma
|
||||
|
||||
@@ -31,6 +31,9 @@ def hl2(
|
||||
low = v_series(low)
|
||||
offset = v_offset(offset)
|
||||
|
||||
if high is None or low is None:
|
||||
return
|
||||
|
||||
# Calculate
|
||||
avg = 0.5 * (high.values + low.values)
|
||||
hl2 = Series(avg, index=high.index)
|
||||
|
||||
@@ -35,8 +35,11 @@ def hlc3(
|
||||
mode_tal = v_talib(talib)
|
||||
offset = v_offset(offset)
|
||||
|
||||
if high is None or low is None or close is None:
|
||||
return
|
||||
|
||||
# Calculate
|
||||
if Imports["talib"] and mode_tal:
|
||||
if Imports["talib"] and mode_tal and close.size:
|
||||
from talib import TYPPRICE
|
||||
hlc3 = TYPPRICE(high, low, close)
|
||||
else:
|
||||
|
||||
@@ -17,7 +17,7 @@ def np_prepend(x: Array, n: Int, value: IntFloat = nan) -> Array:
|
||||
|
||||
|
||||
@njit
|
||||
def np_roll(x: Array, n: Int, fn = None) -> Array:
|
||||
def np_rolling(x: Array, n: Int, fn = None) -> Array:
|
||||
"""Like Pandas Rolling Window. x.rolling(n).fn()"""
|
||||
m = x.size
|
||||
result = zeros_like(x, dtype=float)
|
||||
|
||||
@@ -41,7 +41,7 @@ def hwc(
|
||||
pd.DataFrame: HWM (Mid), HWU (Upper), HWL (Lower) columns.
|
||||
"""
|
||||
# Validate
|
||||
close = v_series(close)
|
||||
close = v_series(close, 1)
|
||||
scalar = v_pos_default(scalar, 1)
|
||||
channels = v_bool(channels, False)
|
||||
na = v_pos_default(na, 0.2)
|
||||
@@ -50,6 +50,9 @@ def hwc(
|
||||
nd = v_pos_default(nd, 0.1)
|
||||
offset = v_offset(offset)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
# Calculate Result
|
||||
last_a = last_v = last_var = 0
|
||||
last_f = last_price = last_result = close[0]
|
||||
|
||||
@@ -10,8 +10,11 @@ from .mfi import mfi
|
||||
from .nvi import nvi
|
||||
from .obv import obv
|
||||
from .pvi import pvi
|
||||
from .pvo import pvo
|
||||
from .pvol import pvol
|
||||
from .pvr import pvr
|
||||
from .pvt import pvt
|
||||
from .vp import vp
|
||||
from .vwap import vwap
|
||||
from .vwma import vwma
|
||||
from .wb_tsv import wb_tsv
|
||||
|
||||
@@ -44,7 +44,7 @@ def ad(
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
if Imports["talib"] and mode_tal:
|
||||
if Imports["talib"] and mode_tal and volume.size:
|
||||
from talib import AD
|
||||
ad = AD(high, low, close, volume)
|
||||
else:
|
||||
|
||||
@@ -35,8 +35,8 @@ def nvi(
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 1)
|
||||
close = v_series(close, length)
|
||||
volume = v_series(volume, length)
|
||||
close = v_series(close, length + 1)
|
||||
volume = v_series(volume, length + 1)
|
||||
|
||||
if close is None or volume is None:
|
||||
return
|
||||
|
||||
@@ -34,8 +34,8 @@ def pvi(
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 1)
|
||||
close = v_series(close, length)
|
||||
volume = v_series(volume, length)
|
||||
close = v_series(close, length + 1)
|
||||
volume = v_series(volume, length + 1)
|
||||
|
||||
if close is None or volume is None:
|
||||
return
|
||||
|
||||
@@ -47,10 +47,11 @@ def vwap(
|
||||
pd.DataFrame: New feature generated.
|
||||
"""
|
||||
# Validate
|
||||
high = v_series(high)
|
||||
low = v_series(low)
|
||||
close = v_series(close)
|
||||
volume = v_series(volume)
|
||||
_length = 1
|
||||
high = v_series(high, _length)
|
||||
low = v_series(low, _length)
|
||||
close = v_series(close, _length)
|
||||
volume = v_series(volume, _length)
|
||||
bands = v_list(bands)
|
||||
offset = v_offset(offset)
|
||||
|
||||
@@ -60,7 +61,8 @@ def vwap(
|
||||
anchor = "D"
|
||||
|
||||
typical_price = hlc3(high=high, low=low, close=close)
|
||||
if not v_datetime_ordered(volume) or not v_datetime_ordered(typical_price):
|
||||
if not v_datetime_ordered(volume) or \
|
||||
not v_datetime_ordered(typical_price):
|
||||
print("[!] VWAP requires a datetime ordered index.")
|
||||
return
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numpy import isnan
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.ma import ma
|
||||
@@ -52,7 +53,7 @@ def wb_tsv(
|
||||
# Validate
|
||||
length = v_pos_default(length, 18)
|
||||
signal = v_pos_default(signal, 10)
|
||||
_length = max(length, signal) - 2
|
||||
_length = max(length, signal) + 1
|
||||
close = v_series(close, _length)
|
||||
|
||||
if close is None:
|
||||
@@ -69,6 +70,8 @@ def wb_tsv(
|
||||
cvd = signed_volume * close.diff(drift)
|
||||
|
||||
tsv = cvd.rolling(length).sum()
|
||||
if all(isnan(tsv)):
|
||||
return # Emergency Break
|
||||
signal_ = ma(mamode, tsv, length=signal)
|
||||
ratio = tsv / signal_
|
||||
|
||||
|
||||
+12
-4
@@ -112,7 +112,7 @@ class TestStudyMethods(TestCase):
|
||||
self.category = "Candles"
|
||||
self.data.ta.study(pandas_ta.AllStudy, verbose=verbose, timed=timed_test)
|
||||
|
||||
# @skipUnless(verbose, "verbose mode only")
|
||||
@skipUnless(verbose, "verbose mode only")
|
||||
def test_all_without_append(self):
|
||||
"""Study: All sans append"""
|
||||
self.category = "All: Sans append"
|
||||
@@ -230,10 +230,18 @@ class TestStudyMethods(TestCase):
|
||||
)
|
||||
self.data.ta.study(custom, verbose=verbose, timed=timed_test)
|
||||
|
||||
def test_custom_ohlc(self):
|
||||
"""Custom E: OHLC"""
|
||||
self.category = "Custom E: OHLC"
|
||||
|
||||
self.data.rename(columns={"volume": "_v"}, inplace=True)
|
||||
self.data.ta.study(exclude=pandas_ta.Category["volume"], verbose=verbose, timed=timed_test)
|
||||
self.data.rename(columns={"_v": "volume"}, inplace=True)
|
||||
|
||||
# @skip
|
||||
def test_custom_e(self):
|
||||
"""Custom E"""
|
||||
self.category = "Custom E"
|
||||
def test_custom_study_with_signals(self):
|
||||
"""Custom F: Custom Study with Signals"""
|
||||
self.category = "Custom F: Custom Study with Signals"
|
||||
|
||||
amat_logret_ta = [
|
||||
{"kind": "amat", "fast": 20, "slow": 50 }, # 2
|
||||
|
||||
Reference in New Issue
Block a user