# -*- coding: utf-8 -*-# 导入 numpy 库中的 nan 别名 npNaNfrom numpy import nan as npNaN
# 导入 pandas 库中的 Series 类from pandas import Series
# 从 pandas_ta 库中的 utils 模块中导入 get_drift、get_offset、non_zero_range、verify_series 函数from pandas_ta.utils import get_drift, get_offset, non_zero_range, verify_series
# 定义 Kaufman's Adaptive Moving Average (KAMA) 函数defkama(close, length=None, fast=None, slow=None, drift=None, offset=None, **kwargs):
"""Indicator: Kaufman's Adaptive Moving Average (KAMA)"""# 验证参数# 如果 length 不为空且大于 0,则将其转换为整数,否则设为默认值 10
length = int(length) if length and length > 0else10# 如果 fast 不为空且大于 0,则将其转换为整数,否则设为默认值 2
fast = int(fast) if fast and fast > 0else2# 如果 slow 不为空且大于 0,则将其转换为整数,否则设为默认值 30
slow = int(slow) if slow and slow > 0else30# 验证 close 序列,长度为 fast、slow、length 中的最大值
close = verify_series(close, max(fast, slow, length))
# 获取 drift 参数
drift = get_drift(drift)
# 获取 offset 参数
offset = get_offset(offset)
# 如果 close 为空,则返回空if close isNone: return# 计算结果# 定义 weight 函数,用于计算权重defweight(length: int) -> float:
return2 / (length + 1)
# 计算 fast 和 slow 的权重
fr = weight(fast)
sr = weight(slow)
# 计算绝对差和同侧差
abs_diff = non_zero_range(close, close.shift(length)).abs()
peer_diff = non_zero_range(close, close.shift(drift)).abs()
peer_diff_sum = peer_diff.rolling(length).sum()
er = abs_diff / peer_diff_sum
x = er * (fr - sr) + sr
sc = x * x
# 获取 close 序列的长度
m = close.size
# 初始化结果列表,前 length-1 个值为 npNaN,最后一个值为 0
result = [npNaN for _ inrange(0, length - 1)] + [0]
# 遍历计算 KAMAfor i inrange(length, m):
result.append(sc.iloc[i] * close.iloc[i] + (1 - sc.iloc[i]) * result[i - 1])
# 将结果转换为 Series 类型,索引为 close 序列的索引
kama = Series(result, index=close.index)
# 偏移结果if offset != 0:
kama = kama.shift(offset)
# 处理填充值if"fillna"in kwargs:
kama.fillna(kwargs["fillna"], inplace=True)
if"fill_method"in kwargs:
kama.fillna(method=kwargs["fill_method"], inplace=True)
# 设置指标名称和类别
kama.name = f"KAMA_{length}_{fast}_{slow}"
kama.category = "overlap"# 返回 KAMA 序列return kama
# 设置 KAMA 函数的文档字符串
kama.__doc__ = \
"""Kaufman's Adaptive Moving Average (KAMA)
Developed by Perry Kaufman, Kaufman's Adaptive Moving Average (KAMA) is a moving average
designed to account for market noise or volatility. KAMA will closely follow prices when
the price swings are relatively small and the noise is low. KAMA will adjust when the
price swings widen and follow prices from a greater distance. This trend-following indicator
can be used to identify the overall trend, time turning points and filter price movements.
Sources:
https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:kaufman_s_adaptive_moving_average
https://www.tradingview.com/script/wZGOIz9r-REPOST-Indicators-3-Different-Adaptive-Moving-Averages/
Calculation:
Default Inputs:
length=10
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 10
fast (int): Fast MA period. Default: 2
slow (int): Slow MA period. Default: 30
drift (int): The difference period. Default: 1
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 generated.
"""
.\pandas-ta\pandas_ta\overlap\linreg.py
# -*- coding: utf-8 -*-# 从 numpy 库导入 array 并重命名为 npArray,导入 arctan 并重命名为 npAtan,导入 nan 并重命名为 npNaN,导入 pi 并重命名为 npPi,从 numpy 版本导入 version 并重命名为 npVersionfrom numpy import array as npArray
from numpy import arctan as npAtan
from numpy import nan as npNaN
from numpy import pi as npPi
from numpy.version import version as npVersion
# 从 pandas 库导入 Series,从 pandas_ta.utils 导入 get_offset 和 verify_series 函数from pandas import Series
from pandas_ta.utils import get_offset, verify_series
deflinreg(close, length=None, offset=None, **kwargs):
"""Indicator: Linear Regression"""# 验证参数# 如果 length 存在且大于 0,则将其转换为整数,否则设为默认值 14
length = int(length) if length and length > 0else14# 验证 close 是否为有效的 Series,并设定长度
close = verify_series(close, length)
# 获取偏移量
offset = get_offset(offset)
# 获取其他参数:angle、intercept、degrees、r、slope、tsf
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)
# 如果 close 为空,则返回 Noneif close isNone: return# 计算结果# 生成 x 轴的值,范围从 1 到 length
x = range(1, length + 1) # [1, 2, ..., n] from 1 to n keeps Sum(xy) low# 计算 x 的和
x_sum = 0.5 * length * (length + 1)
# 计算 x 的平方和
x2_sum = x_sum * (2 * length + 1) / 3# 计算除数
divisor = length * x2_sum - x_sum * x_sum
# 定义线性回归函数deflinear_regression(series):
# 计算 y 的和
y_sum = series.sum()
# 计算 x*y 的和
xy_sum = (x * series).sum()
# 计算斜率
m = (length * xy_sum - x_sum * y_sum) / divisor
# 如果 slope 为 True,则返回斜率if slope:
return m
# 计算截距
b = (y_sum * x2_sum - x_sum * xy_sum) / divisor
# 如果 intercept 为 True,则返回截距if intercept:
return b
# 如果 angle 为 True,则计算角度if angle:
theta = npAtan(m)
# 如果 degrees 为 True,则将角度转换为度if degrees:
theta *= 180 / npPi
return theta
# 如果 r 为 True,则计算相关系数if r:
# 计算 y^2 的和
y2_sum = (series * series).sum()
# 计算相关系数的分子
rn = length * xy_sum - x_sum * y_sum
# 计算相关系数的分母
rd = (divisor * (length * y2_sum - y_sum * y_sum)) ** 0.5return rn / rd
# 如果 tsf 为 True,则进行时间序列调整return m * length + b if tsf else m * (length - 1) + b
# 定义滚动窗口函数defrolling_window(array, length):
"""https://github.com/twopirllc/pandas-ta/issues/285"""
strides = array.strides + (array.strides[-1],)
shape = array.shape[:-1] + (array.shape[-1] - length + 1, length)
return as_strided(array, shape=shape, strides=strides)
# 如果 numpy 版本大于等于 1.20.0,则使用 sliding_window_view 函数if npVersion >= "1.20.0":
from numpy.lib.stride_tricks import sliding_window_view
# 对于滑动窗口内的每个窗口,应用线性回归函数
linreg_ = [linear_regression(_) for _ in sliding_window_view(npArray(close), length)]
else:
# 否则,使用 rolling_window 函数from numpy.lib.stride_tricks import as_strided
# 对于滚动窗口内的每个窗口,应用线性回归函数
linreg_ = [linear_regression(_) for _ in rolling_window(npArray(close), length)]
# 创建 Series 对象,索引为 close 的索引,值为线性回归的结果
linreg = Series([npNaN] * (length - 1) + linreg_, index=close.index)
# 偏移结果if offset != 0:
linreg = linreg.shift(offset)
# 处理填充if"fillna"in kwargs:
linreg.fillna(kwargs["fillna"], inplace=True)
if"fill_method"in kwargs:
linreg.fillna(method=kwargs["fill_method"], inplace=True)
# 设置名称和分类
linreg.name = f"LR"if slope: linreg.name += "m"if intercept: linreg.name += "b"if angle: linreg.name += "a"if r: linreg.name += "r"
linreg.name += f"_{length}"
linreg.category = "overlap"return linreg
# 将文档字符串赋值给线性回归移动平均函数的__doc__属性,用于函数说明和文档生成
linreg.__doc__ = \
"""Linear Regression Moving Average (linreg)
Linear Regression Moving Average (LINREG). This is a simplified version of a
Standard Linear Regression. LINREG is a rolling regression of one variable. A
Standard Linear Regression is between two or more variables.
Source: TA Lib
Calculation:
Default Inputs:
length=14
x = [1, 2, ..., n]
x_sum = 0.5 * length * (length + 1)
x2_sum = length * (length + 1) * (2 * length + 1) / 6
divisor = length * x2_sum - x_sum * x_sum
# 定义线性回归函数lr(series),用于计算移动平均
lr(series):
# 计算系列的总和、平方和以及x和y的乘积和
y_sum = series.sum()
y2_sum = (series* series).sum()
xy_sum = (x * series).sum()
# 计算回归线的斜率m和截距b
m = (length * xy_sum - x_sum * y_sum) / divisor
b = (y_sum * x2_sum - x_sum * xy_sum) / divisor
return m * (length - 1) + b
# 使用rolling函数对close进行移动窗口处理,并应用lr函数计算移动平均
linreg = close.rolling(length).apply(lr)
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 10
offset (int): How many periods to offset the result. Default: 0
Kwargs:
angle (bool, optional): If True, returns the angle of the slope in radians.
Default: False.
degrees (bool, optional): If True, returns the angle of the slope in
degrees. Default: False.
intercept (bool, optional): If True, returns the angle of the slope in
radians. Default: False.
r (bool, optional): If True, returns it's correlation 'r'. Default: False.
slope (bool, optional): If True, returns the slope. Default: False.
tsf (bool, optional): If True, returns the Time Series Forecast value.
Default: False.
fillna (value, optional): pd.DataFrame.fillna(value)
fill_method (value, optional): Type of fill method
Returns:
pd.Series: New feature generated.
"""
.\pandas-ta\pandas_ta\overlap\ma.py
# 设置文件编码为 UTF-8# 导入 Series 类from pandas import Series
# 导入不同的移动平均方法# 从模块中导入指定的函数from .dema import dema
from .ema import ema
from .fwma import fwma
from .hma import hma
from .linreg import linreg
from .midpoint import midpoint
from .pwma import pwma
from .rma import rma
from .sinwma import sinwma
from .sma import sma
from .swma import swma
from .t3 import t3
from .tema import tema
from .trima import trima
from .vidya import vidya
from .wma import wma
from .zlma import zlma
# 定义移动平均函数,用于简化移动平均的选择defma(name:str = None, source:Series = None, **kwargs) -> Series:
"""Simple MA Utility for easier MA selection
Available MAs:
dema, ema, fwma, hma, linreg, midpoint, pwma, rma,
sinwma, sma, swma, t3, tema, trima, vidya, wma, zlma
Examples:
ema8 = ta.ma("ema", df.close, length=8)
sma50 = ta.ma("sma", df.close, length=50)
pwma10 = ta.ma("pwma", df.close, length=10, asc=False)
Args:
name (str): One of the Available MAs. Default: "ema"
source (pd.Series): The 'source' Series.
Kwargs:
Any additional kwargs the MA may require.
Returns:
pd.Series: New feature generated.
"""# 支持的移动平均方法列表
_mas = [
"dema", "ema", "fwma", "hma", "linreg", "midpoint", "pwma", "rma",
"sinwma", "sma", "swma", "t3", "tema", "trima", "vidya", "wma", "zlma"
]
# 如果没有指定移动平均方法和数据源,则返回支持的移动平均方法列表if name isNoneand source isNone:
return _mas
# 如果指定的移动平均方法是字符串,并且在支持的方法列表中,则转换为小写elifisinstance(name, str) and name.lower() in _mas:
name = name.lower()
else: # "ema"# 如果未指定移动平均方法,则默认选择 EMA
name = _mas[1]
# 根据选择的移动平均方法调用相应的函数if name == "dema": return dema(source, **kwargs)
elif name == "fwma": return fwma(source, **kwargs)
elif name == "hma": return hma(source, **kwargs)
elif name == "linreg": return linreg(source, **kwargs)
elif name == "midpoint": return midpoint(source, **kwargs)
elif name == "pwma": return pwma(source, **kwargs)
elif name == "rma": return rma(source, **kwargs)
elif name == "sinwma": return sinwma(source, **kwargs)
elif name == "sma": return sma(source, **kwargs)
elif name == "swma": return swma(source, **kwargs)
elif name == "t3": return t3(source, **kwargs)
elif name == "tema": return tema(source, **kwargs)
elif name == "trima": return trima(source, **kwargs)
elif name == "vidya": return vidya(source, **kwargs)
elif name == "wma": return wma(source, **kwargs)
elif name == "zlma": return zlma(source, **kwargs)
else: return ema(source, **kwargs)
.\pandas-ta\pandas_ta\overlap\mcgd.py
# -*- coding: utf-8 -*-# 导入所需模块和函数from pandas_ta.utils import get_offset, verify_series
defmcgd(close, length=None, offset=None, c=None, **kwargs):
"""Indicator: McGinley Dynamic Indicator"""# 验证参数有效性# 如果 length 存在且大于 0,则将其转换为整数;否则,默认为 10
length = int(length) if length and length > 0else10# 如果 c 存在且在 0 到 1 之间,则将其转换为浮点数;否则,默认为 1
c = float(c) if c and0 < c <= 1else1# 验证 close 是否为有效的 Series,并将其长度限制为 length
close = verify_series(close, length)
# 获取偏移量
offset = get_offset(offset)
# 如果 close 为 None,则返回空值if close isNone: return# 计算结果# 复制 close Series,避免直接修改原始数据
close = close.copy()
# 定义 McGinley Dynamic Indicator 计算函数defmcg_(series):
# 计算分母
denom = (c * length * (series.iloc[1] / series.iloc[0]) ** 4)
# 计算 McGinley Dynamic Indicator
series.iloc[1] = (series.iloc[0] + ((series.iloc[1] - series.iloc[0]) / denom))
return series.iloc[1]
# 应用 mcg_ 函数到 rolling window 上,计算 McGinley Dynamic Indicator
mcg_cell = close[0:].rolling(2, min_periods=2).apply(mcg_, raw=False)
# 将第一个值添加回结果 Series 中
mcg_ds = close[:1].append(mcg_cell[1:])
# 偏移结果 Seriesif offset != 0:
mcg_ds = mcg_ds.shift(offset)
# 处理填充值if"fillna"in kwargs:
mcg_ds.fillna(kwargs["fillna"], inplace=True)
if"fill_method"in kwargs:
mcg_ds.fillna(method=kwargs["fill_method"], inplace=True)
# 设置结果 Series 的名称和类别
mcg_ds.name = f"MCGD_{length}"
mcg_ds.category = "overlap"return mcg_ds
# 设置 McGinley Dynamic Indicator 的文档字符串
mcgd.__doc__ = \
"""McGinley Dynamic Indicator
The McGinley Dynamic looks like a moving average line, yet it is actually a
smoothing mechanism for prices that minimizes price separation, price whipsaws,
and hugs prices much more closely. Because of the calculation, the Dynamic Line
speeds up in down markets as it follows prices yet moves more slowly in up
markets. The indicator was designed by John R. McGinley, a Certified Market
Technician and former editor of the Market Technicians Association's Journal
of Technical Analysis.
Sources:
https://www.investopedia.com/articles/forex/09/mcginley-dynamic-indicator.asp
Calculation:
Default Inputs:
length=10
offset=0
c=1
def mcg_(series):
denom = (constant * length * (series.iloc[1] / series.iloc[0]) ** 4)
series.iloc[1] = (series.iloc[0] + ((series.iloc[1] - series.iloc[0]) / denom))
return series.iloc[1]
mcg_cell = close[0:].rolling(2, min_periods=2).apply(mcg_, raw=False)
mcg_ds = close[:1].append(mcg_cell[1:])
Args:
close (pd.Series): Series of 'close's
length (int): Indicator's period. Default: 10
offset (int): Number of periods to offset the result. Default: 0
c (float): Multiplier for the denominator, sometimes set to 0.6. Default: 1
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
fill_method (value, optional): Type of fill method
Returns:
pd.Series: New feature generated.
"""
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步