mirror of
https://github.com/wassname/pandas-ta.git
synced 2026-07-23 13:00:50 +08:00
ENH cfo indicator added MAINT linreg refactor
This commit is contained in:
@@ -67,14 +67,15 @@ Thank you for your contribution!
|
||||
* _Linear Decay_ (**linear_decay**): Renamed to _Decay_ (**decay**) and with the option for Exponential decay using ```mode="exp"```. See: ```help(ta.decay)```
|
||||
|
||||
## __New Indicators__
|
||||
* _Squeeze_ (**squeeze**). A Momentum indicator. Both John Carter's TTM **and** Lazybear's TradingView versions are implemented. The default is John Carter's, or ```lazybear=False```. Set ```lazybear=True``` to enable Lazybear's.
|
||||
* _TTM Trend_ (**ttm_trend**). A trend indicator inspired from John Carter's book "Mastering the Trade".
|
||||
* _Chande Forecast Oscillator_ (**cfo**) It calculates the percentage difference between the actual price and the Time Series Forecast (the endpoint of a linear regression line).
|
||||
* _Gann High-Low Activator_ (**hilo**) The Gann High Low Activator Indicator was created by Robert Krausz in a 1998.
|
||||
* _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)```
|
||||
* _SMI Ergodic_ (**smi**) Developed by William Blau, the SMI Ergodic Indicator is the same as the True Strength Index (TSI) except the SMI includes a signal line and oscillator.
|
||||
* _Gann High-Low Activator_ (**hilo**) The Gann High Low Activator Indicator was created by Robert Krausz in a 1998
|
||||
* _Squeeze_ (**squeeze**). A Momentum indicator. Both John Carter's TTM **and** Lazybear's TradingView versions are implemented. The default is John Carter's, or ```lazybear=False```. Set ```lazybear=True``` to enable Lazybear's.
|
||||
* _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)```
|
||||
* _TTM Trend_ (**ttm_trend**). A trend indicator inspired from John Carter's book "Mastering the Trade".
|
||||
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__
|
||||
* _Average True Range_ (**atr**): Added option to return **atr** as a percentage. See: ```help(ta.atr)```
|
||||
@@ -365,7 +366,7 @@ print(bothhl2.name) # "pre_HL2_post"
|
||||
* _Inside Bar_: **cdl_inside**
|
||||
* _Heikin-Ashi_: **ha**
|
||||
|
||||
## _Momentum_ (33)
|
||||
## _Momentum_ (34)
|
||||
|
||||
* _Awesome Oscillator_: **ao**
|
||||
* _Absolute Price Oscillator_: **apo**
|
||||
@@ -373,6 +374,7 @@ print(bothhl2.name) # "pre_HL2_post"
|
||||
* _Balance of Power_: **bop**
|
||||
* _BRAR_: **brar**
|
||||
* _Commodity Channel Index_: **cci**
|
||||
* _Chande Forecast Oscillator_: **cfo**
|
||||
* _Center of Gravity_: **cg**
|
||||
* _Chande Momentum Oscillator_: **cmo**
|
||||
* _Coppock Curve_: **coppock**
|
||||
|
||||
@@ -25,7 +25,7 @@ Category = {
|
||||
"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"],
|
||||
"momentum": ["ao", "apo", "bias", "bop", "brar", "cci", "cfo", "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"],
|
||||
|
||||
# Overlap
|
||||
"overlap": ["dema", "ema", "fwma", "hilo", "hl2", "hlc3", "hma", "ichimoku", "kama", "linreg", "midpoint", "midprice", "ohlc4", "pwma", "rma", "sinwma", "sma", "supertrend", "swma", "t3", "tema", "trima", "vwap", "vwma", "wcp", "wma", "zlma"],
|
||||
|
||||
+6
-1
@@ -23,7 +23,7 @@ from pandas_ta.volatility import *
|
||||
from pandas_ta.volume import *
|
||||
from pandas_ta.utils import *
|
||||
|
||||
version = ".".join(("0", "2", "09b"))
|
||||
version = ".".join(("0", "2", "10b"))
|
||||
|
||||
|
||||
# Strategy DataClass
|
||||
@@ -684,6 +684,11 @@ class AnalysisIndicators(BasePandasObject):
|
||||
result = cci(high=high, low=low, close=close, length=length, c=c, offset=offset, **kwargs)
|
||||
return self._post_process(result, **kwargs)
|
||||
|
||||
def cfo(self, length=None, offset=None, **kwargs):
|
||||
close = self._get_column(kwargs.pop("close", "close"))
|
||||
result = cfo(close=close, length=length, offset=offset, **kwargs)
|
||||
return self._post_process(result, **kwargs)
|
||||
|
||||
def cg(self, length=None, offset=None, **kwargs):
|
||||
close = self._get_column(kwargs.pop("close", "close"))
|
||||
result = cg(close=close, length=length, offset=offset, **kwargs)
|
||||
|
||||
+14
-12
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from ..utils import get_drift, get_offset, verify_series
|
||||
from ..overlap.linreg import linreg
|
||||
from pandas_ta.overlap import linreg
|
||||
from pandas_ta.utils import get_drift, get_offset, verify_series
|
||||
|
||||
def cfo(close, length=None, scalar=None, drift=None, offset=None, **kwargs):
|
||||
"""Indicator: Chande Forcast Oscillator (CFO)"""
|
||||
@@ -12,8 +12,9 @@ def cfo(close, length=None, scalar=None, drift=None, offset=None, **kwargs):
|
||||
offset = get_offset(offset)
|
||||
|
||||
#Finding linear regression of Series
|
||||
linreg_series = linreg(close,length=length)
|
||||
cfo = ((close-linreg_series)/close *100)
|
||||
cfo = scalar * (close - linreg(close, length=length, tsf=True))
|
||||
cfo /= close
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
cfo = cfo.shift(offset)
|
||||
@@ -28,13 +29,13 @@ def cfo(close, length=None, scalar=None, drift=None, offset=None, **kwargs):
|
||||
cfo.name = f"CFO_{length}"
|
||||
cfo.category = "momentum"
|
||||
|
||||
return cmo
|
||||
return cfo
|
||||
|
||||
cfo.__doc__ = \
|
||||
"""Chande Forcast Oscillator (CFO)
|
||||
|
||||
The Forecast Oscillator calculates the percentage difference between the actual price
|
||||
and the Time Series Forecast (the endpoint of a linear regression line).
|
||||
The Forecast Oscillator calculates the percentage difference between the actual
|
||||
price and the Time Series Forecast (the endpoint of a linear regression line).
|
||||
|
||||
Sources:
|
||||
https://www.fmlabs.com/reference/default.htm?url=ForecastOscillator.htm
|
||||
@@ -42,15 +43,16 @@ Sources:
|
||||
Calculation:
|
||||
Default Inputs:
|
||||
length=9, drift=1, scalar=100
|
||||
LINREG = Linear Regression
|
||||
|
||||
# Same Calculation as RSI except for this step
|
||||
CFO = ( ( CLOSE- LINERREG ) / CLOSE * 100 )
|
||||
CFO = scalar * (close - LINERREG(length, tdf=True)) / close
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
scalar (float): How much to magnify. Default: 100
|
||||
drift (int): The short period. Default: 1
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
length (int): The period. Default: 9
|
||||
scalar (float): How much to magnify. Default: 100
|
||||
drift (int): The short period. Default: 1
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
|
||||
Kwargs:
|
||||
fillna (value, optional): pd.DataFrame.fillna(value)
|
||||
|
||||
+19
-19
@@ -1,20 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import math
|
||||
from ..utils import get_offset, verify_series
|
||||
from pandas_ta.utils import get_offset, verify_series
|
||||
|
||||
def linreg(close, length=None, offset=None, **kwargs):
|
||||
"""Indicator: Linear Regression"""
|
||||
# Validate arguments
|
||||
close = verify_series(close)
|
||||
length = int(length) if length and length > 0 else 14
|
||||
min_periods = int(kwargs['min_periods']) if 'min_periods' in kwargs and kwargs['min_periods'] is not None else length
|
||||
min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else length
|
||||
offset = get_offset(offset)
|
||||
angle = kwargs.pop('angle', False)
|
||||
intercept = kwargs.pop('intercept', False)
|
||||
degrees = kwargs.pop('degrees', False)
|
||||
r = kwargs.pop('r', False)
|
||||
slope = kwargs.pop('slope', False)
|
||||
tsf = kwargs.pop('tsf', False)
|
||||
angle = kwargs.pop("angle", False)
|
||||
intercept = kwargs.pop("intercept", False)
|
||||
degrees = kwargs.pop("degrees", False)
|
||||
r = kwargs.pop("r", False)
|
||||
slope = kwargs.pop("slope", False)
|
||||
tsf = kwargs.pop("tsf", False)
|
||||
|
||||
# Calculate Result
|
||||
x = range(1, length + 1) # [1, 2, ..., n] from 1 to n keeps Sum(xy) low
|
||||
@@ -54,10 +54,10 @@ def linreg(close, length=None, offset=None, **kwargs):
|
||||
linreg = linreg.shift(offset)
|
||||
|
||||
# Handle fills
|
||||
if 'fillna' in kwargs:
|
||||
linreg.fillna(kwargs['fillna'], inplace=True)
|
||||
if 'fill_method' in kwargs:
|
||||
linreg.fillna(method=kwargs['fill_method'], inplace=True)
|
||||
if "fillna" in kwargs:
|
||||
linreg.fillna(kwargs["fillna"], inplace=True)
|
||||
if "fill_method" in kwargs:
|
||||
linreg.fillna(method=kwargs["fill_method"], inplace=True)
|
||||
|
||||
# Name and Categorize it
|
||||
linreg.name = f"LR"
|
||||
@@ -66,7 +66,7 @@ def linreg(close, length=None, offset=None, **kwargs):
|
||||
if angle: linreg.name += "a"
|
||||
if r: linreg.name += "r"
|
||||
linreg.name += f"_{length}"
|
||||
linreg.category = 'overlap'
|
||||
linreg.category = "overlap"
|
||||
|
||||
return linreg
|
||||
|
||||
@@ -104,12 +104,12 @@ Args:
|
||||
offset (int): How many periods to offset the result. Default: 0
|
||||
|
||||
Kwargs:
|
||||
angle (bool, optional): Default: False. If True, returns the angle of the slope in radians
|
||||
degrees (bool, optional): Default: False. If True, returns the angle of the slope in degrees
|
||||
intercept (bool, optional): Default: False. If True, returns the angle of the slope in radians
|
||||
r (bool, optional): Default: False. If True, returns it's correlation 'r'
|
||||
slope (bool, optional): Default: False. If True, returns the slope
|
||||
tsf (bool, optional): Default: False. If True, returns the Time Series Forecast value.
|
||||
angle (bool, optional): Default: False. If True, returns the angle of the slope in radians
|
||||
degrees (bool, optional): Default: False. If True, returns the angle of the slope in degrees
|
||||
intercept (bool, optional): Default: False. If True, returns the angle of the slope in radians
|
||||
r (bool, optional): Default: False. If True, returns it's correlation 'r'
|
||||
slope (bool, optional): Default: False. If True, returns the slope
|
||||
tsf (bool, optional): Default: False. If True, returns the Time Series Forecast value.
|
||||
fillna (value, optional): pd.DataFrame.fillna(value)
|
||||
fill_method (value, optional): Type of fill method
|
||||
|
||||
|
||||
@@ -49,6 +49,11 @@ class TestMomentumExtension(TestCase):
|
||||
self.assertIsInstance(self.data, DataFrame)
|
||||
self.assertEqual(self.data.columns[-1], "CCI_14_0.015")
|
||||
|
||||
def test_cfo_ext(self):
|
||||
self.data.ta.cfo(append=True)
|
||||
self.assertIsInstance(self.data, DataFrame)
|
||||
self.assertEqual(self.data.columns[-1], "CFO_9")
|
||||
|
||||
def test_cg_ext(self):
|
||||
self.data.ta.cg(append=True)
|
||||
self.assertIsInstance(self.data, DataFrame)
|
||||
|
||||
@@ -119,6 +119,11 @@ class TestMomentum(TestCase):
|
||||
except Exception as ex:
|
||||
error_analysis(result, CORRELATION, ex)
|
||||
|
||||
def test_cfo(self):
|
||||
result = pandas_ta.cfo(self.close)
|
||||
self.assertIsInstance(result, Series)
|
||||
self.assertEqual(result.name, "CFO_9")
|
||||
|
||||
def test_cg(self):
|
||||
result = pandas_ta.cg(self.close)
|
||||
self.assertIsInstance(result, Series)
|
||||
|
||||
Reference in New Issue
Block a user