mirror of
https://github.com/wassname/pandas-ta.git
synced 2026-08-16 11:25:01 +08:00
@@ -66,6 +66,7 @@ and _Weighted Moving Average_.
|
||||
issue of Stocks & Commodities Magazine. It is a moving average based trend
|
||||
indicator consisting of two different simple moving averages.
|
||||
* _Stochastic RSI_ (**stochrsi**) "Stochastic RSI and Dynamic Momentum Index" was created by Tushar Chande and Stanley Kroll. In line with Trading View's calculation. See: ```help(ta.stochrsi)```
|
||||
* _Inside Bar_ (**cdl_inside**) An Inside Bar is a bar contained within it's previous bar's high and low See: ```help(ta.cdl_inside)```
|
||||
|
||||
## __Updated Indicators__
|
||||
* _Fisher Transform_ (**fisher**): Added Fisher's default **ema** signal line. To change the length of the signal line, use the argument: ```signal=5```. Default: 5
|
||||
@@ -320,9 +321,10 @@ print(bothhl2.name) # "pre_HL2_post"
|
||||
|
||||
# __Technical Analysis Indicators__ (_by Category_)
|
||||
|
||||
## _Candles_ (2)
|
||||
## _Candles_ (3)
|
||||
|
||||
* _Doji_: **cdl_doji**
|
||||
* _Inside Bar_: **cdl_inside**
|
||||
* _Heikin-Ashi_: **ha**
|
||||
|
||||
## _Momentum_ (33)
|
||||
@@ -504,6 +506,7 @@ Use parameter: cumulative=**True** for cumulative results.
|
||||
# Contributors
|
||||
* [alexonab](https://github.com/alexonab)
|
||||
* [allahyarzadeh](https://github.com/allahyarzadeh)
|
||||
* [DrPaprikaa](https://github.com/DrPaprikaa)
|
||||
* [FGU1](https://github.com/FGU1)
|
||||
* [lluissalord](https://github.com/lluissalord)
|
||||
* [SoftDevDanial](https://github.com/SoftDevDanial)
|
||||
|
||||
@@ -22,7 +22,7 @@ else:
|
||||
# Will find a dynamic solution later.
|
||||
Category = {
|
||||
# Candles
|
||||
"candles": ["cdl_doji", "ha"],
|
||||
"candles": ["cdl_doji", "cdl_inside", "ha"],
|
||||
|
||||
# Momentum
|
||||
"momentum": ["ao", "apo", "bias", "bop", "brar", "cci", "cg", "cmo", "coppock", "er", "eri", "fisher", "inertia", "kdj", "kst", "macd", "mom", "pgo", "ppo", "psl", "pvo", "roc", "rsi", "rvgi", "slope", "smi", "squeeze", "stoch", "stochrsi", "trix", "tsi", "uo", "willr"],
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from .ha import ha
|
||||
from .cdl_doji import cdl_doji
|
||||
from .cdl_doji import cdl_doji
|
||||
from .cdl_inside import cdl_inside
|
||||
@@ -0,0 +1,74 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import DataFrame, set_option
|
||||
from pandas_ta.utils import candle_color, get_drift, get_offset
|
||||
from pandas_ta.utils import non_zero_range, real_body, verify_series
|
||||
|
||||
def cdl_inside(open_, high, low, close, asbool=False, offset=None, **kwargs):
|
||||
"""Candle Type: Inside Bar"""
|
||||
# Validate arguments
|
||||
open_ = verify_series(open_)
|
||||
high = verify_series(high)
|
||||
low = verify_series(low)
|
||||
close = verify_series(close)
|
||||
offset = get_offset(offset)
|
||||
|
||||
# Calculate Result
|
||||
inside = (high.diff() < 0) & (low.diff() > 0)
|
||||
|
||||
if not asbool:
|
||||
inside *= candle_color(open_, close)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
inside = inside.shift(offset)
|
||||
|
||||
# Handle fills
|
||||
if "fillna" in kwargs:
|
||||
inside.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
if "fill_method" in kwargs:
|
||||
inside.fillna(method=kwargs["fill_method"], inplace=True)
|
||||
|
||||
# Name and Categorize it
|
||||
inside.name = f"CDL_INSIDE"
|
||||
inside.category = "candles"
|
||||
|
||||
return inside
|
||||
|
||||
|
||||
|
||||
cdl_inside.__doc__ = \
|
||||
"""Candle Type: Inside Bar
|
||||
|
||||
An Inside Bar is a bar that is engulfed by the prior highs and lows of it's
|
||||
previous bar. In other words, the current bar is smaller than it's previous bar.
|
||||
Set asbool=True if you want to know if it is an Inside Bar. Note by default
|
||||
asbool=False so this returns a 0 if it is not an Inside Bar, 1 if it is an
|
||||
Inside Bar and close > open, and -1 if it is an Inside Bar but close < open.
|
||||
|
||||
Sources:
|
||||
https://www.tradingview.com/script/IyIGN1WO-Inside-Bar/
|
||||
|
||||
Calculation:
|
||||
Default Inputs:
|
||||
asbool=False
|
||||
inside = (high.diff() < 0) & (low.diff() > 0)
|
||||
|
||||
if not asbool:
|
||||
inside *= candle_color(open_, close)
|
||||
|
||||
Args:
|
||||
open_ (pd.Series): Series of 'open's
|
||||
high (pd.Series): Series of 'high's
|
||||
low (pd.Series): Series of 'low's
|
||||
close (pd.Series): Series of 'close's
|
||||
asbool (bool): Returns the boolean result. 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
|
||||
"""
|
||||
+11
-1
@@ -23,7 +23,7 @@ from pandas_ta.volatility import *
|
||||
from pandas_ta.volume import *
|
||||
from pandas_ta.utils import *
|
||||
|
||||
version = ".".join(("0", "2", "01b"))
|
||||
version = ".".join(("0", "2", "02b"))
|
||||
|
||||
|
||||
def mp_worker(args):
|
||||
@@ -610,6 +610,16 @@ class AnalysisIndicators(BasePandasObject):
|
||||
result = cdl_doji(open_=open_, high=high, low=low, close=close, offset=offset, **kwargs)
|
||||
return result
|
||||
|
||||
@finalize
|
||||
def cdl_inside(self, open_=None, high=None, low=None, close=None, offset=None, **kwargs):
|
||||
open_ = self._get_column(open_, "open")
|
||||
high = self._get_column(high, "high")
|
||||
low = self._get_column(low, "low")
|
||||
close = self._get_column(close, "close")
|
||||
|
||||
result = cdl_inside(open_=open_, high=high, low=low, close=close, offset=offset, **kwargs)
|
||||
return result
|
||||
|
||||
@finalize
|
||||
def ha(self, open_=None, high=None, low=None, close=None, offset=None, **kwargs):
|
||||
open_ = self._get_column(open_, "open")
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
import pandas as pd
|
||||
from pandas_ta.utils import get_offset , verify_series , zero
|
||||
|
||||
def inbar(self , open , high ,low , close , offset = None , **kwargs ):
|
||||
"""Indicator: Inside Bar"""
|
||||
# Validate arguments
|
||||
close = verify_series(close).apply(zero)
|
||||
open = verify_series(open).apply(zero)
|
||||
high = verify_series(high).apply(zero)
|
||||
low = verify_series(low).apply(zero)
|
||||
offset = get_offset(offset)
|
||||
prevBar = 1
|
||||
|
||||
# Calculate Result
|
||||
bodyStat = (close >= open).rename('bodystat').replace({True: 1 , False:-1})
|
||||
isIn = ((high < high.shift(prevBar)) & (low > low.shift(prevBar))).rename('isin')
|
||||
res = pd.Series(index = close.index , dtype = 'int64')
|
||||
|
||||
for i in close.index:
|
||||
if isIn[i] == True:
|
||||
res[i] = bodyStat[i]
|
||||
else:
|
||||
res[i] = 0
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
res = res.shift(offset)
|
||||
|
||||
# Handle fills
|
||||
if 'fillna' in kwargs:
|
||||
res.fillna(kwargs['fillna'], inplace=True)
|
||||
|
||||
if 'fill_method' in kwargs:
|
||||
res.fillna(method=kwargs['fill_method'], inplace=True)
|
||||
|
||||
# Name and Categorize it
|
||||
res.name = "InBar"
|
||||
res.category = 'insidebar'
|
||||
|
||||
return res
|
||||
|
||||
inbar.__doc__ = \
|
||||
"""Inside Bar
|
||||
Sources:
|
||||
https://www.tradingview.com/script/IyIGN1WO-Inside-Bar/
|
||||
Calculation:
|
||||
Default Inputs:
|
||||
drift=1
|
||||
isIn = ((high < high.shift(prevBar)) & (low > low.shift(prevBar)))
|
||||
bodyStat = (close >= open)
|
||||
Args:
|
||||
high (pd.Series): Series of 'high's
|
||||
low (pd.Series): Series of 'low's
|
||||
close (pd.Series): Series of 'close's
|
||||
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
|
||||
"""
|
||||
@@ -1,18 +1,17 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from .ema import ema
|
||||
from ..utils import get_offset, verify_series, weights
|
||||
from pandas_ta.utils import get_offset, verify_series
|
||||
|
||||
def dema(close, length=None, offset=None, **kwargs):
|
||||
"""Indicator: Double Exponential Moving Average (DEMA)"""
|
||||
# Validate Arguments
|
||||
close = verify_series(close)
|
||||
length = int(length) if length and length > 0 else 10
|
||||
min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length
|
||||
offset = get_offset(offset)
|
||||
|
||||
# Calculate Result
|
||||
ema1 = ema(close=close, length=length, **kwargs)
|
||||
ema2 = ema(close=ema1, length=length, **kwargs)
|
||||
ema1 = ema(close=close, length=length)
|
||||
ema2 = ema(close=ema1, length=length)
|
||||
dema = 2 * ema1 - ema2
|
||||
|
||||
# Offset
|
||||
@@ -21,7 +20,7 @@ def dema(close, length=None, offset=None, **kwargs):
|
||||
|
||||
# Name & Category
|
||||
dema.name = f"DEMA_{length}"
|
||||
dema.category = 'overlap'
|
||||
dema.category = "overlap"
|
||||
|
||||
return dema
|
||||
|
||||
|
||||
+58
-54
@@ -3,8 +3,14 @@ import math
|
||||
from pathlib import Path
|
||||
from time import perf_counter
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from numpy import argmax, argmin, dot, ones, triu
|
||||
from numpy import append as npAppend
|
||||
from numpy import array as npArray
|
||||
from numpy import ndarray as npNdArray
|
||||
from numpy import sum as npSum
|
||||
|
||||
from pandas import DataFrame, Series
|
||||
from pandas.api.types import is_datetime64_any_dtype
|
||||
|
||||
from functools import reduce
|
||||
from operator import mul
|
||||
@@ -16,8 +22,8 @@ MINUTES_PER_HOUR = 60
|
||||
|
||||
|
||||
def _above_below(
|
||||
series_a: pd.Series,
|
||||
series_b: pd.Series,
|
||||
series_a: Series,
|
||||
series_b: Series,
|
||||
above: bool = True,
|
||||
asint: bool = True,
|
||||
offset: int = None,
|
||||
@@ -51,8 +57,8 @@ def _above_below(
|
||||
|
||||
|
||||
def above(
|
||||
series_a: pd.Series,
|
||||
series_b: pd.Series,
|
||||
series_a: Series,
|
||||
series_b: Series,
|
||||
asint: bool = True,
|
||||
offset: int = None,
|
||||
**kwargs
|
||||
@@ -61,7 +67,7 @@ def above(
|
||||
|
||||
|
||||
def above_value(
|
||||
series_a: pd.Series,
|
||||
series_a: Series,
|
||||
value: float,
|
||||
asint: bool = True,
|
||||
offset: int = None,
|
||||
@@ -70,13 +76,13 @@ def above_value(
|
||||
if not isinstance(value, (int, float, complex)):
|
||||
print("[X] value is not a number")
|
||||
return
|
||||
series_b = pd.Series(value, index=series_a.index, name=f"{value}".replace(".","_"))
|
||||
series_b = Series(value, index=series_a.index, name=f"{value}".replace(".","_"))
|
||||
return _above_below(series_a, series_b, above=True, asint=asint, offset=offset, **kwargs)
|
||||
|
||||
|
||||
def below(
|
||||
series_a: pd.Series,
|
||||
series_b: pd.Series,
|
||||
series_a: Series,
|
||||
series_b: Series,
|
||||
asint: bool =True,
|
||||
offset: int =None
|
||||
,**kwargs
|
||||
@@ -85,7 +91,7 @@ def below(
|
||||
|
||||
|
||||
def below_value(
|
||||
series_a: pd.Series,
|
||||
series_a: Series,
|
||||
value: float,
|
||||
asint: bool = True,
|
||||
offset: int = None,
|
||||
@@ -94,7 +100,7 @@ def below_value(
|
||||
if not isinstance(value, (int, float, complex)):
|
||||
print("[X] value is not a number")
|
||||
return
|
||||
series_b = pd.Series(value, index=series_a.index, name=f"{value}".replace(".","_"))
|
||||
series_b = Series(value, index=series_a.index, name=f"{value}".replace(".","_"))
|
||||
return _above_below(series_a, series_b, above=False, asint=asint, offset=offset, **kwargs)
|
||||
|
||||
|
||||
@@ -123,20 +129,20 @@ def combination(**kwargs):
|
||||
|
||||
|
||||
def cross_value(
|
||||
series_a: pd.Series,
|
||||
series_a: Series,
|
||||
value: float,
|
||||
above: bool = True,
|
||||
asint: bool = True,
|
||||
offset: int = None,
|
||||
**kwargs
|
||||
):
|
||||
series_b = pd.Series(value, index=series_a.index, name=f"{value}".replace(".","_"))
|
||||
series_b = Series(value, index=series_a.index, name=f"{value}".replace(".","_"))
|
||||
return cross(series_a, series_b, above, asint, offset, **kwargs)
|
||||
|
||||
|
||||
def cross(
|
||||
series_a: pd.Series,
|
||||
series_b: pd.Series,
|
||||
series_a: Series,
|
||||
series_b: Series,
|
||||
above: bool = True,
|
||||
asint: bool = True,
|
||||
offset: int = None,
|
||||
@@ -169,9 +175,9 @@ def cross(
|
||||
return cross
|
||||
|
||||
|
||||
def is_datetime_ordered(df: pd.DataFrame or pd.Series) -> bool:
|
||||
def is_datetime_ordered(df: DataFrame or Series) -> bool:
|
||||
"""Returns True if the index is a datetime and ordered."""
|
||||
index_is_datetime = pd.api.types.is_datetime64_any_dtype(df.index)
|
||||
index_is_datetime = is_datetime64_any_dtype(df.index)
|
||||
try:
|
||||
ordered = df.index[0] < df.index[-1]
|
||||
except RuntimeWarning: pass
|
||||
@@ -179,8 +185,8 @@ def is_datetime_ordered(df: pd.DataFrame or pd.Series) -> bool:
|
||||
return True if index_is_datetime and ordered else False
|
||||
|
||||
|
||||
def signals(indicator, xa, xb, cross_values, xserie, xserie_a, xserie_b, cross_series, offset) -> pd.DataFrame:
|
||||
df = pd.DataFrame()
|
||||
def signals(indicator, xa, xb, cross_values, xserie, xserie_a, xserie_b, cross_series, offset) -> DataFrame:
|
||||
df = DataFrame()
|
||||
if xa is not None and isinstance(xa, (int, float)):
|
||||
if cross_values:
|
||||
crossed_above_start = cross_value(indicator, xa, above=True, offset=offset)
|
||||
@@ -226,7 +232,7 @@ def signals(indicator, xa, xb, cross_values, xserie, xserie_a, xserie_b, cross_s
|
||||
return df
|
||||
|
||||
|
||||
def df_error_analysis(dfA: pd.DataFrame, dfB: pd.DataFrame, **kwargs) -> pd.DataFrame:
|
||||
def df_error_analysis(dfA: DataFrame, dfB: DataFrame, **kwargs) -> DataFrame:
|
||||
"""DataFrame Correlation Analysis helper"""
|
||||
corr_method = kwargs.pop("corr_method", "pearson")
|
||||
|
||||
@@ -241,29 +247,29 @@ def df_error_analysis(dfA: pd.DataFrame, dfB: pd.DataFrame, **kwargs) -> pd.Data
|
||||
diff.plot(kind="kde")
|
||||
|
||||
if kwargs.pop("triangular", False):
|
||||
return corr.where(np.triu(np.ones(corr.shape)).astype(np.bool))
|
||||
return corr.where(triu(ones(corr.shape)).astype(bool))
|
||||
|
||||
return corr
|
||||
|
||||
def fibonacci(**kwargs) -> np.ndarray:
|
||||
def fibonacci(n: int = 2, **kwargs) -> npNdArray:
|
||||
"""Fibonacci Sequence as a numpy array"""
|
||||
n = int(math.fabs(kwargs.pop("n", 2)))
|
||||
zero = kwargs.pop("zero", False)
|
||||
weighted = kwargs.pop("weighted", False)
|
||||
n = int(math.fabs(n)) if n >= 0 else 2
|
||||
|
||||
zero = kwargs.pop("zero", False)
|
||||
if zero:
|
||||
a, b = 0, 1
|
||||
else:
|
||||
n -= 1
|
||||
a, b = 1, 1
|
||||
|
||||
result = np.array([a])
|
||||
result = npArray([a])
|
||||
for i in range(0, n):
|
||||
a, b = b, a + b
|
||||
result = np.append(result, a)
|
||||
result = npAppend(result, a)
|
||||
|
||||
weighted = kwargs.pop("weighted", False)
|
||||
if weighted:
|
||||
fib_sum = np.sum(result)
|
||||
fib_sum = npSum(result)
|
||||
if fib_sum > 0:
|
||||
return result / fib_sum
|
||||
else:
|
||||
@@ -279,12 +285,12 @@ def final_time(stime):
|
||||
|
||||
def get_drift(x: int) -> int:
|
||||
"""Returns an int if not zero, otherwise defaults to one."""
|
||||
return int(x) if x and x != 0 else 1
|
||||
return int(x) if isinstance(x, int) and x != 0 else 1
|
||||
|
||||
|
||||
def get_offset(x: int) -> int:
|
||||
"""Returns an int, otherwise defaults to zero."""
|
||||
return int(x) if x else 0
|
||||
return int(x) if isinstance(x, int) else 0
|
||||
|
||||
|
||||
def is_percent(x: int or float) -> bool:
|
||||
@@ -293,9 +299,8 @@ def is_percent(x: int or float) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def non_zero_range(high: pd.Series, low: pd.Series) -> pd.Series:
|
||||
"""Returns the difference of two series and adds epsilon if
|
||||
to any zero values. This occurs commonly in crypto data when
|
||||
def non_zero_range(high: Series, low: Series) -> Series:
|
||||
"""Returns the difference of two series and adds epsilon to any zero values. This occurs commonly in crypto data when
|
||||
high = low.
|
||||
"""
|
||||
diff = high - low
|
||||
@@ -304,7 +309,7 @@ def non_zero_range(high: pd.Series, low: pd.Series) -> pd.Series:
|
||||
return diff
|
||||
|
||||
|
||||
def pascals_triangle(n: int = None, **kwargs) -> np.ndarray:
|
||||
def pascals_triangle(n: int = None, **kwargs) -> npNdArray:
|
||||
"""Pascal's Triangle
|
||||
|
||||
Returns a numpy array of the nth row of Pascal's Triangle.
|
||||
@@ -313,15 +318,15 @@ def pascals_triangle(n: int = None, **kwargs) -> np.ndarray:
|
||||
=> inverse weighted: [0.9375, 0.75, 0.625, 0.75, 0.9375]
|
||||
"""
|
||||
n = int(math.fabs(n)) if n is not None else 0
|
||||
weighted = kwargs.pop("weighted", False)
|
||||
inverse = kwargs.pop("inverse", False)
|
||||
|
||||
# Calculation
|
||||
triangle = np.array([combination(n=n, r=i) for i in range(0, n + 1)])
|
||||
triangle_sum = np.sum(triangle)
|
||||
triangle = npArray([combination(n=n, r=i) for i in range(0, n + 1)])
|
||||
triangle_sum = npSum(triangle)
|
||||
triangle_weights = triangle / triangle_sum
|
||||
inverse_weights = 1 - triangle_weights
|
||||
|
||||
weighted = kwargs.pop("weighted", False)
|
||||
inverse = kwargs.pop("inverse", False)
|
||||
if weighted and inverse:
|
||||
return inverse_weights
|
||||
if weighted:
|
||||
@@ -333,20 +338,20 @@ def pascals_triangle(n: int = None, **kwargs) -> np.ndarray:
|
||||
|
||||
|
||||
def recent_maximum_index(x):
|
||||
return int(np.argmax(x[::-1]))
|
||||
return int(argmax(x[::-1]))
|
||||
|
||||
|
||||
def recent_minimum_index(x):
|
||||
return int(np.argmin(x[::-1]))
|
||||
return int(argmin(x[::-1]))
|
||||
|
||||
|
||||
def signed_series(series: pd.Series, initial: int =None) -> pd.Series:
|
||||
def signed_series(series: Series, initial: int = None) -> Series:
|
||||
"""Returns a Signed Series with or without an initial value
|
||||
|
||||
Default Example:
|
||||
series = pd.Series([3, 2, 2, 1, 1, 5, 6, 6, 7, 5])
|
||||
series = Series([3, 2, 2, 1, 1, 5, 6, 6, 7, 5])
|
||||
and returns:
|
||||
sign = pd.Series([NaN, -1.0, 0.0, -1.0, 0.0, 1.0, 1.0, 0.0, 1.0, -1.0])
|
||||
sign = Series([NaN, -1.0, 0.0, -1.0, 0.0, 1.0, 1.0, 0.0, 1.0, -1.0])
|
||||
"""
|
||||
series = verify_series(series)
|
||||
sign = series.diff(1)
|
||||
@@ -364,7 +369,6 @@ def symmetric_triangle(n: int = None, **kwargs) -> list:
|
||||
=> weighted: [0.16666667 0.33333333 0.33333333 0.16666667]
|
||||
"""
|
||||
n = int(math.fabs(n)) if n is not None else 2
|
||||
weighted = kwargs.pop("weighted", False)
|
||||
|
||||
if n == 2:
|
||||
triangle = [1, 1]
|
||||
@@ -379,24 +383,24 @@ def symmetric_triangle(n: int = None, **kwargs) -> list:
|
||||
front.pop()
|
||||
triangle += front[::-1]
|
||||
|
||||
if weighted:
|
||||
triangle_sum = np.sum(triangle)
|
||||
if kwargs.pop("weighted", False):
|
||||
triangle_sum = npSum(triangle)
|
||||
triangle_weights = triangle / triangle_sum
|
||||
return triangle_weights
|
||||
|
||||
return triangle
|
||||
|
||||
|
||||
def unsigned_differences(series: pd.Series, amount: int = None, **kwargs) -> pd.Series:
|
||||
def unsigned_differences(series: Series, amount: int = None, **kwargs) -> Series:
|
||||
"""Unsigned Differences
|
||||
Returns two Series, an unsigned positive and unsigned negative series based
|
||||
on the differences of the original series. The positive series are only the
|
||||
increases and the negative series is only the decreases.
|
||||
|
||||
Default Example:
|
||||
series = pd.Series([3, 2, 2, 1, 1, 5, 6, 6, 7, 5, 3]) and returns
|
||||
postive = pd.Series([0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0])
|
||||
negative = pd.Series([0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1])
|
||||
series = Series([3, 2, 2, 1, 1, 5, 6, 6, 7, 5, 3]) and returns
|
||||
postive = Series([0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0])
|
||||
negative = Series([0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1])
|
||||
"""
|
||||
amount = int(amount) if amount is not None else 1
|
||||
negative = series.diff(amount)
|
||||
@@ -416,15 +420,15 @@ def unsigned_differences(series: pd.Series, amount: int = None, **kwargs) -> pd.
|
||||
return positive, negative
|
||||
|
||||
|
||||
def verify_series(series: pd.Series) -> pd.Series:
|
||||
def verify_series(series: Series) -> Series:
|
||||
"""If a Pandas Series return it."""
|
||||
if series is not None and isinstance(series, pd.core.series.Series):
|
||||
if series is not None and isinstance(series, Series):
|
||||
return series
|
||||
|
||||
|
||||
def weights(w):
|
||||
def _dot(x):
|
||||
return np.dot(w, x)
|
||||
return dot(w, x)
|
||||
return _dot
|
||||
|
||||
|
||||
|
||||
@@ -53,3 +53,12 @@ class TestCandle(TestCase):
|
||||
self.assertGreater(corr, CORRELATION_THRESHOLD)
|
||||
except Exception as ex:
|
||||
error_analysis(result, CORRELATION, ex)
|
||||
|
||||
def test_cdl_inside(self):
|
||||
result = pandas_ta.cdl_inside(self.open, self.high, self.low, self.close)
|
||||
self.assertIsInstance(result, Series)
|
||||
self.assertEqual(result.name, "CDL_INSIDE")
|
||||
|
||||
result = pandas_ta.cdl_inside(self.open, self.high, self.low, self.close, asbool=True)
|
||||
self.assertIsInstance(result, Series)
|
||||
self.assertEqual(result.name, "CDL_INSIDE")
|
||||
@@ -23,12 +23,17 @@ class TestCandleExtension(TestCase):
|
||||
pass
|
||||
|
||||
|
||||
def test_ha_ext(self):
|
||||
self.data.ta.ha(append=True)
|
||||
self.assertIsInstance(self.data, DataFrame)
|
||||
self.assertEqual(list(self.data.columns[-4:]), ["HA_open", "HA_high", "HA_low", "HA_close"])
|
||||
|
||||
def test_cdl_doji_ext(self):
|
||||
self.data.ta.cdl_doji(append=True)
|
||||
self.assertIsInstance(self.data, DataFrame)
|
||||
self.assertEqual(self.data.columns[-1], "CDL_DOJI_10_0.1")
|
||||
self.assertEqual(self.data.columns[-1], "CDL_DOJI_10_0.1")
|
||||
|
||||
def test_cdl_inside_ext(self):
|
||||
self.data.ta.cdl_inside(append=True)
|
||||
self.assertIsInstance(self.data, DataFrame)
|
||||
self.assertEqual(self.data.columns[-1], "CDL_INSIDE")
|
||||
|
||||
def test_ha_ext(self):
|
||||
self.data.ta.ha(append=True)
|
||||
self.assertIsInstance(self.data, DataFrame)
|
||||
self.assertEqual(list(self.data.columns[-4:]), ["HA_open", "HA_high", "HA_low", "HA_close"])
|
||||
Reference in New Issue
Block a user