Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(feat) : Adding standard deviation functionality to linear regression #769

Open
wants to merge 2 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 36 additions & 17 deletions pandas_ta/overlap/linreg.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def linreg(
r (bool, optional): If True, returns it's correlation 'r'.
Default: False.
slope (bool, optional): If True, returns the slope. Default: False.
stdev (bool, optional): If True, returns the Standard Deviation.
tsf (bool, optional): If True, returns the Time Series Forecast value.
Default: False.
fillna (value, optional): pd.DataFrame.fillna(value)
Expand All @@ -68,22 +69,23 @@ def linreg(
r = kwargs.pop("r", False)
slope = kwargs.pop("slope", False)
tsf = kwargs.pop("tsf", False)
stdev = kwargs.pop("stdev", False)

# Calculate
np_close = close.values

if Imports["talib"] and mode_tal and not r:
from talib import LINEARREG, LINEARREG_ANGLE, LINEARREG_INTERCEPT, LINEARREG_SLOPE, TSF
if tsf:
linreg = TSF(close, timeperiod=length)
_linreg = TSF(close, timeperiod=length)
elif slope:
linreg = LINEARREG_SLOPE(close, timeperiod=length)
_linreg = LINEARREG_SLOPE(close, timeperiod=length)
elif intercept:
linreg = LINEARREG_INTERCEPT(close, timeperiod=length)
_linreg = LINEARREG_INTERCEPT(close, timeperiod=length)
elif angle:
linreg = LINEARREG_ANGLE(close, timeperiod=length)
_linreg = LINEARREG_ANGLE(close, timeperiod=length)
else:
linreg = LINEARREG(close, timeperiod=length)
_linreg = LINEARREG(close, timeperiod=length)
else:
linreg_ = zeros_like(np_close)
# [1, 2, ..., n] from 1 to n keeps Sum(xy) low
Expand Down Expand Up @@ -119,6 +121,17 @@ def linear_regression(series):
return rn / rd

return m * length + b if not tsf else m * (length - 1) + b

def stdevlinreg(close, length):
x_value = close
stdev = close
slope = linreg(close=close, length=length, slope=True)
tsf = linreg(close=close, length=length, tsf=True)
variance = 0
for i in range(1, length):
variance += (x_value.shift(i) - (tsf - i * slope)) ** 2
stdev = (variance / (length - 1)) ** 0.5
return stdev

if np_version >= "1.20.0":
from numpy.lib.stride_tricks import sliding_window_view
Expand All @@ -133,30 +146,36 @@ def linear_regression(series):
np_close, length)
]

linreg = Series([nan] * (length - 1) + linreg_, index=close.index)
_linreg = Series([nan] * (length - 1) + linreg_, index=close.index)

# Offset
if offset != 0:
linreg = linreg.shift(offset)
_linreg = _linreg.shift(offset)

# Standard Deviation
if stdev:
_linreg = stdevlinreg(close, length)

# Fill
if "fillna" in kwargs:
linreg.fillna(kwargs["fillna"], inplace=True)
_linreg.fillna(kwargs["fillna"], inplace=True)
if "fill_method" in kwargs:
linreg.fillna(method=kwargs["fill_method"], inplace=True)
_linreg.fillna(method=kwargs["fill_method"], inplace=True)

# Name and Category
linreg.name = f"LINREG"
_linreg.name = f"LINREG"
if slope:
linreg.name += "m"
_linreg.name += "m"
if intercept:
linreg.name += "b"
_linreg.name += "b"
if angle:
linreg.name += "a"
_linreg.name += "a"
if r:
linreg.name += "r"
_linreg.name += "r"
if stdev:
_linreg.name += "stdev"

linreg.name += f"_{length}"
linreg.category = "overlap"
_linreg.name += f"_{length}"
_linreg.category = "overlap"

return linreg
return _linreg
4 changes: 4 additions & 0 deletions tests/test_indicator_overlap.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,10 @@ def test_linreg_slope(df):
assert isinstance(result, Series)
assert result.name == "LINREGm_14"

def test_linreg_stdev(df):
result = ta.linreg(df.close, stdev=True, talib=False)
assert isinstance(result, Series)
assert result.name == "LINREGstdev_14"

def test_ma(df):
result = ta.ma()
Expand Down