PandasTA 源码解析(八)

.\pandas-ta\pandas_ta\momentum\__init__.py

# 设置文件编码为 UTF-8
# 导入 ao 指标
from .ao import ao
# 导入 apo 指标
from .apo import apo
# 导入 bias 指标
from .bias import bias
# 导入 bop 指标
from .bop import bop
# 导入 brar 指标
from .brar import brar
# 导入 cci 指标
from .cci import cci
# 导入 cfo 指标
from .cfo import cfo
# 导入 cg 指标
from .cg import cg
# 导入 cmo 指标
from .cmo import cmo
# 导入 coppock 指标
from .coppock import coppock
# 导入 cti 指标
from .cti import cti
# 导入 dm 指标
from .dm import dm
# 导入 er 指标
from .er import er
# 导入 eri 指标
from .eri import eri
# 导入 fisher 指标
from .fisher import fisher
# 导入 inertia 指标
from .inertia import inertia
# 导入 kdj 指标
from .kdj import kdj
# 导入 kst 指标
from .kst import kst
# 导入 macd 指标
from .macd import macd
# 导入 mom 指标
from .mom import mom
# 导入 pgo 指标
from .pgo import pgo
# 导入 ppo 指标
from .ppo import ppo
# 导入 psl 指标
from .psl import psl
# 导入 pvo 指标
from .pvo import pvo
# 导入 qqe 指标
from .qqe import qqe
# 导入 roc 指标
from .roc import roc
# 导入 rsi 指标
from .rsi import rsi
# 导入 rsx 指标
from .rsx import rsx
# 导入 rvgi 指标
from .rvgi import rvgi
# 导入 slope 指标
from .slope import slope
# 导入 smi 指标
from .smi import smi
# 导入 squeeze 指标
from .squeeze import squeeze
# 导入 squeeze_pro 指标
from .squeeze_pro import squeeze_pro
# 导入 stc 指标
from .stc import stc
# 导入 stoch 指标
from .stoch import stoch
# 导入 stochrsi 指标
from .stochrsi import stochrsi
# 导入 td_seq 指标
from .td_seq import td_seq
# 导入 trix 指标
from .trix import trix
# 导入 tsi 指标
from .tsi import tsi
# 导入 uo 指标
from .uo import uo
# 导入 willr 指标
from .willr import willr

.\pandas-ta\pandas_ta\overlap\alma.py

# -*- coding: utf-8 -*-
# 从 numpy 库中导入 exp 函数并重命名为 npExp
from numpy import exp as npExp
# 从 numpy 库中导入 nan 常量并重命名为 npNaN
from numpy import nan as npNaN
# 从 pandas 库中导入 Series 类
from pandas import Series
# 从 pandas_ta.utils 模块中导入 get_offset 和 verify_series 函数
from pandas_ta.utils import get_offset, verify_series


def alma(close, length=None, sigma=None, distribution_offset=None, offset=None, **kwargs):
    """Indicator: Arnaud Legoux Moving Average (ALMA)"""
    # 验证参数
    # 将长度转换为整数,如果长度存在且大于 0;否则默认为 10
    length = int(length) if length and length > 0 else 10
    # 将 sigma 转换为浮点数,如果 sigma 存在且大于 0;否则默认为 6.0
    sigma = float(sigma) if sigma and sigma > 0 else 6.0
    # 将 distribution_offset 转换为浮点数,如果 distribution_offset 存在且大于 0;否则默认为 0.85
    distribution_offset = float(distribution_offset) if distribution_offset and distribution_offset > 0 else 0.85
    # 验证 close 序列,长度为 length
    close = verify_series(close, length)
    # 获取偏移量
    offset = get_offset(offset)

    # 如果 close 为空,返回空
    if close is None: return

    # 预先计算
    m = distribution_offset * (length - 1)
    s = length / sigma
    wtd = list(range(length))
    for i in range(0, length):
        # 计算权重(窗口)
        wtd[i] = npExp(-1 * ((i - m) * (i - m)) / (2 * s * s))

    # 计算结果
    # 初始化结果为长度-1个 NaN 和 1 个 0 组成的列表
    result = [npNaN for _ in range(0, length - 1)] + [0]
    for i in range(length, close.size):
        window_sum = 0
        cum_sum = 0
        for j in range(0, length):
            # 计算窗口和
            window_sum = window_sum + wtd[j] * close.iloc[i - j]
            # 计算累积和
            cum_sum = cum_sum + wtd[j]

        # 计算 ALMA
        almean = window_sum / cum_sum
        # 如果 i 等于长度,则将结果列表追加 NaN,否则追加 almean
        result.append(npNaN) if i == length else result.append(almean)

    # 创建 ALMA Series 对象
    alma = Series(result, index=close.index)

    # 处理偏移
    if offset != 0:
        alma = alma.shift(offset)

    # 处理填充
    if "fillna" in kwargs:
        alma.fillna(kwargs["fillna"], inplace=True)
    if "fill_method" in kwargs:
        alma.fillna(method=kwargs["fill_method"], inplace=True)

    # 名称和分类
    alma.name = f"ALMA_{length}_{sigma}_{distribution_offset}"
    alma.category = "overlap"

    return alma


# 为 alma 函数添加文档字符串
alma.__doc__ = \
"""Arnaud Legoux Moving Average (ALMA)

The ALMA moving average uses the curve of the Normal (Gauss) distribution, which
can be shifted from 0 to 1. This allows regulating the smoothness and high
sensitivity of the indicator. Sigma is another parameter that is responsible for
the shape of the curve coefficients. This moving average reduces lag of the data
in conjunction with smoothing to reduce noise.

Implemented for Pandas TA by rengel8 based on the source provided below.

Sources:
    https://www.prorealcode.com/prorealtime-indicators/alma-arnaud-legoux-moving-average/

Calculation:
    refer to provided source

Args:
    close (pd.Series): Series of 'close's
    length (int): It's period, window size. Default: 10
    sigma (float): Smoothing value. Default 6.0
    distribution_offset (float): Value to offset the distribution min 0
        (smoother), max 1 (more responsive). Default 0.85
    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:

"""
    # 创建一个 Pandas Series 对象,表示生成了一个新的特征
# 这是一个空的字符串,通常用作多行注释的起始

.\pandas-ta\pandas_ta\overlap\dema.py

# -*- coding: utf-8 -*-
# 导入 ema 函数
from .ema import ema
# 导入 Imports 模块
from pandas_ta import Imports
# 导入 get_offset 和 verify_series 函数
from pandas_ta.utils import get_offset, verify_series

# 定义 dema 函数,计算 Double Exponential Moving Average (DEMA)
def dema(close, length=None, talib=None, offset=None, **kwargs):
    """Indicator: Double Exponential Moving Average (DEMA)"""
    # 验证参数
    # 如果 length 存在且大于 0,则将其转换为整数,否则设为默认值 10
    length = int(length) if length and length > 0 else 10
    # 验证 close 数据类型为 Series,并且长度符合要求
    close = verify_series(close, length)
    # 获取 offset 值
    offset = get_offset(offset)
    # 判断是否使用 talib 模式
    mode_tal = bool(talib) if isinstance(talib, bool) else True

    # 如果 close 为空,则返回空值
    if close is None: return

    # 计算结果
    if Imports["talib"] and mode_tal:
        # 如果导入了 talib 并且使用 talib 模式,则调用 talib 中的 DEMA 函数
        from talib import DEMA
        dema = DEMA(close, length)
    else:
        # 否则,分别计算两个 EMA 值
        ema1 = ema(close=close, length=length)
        ema2 = ema(close=ema1, length=length)
        # 计算 DEMA 值
        dema = 2 * ema1 - ema2

    # 对结果进行偏移
    if offset != 0:
        dema = dema.shift(offset)

    # 处理填充值
    if "fillna" in kwargs:
        dema.fillna(kwargs["fillna"], inplace=True)
    if "fill_method" in kwargs:
        dema.fillna(method=kwargs["fill_method"], inplace=True)

    # 设置指标名称和类别
    dema.name = f"DEMA_{length}"
    dema.category = "overlap"

    return dema

# 设置 dema 函数的文档字符串
dema.__doc__ = \
"""Double Exponential Moving Average (DEMA)

The Double Exponential Moving Average attempts to a smoother average with less
lag than the normal Exponential Moving Average (EMA).

Sources:
    https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/double-exponential-moving-average-dema/

Calculation:
    Default Inputs:
        length=10
    EMA = Exponential Moving Average
    ema1 = EMA(close, length)
    ema2 = EMA(ema1, length)

    DEMA = 2 * ema1 - ema2

Args:
    close (pd.Series): Series of 'close's
    length (int): It's period. Default: 10
    talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
        version. Default: True
    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\ema.py

# -*- coding: utf-8 -*-
# 从 numpy 导入 nan 并重命名为 npNaN
from numpy import nan as npNaN
# 从 pandas_ta 导入 Imports 模块
from pandas_ta import Imports
# 从 pandas_ta.utils 导入 get_offset 和 verify_series 函数
from pandas_ta.utils import get_offset, verify_series


def ema(close, length=None, talib=None, offset=None, **kwargs):
    """Indicator: Exponential Moving Average (EMA)"""
    # 验证参数
    # 将 length 转换为整数,如果 length 存在且大于 0,否则默认为 10
    length = int(length) if length and length > 0 else 10
    # 从 kwargs 中弹出 "adjust" 键的值,默认为 False
    adjust = kwargs.pop("adjust", False)
    # 从 kwargs 中弹出 "sma" 键的值,默认为 True
    sma = kwargs.pop("sma", True)
    # 验证 close 数据,并使用 length 进行验证
    close = verify_series(close, length)
    # 获取偏移量
    offset = get_offset(offset)
    # 如果 talib 存在且为布尔类型,则将 mode_tal 设置为 talib,否则设置为 True
    mode_tal = bool(talib) if isinstance(talib, bool) else True

    # 如果 close 为 None,则返回
    if close is None: return

    # 计算结果
    if Imports["talib"] and mode_tal:
        # 如果 Imports 中的 "talib" 为 True 且 mode_tal 为 True,则使用 talib 库中的 EMA 函数
        from talib import EMA
        ema = EMA(close, length)
    else:
        # 否则执行以下操作
        if sma:
            # 如果 sma 为 True,则执行以下操作
            close = close.copy()
            # 计算前 length 个 close 的均值作为初始值
            sma_nth = close[0:length].mean()
            # 将 close 的前 length-1 个值设为 NaN
            close[:length - 1] = npNaN
            # 将 close 的第 length-1 个值设为初始均值
            close.iloc[length - 1] = sma_nth
        # 使用指数加权移动平均计算 EMA
        ema = close.ewm(span=length, adjust=adjust).mean()

    # 偏移结果
    if offset != 0:
        ema = ema.shift(offset)

    # 处理填充
    if "fillna" in kwargs:
        ema.fillna(kwargs["fillna"], inplace=True)
    if "fill_method" in kwargs:
        ema.fillna(method=kwargs["fill_method"], inplace=True)

    # 名称和类别
    # 设置 ema 的名称为 "EMA_length",类别为 "overlap"
    ema.name = f"EMA_{length}"
    ema.category = "overlap"

    return ema


# 重新定义 ema 函数的文档字符串
ema.__doc__ = \
"""Exponential Moving Average (EMA)

指数移动平均是对比简单移动平均(SMA)更具响应性的移动平均。其权重由 alpha 决定,与其长度成正比。有几种不同的计算 EMA 的方法。一种方法仅使用标准的 EMA 定义,另一种方法使用 SMA 生成其余计算的初始值。

来源:
    https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_averages
    https://www.investopedia.com/ask/answers/122314/what-exponential-moving-average-ema-formula-and-how-ema-calculated.asp

计算:
    默认参数:
        length=10, adjust=False, sma=True
    如果 sma 为 True:
        sma_nth = close[0:length].sum() / length
        close[:length - 1] = np.NaN
        close.iloc[length - 1] = sma_nth
    EMA = close.ewm(span=length, adjust=adjust).mean()

参数:
    close (pd.Series): 'close' 数据的序列
    length (int): 周期。默认为 10
    talib (bool): 如果安装了 TA Lib 并且 talib 为 True,则返回 TA Lib 版本。默认为 True
    offset (int): 结果的偏移周期数。默认为 0

可选参数:
    adjust (bool, optional): 默认为 False
    sma (bool, optional): 如果为 True,则使用 SMA 作为初始值。默认为 True
    fillna (value, optional): pd.DataFrame.fillna(value)
    fill_method (value, optional): 填充方法的类型

返回:
    pd.Series: 生成的新特征。
"""

.\pandas-ta\pandas_ta\overlap\fwma.py

# -*- coding: utf-8 -*-
# 从 pandas_ta.utils 模块导入 fibonacci、get_offset、verify_series、weights 函数
from pandas_ta.utils import fibonacci, get_offset, verify_series, weights


# 定义 Fibonacci's Weighted Moving Average (FWMA) 函数
def fwma(close, length=None, asc=None, offset=None, **kwargs):
    """Indicator: Fibonacci's Weighted Moving Average (FWMA)"""
    # 验证参数
    # 如果 length 参数存在且大于 0,则将其转换为整数,否则设为默认值 10
    length = int(length) if length and length > 0 else 10
    # 如果 asc 参数存在且为真,则保持其值,否则设为默认值 True
    asc = asc if asc else True
    # 验证 close 参数,并设定长度为 length
    close = verify_series(close, length)
    # 获取偏移量
    offset = get_offset(offset)

    # 如果 close 为空,则返回空值
    if close is None: return

    # 计算结果
    # 根据长度生成 Fibonacci 数列,使用加权方法
    fibs = fibonacci(n=length, weighted=True)
    # 计算 FWMA
    fwma = close.rolling(length, min_periods=length).apply(weights(fibs), raw=True)

    # 偏移
    # 如果偏移量不为零,则对 FWMA 进行偏移
    if offset != 0:
        fwma = fwma.shift(offset)

    # 处理填充
    # 如果 kwargs 中包含 fillna 键,则使用指定值进行填充
    if "fillna" in kwargs:
        fwma.fillna(kwargs["fillna"], inplace=True)
    # 如果 kwargs 中包含 fill_method 键,则使用指定的填充方法
    if "fill_method" in kwargs:
        fwma.fillna(method=kwargs["fill_method"], inplace=True)

    # 名称与类别
    # 设置 FWMA 的名称为 FWMA_length,类别为 overlap
    fwma.name = f"FWMA_{length}"
    fwma.category = "overlap"

    # 返回 FWMA 结果
    return fwma


# 设置 FWMA 函数的文档字符串
fwma.__doc__ = \
"""Fibonacci's Weighted Moving Average (FWMA)

Fibonacci's Weighted Moving Average is similar to a Weighted Moving Average
(WMA) where the weights are based on the Fibonacci Sequence.

Source: Kevin Johnson

Calculation:
    Default Inputs:
        length=10,

    def weights(w):
        def _compute(x):
            return np.dot(w * x)
        return _compute

    fibs = utils.fibonacci(length - 1)
    FWMA = close.rolling(length)_.apply(weights(fibs), raw=True)

Args:
    close (pd.Series): Series of 'close's
    length (int): It's period. Default: 10
    asc (bool): Recent values weigh more. Default: True
    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\hilo.py

# -*- coding: utf-8 -*-
# 导入 numpy 中的 nan 作为 npNaN
from numpy import nan as npNaN
# 从 pandas 中导入 DataFrame 和 Series
from pandas import DataFrame, Series
# 从当前包中导入 ma 模块
from .ma import ma
# 从 pandas_ta.utils 中导入 get_offset 和 verify_series 函数
from pandas_ta.utils import get_offset, verify_series


def hilo(high, low, close, high_length=None, low_length=None, mamode=None, offset=None, **kwargs):
    """Indicator: Gann HiLo (HiLo)"""
    # 验证参数
    # 如果 high_length 存在且大于 0,则转换为整数;否则设为默认值 13
    high_length = int(high_length) if high_length and high_length > 0 else 13
    # 如果 low_length 存在且大于 0,则转换为整数;否则设为默认值 21
    low_length = int(low_length) if low_length and low_length > 0 else 21
    # 如果 mamode 是字符串,则转换为小写;否则设为默认值 "sma"
    mamode = mamode.lower() if isinstance(mamode, str) else "sma"
    # 计算 high 和 low 的最大长度
    _length = max(high_length, low_length)
    # 验证 high、low 和 close 的数据,并取长度为 _length 的数据
    high = verify_series(high, _length)
    low = verify_series(low, _length)
    close = verify_series(close, _length)
    # 获取偏移量
    offset = get_offset(offset)

    # 如果 high、low 或 close 为空,则返回空值
    if high is None or low is None or close is None: return

    # 计算结果
    m = close.size
    # 初始化 hilo、long 和 short 为全 NaN 的 Series
    hilo = Series(npNaN, index=close.index)
    long = Series(npNaN, index=close.index)
    short = Series(npNaN, index=close.index)

    # 计算 high 和 low 的移动平均值
    high_ma = ma(mamode, high, length=high_length)
    low_ma = ma(mamode, low, length=low_length)

    # 循环计算 hilo、long 和 short
    for i in range(1, m):
        if close.iloc[i] > high_ma.iloc[i - 1]:
            hilo.iloc[i] = long.iloc[i] = low_ma.iloc[i]
        elif close.iloc[i] < low_ma.iloc[i - 1]:
            hilo.iloc[i] = short.iloc[i] = high_ma.iloc[i]
        else:
            hilo.iloc[i] = hilo.iloc[i - 1]
            long.iloc[i] = short.iloc[i] = hilo.iloc[i - 1]

    # 偏移结果
    if offset != 0:
        hilo = hilo.shift(offset)
        long = long.shift(offset)
        short = short.shift(offset)

    # 处理填充值
    if "fillna" in kwargs:
        hilo.fillna(kwargs["fillna"], inplace=True)
        long.fillna(kwargs["fillna"], inplace=True)
        short.fillna(kwargs["fillna"], inplace=True)
    if "fill_method" in kwargs:
        hilo.fillna(method=kwargs["fill_method"], inplace=True)
        long.fillna(method=kwargs["fill_method"], inplace=True)
        short.fillna(method=kwargs["fill_method"], inplace=True)

    # 名称和类别
    _props = f"_{high_length}_{low_length}"
    # 创建包含 hilo、long 和 short 数据的 DataFrame
    data = {f"HILO{_props}": hilo, f"HILOl{_props}": long, f"HILOs{_props}": short}
    df = DataFrame(data, index=close.index)

    # 设置 DataFrame 的名称和类别
    df.name = f"HILO{_props}"
    df.category = "overlap"

    # 返回 DataFrame
    return df


# 设置 hilo 函数的文档字符串
hilo.__doc__ = \
"""Gann HiLo Activator(HiLo)

The Gann High Low Activator Indicator was created by Robert Krausz in a 1998
issue of Stocks & Commodities Magazine. It is a moving average based trend
indicator consisting of two different simple moving averages.

The indicator tracks both curves (of the highs and the lows). The close of the
bar defines which of the two gets plotted.

Increasing high_length and decreasing low_length better for short trades,
vice versa for long positions.

Sources:
    https://www.sierrachart.com/index.php?page=doc/StudiesReference.php&ID=447&Name=Gann_HiLo_Activator
    https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/simple-moving-average-sma/
"""
    # 通过指定的 URL 访问 Gann High Low 脚本
    https://www.tradingview.com/script/XNQSLIYb-Gann-High-Low/
# 计算函数,根据所选的移动平均模式计算高低移动平均线
Calculation:
    # 默认输入参数:高期限、低期限、移动平均模式(默认为简单移动平均)
    Default Inputs:
        high_length=13, low_length=21, mamode="sma"
    # EMA = 指数移动平均
    EMA = Exponential Moving Average
    # HMA = 哈尔移动平均
    HMA = Hull Moving Average
    # SMA = 简单移动平均 # 默认

    # 根据所选的移动平均模式计算高期限和低期限移动平均值
    if "ema":
        high_ma = EMA(high, high_length)
        low_ma = EMA(low, low_length)
    elif "hma":
        high_ma = HMA(high, high_length)
        low_ma = HMA(low, low_length)
    else: # "sma"
        high_ma = SMA(high, high_length)
        low_ma = SMA(low, low_length)

    # 类似于Supertrend MA选择
    # 创建一个Series对象,用于存储高低移动平均线
    hilo = Series(npNaN, index=close.index)
    # 循环计算
    for i in range(1, m):
        # 如果当前收盘价大于上一个周期的高期限移动平均值,则将当前位置的低期限移动平均值存入hilo
        if close.iloc[i] > high_ma.iloc[i - 1]:
            hilo.iloc[i] = low_ma.iloc[i]
        # 如果当前收盘价小于上一个周期的低期限移动平均值,则将当前位置的高期限移动平均值存入hilo
        elif close.iloc[i] < low_ma.iloc[i - 1]:
            hilo.iloc[i] = high_ma.iloc[i]
        # 否则,维持前一个周期的值
        else:
            hilo.iloc[i] = hilo.iloc[i - 1]

Args:
    # 高价的Series
    high (pd.Series): Series of 'high's
    # 低价的Series
    low (pd.Series): Series of 'low's
    # 收盘价的Series
    close (pd.Series): Series of 'close's
    # 高期限的长度,即移动平均线的周期。默认值为13
    high_length (int): It's period. Default: 13
    # 低期限的长度,即移动平均线的周期。默认值为21
    low_length (int): It's period. Default: 21
    # 移动平均模式,参见```help(ta.ma)```py。默认为'sma'
    mamode (str): See ```help(ta.ma)```py. Default: 'sma'
    # 结果的偏移量,即将结果向前或向后移动的周期数。默认为0
    offset (int): How many periods to offset the result. Default: 0

Kwargs:
    # 是否调整结果
    adjust (bool): Default: True
    # 是否使用SMA作为初始值
    presma (bool, optional): If True, uses SMA for initial value.
    # 对DataFrame进行fillna填充
    fillna (value, optional): pd.DataFrame.fillna(value)
    # 填充方法的类型
    fill_method (value, optional): Type of fill method

Returns:
    # 返回一个DataFrame,包含HILO(线)、HILOl(长)、HILOs(短)列。
    pd.DataFrame: HILO (line), HILOl (long), HILOs (short) columns.

.\pandas-ta\pandas_ta\overlap\hl2.py

# -*- coding: utf-8 -*-
# 从 pandas_ta.utils 模块中导入 get_offset 和 verify_series 函数
from pandas_ta.utils import get_offset, verify_series

# 定义函数 hl2,计算 HL2 指标
def hl2(high, low, offset=None, **kwargs):
    """Indicator: HL2 """
    # 验证参数
    # 确保 high 和 low 是有效的序列数据
    high = verify_series(high)
    low = verify_series(low)
    # 获取偏移量
    offset = get_offset(offset)

    # 计算结果
    # HL2 指标的计算公式为 (high + low) / 2
    hl2 = 0.5 * (high + low)

    # 偏移
    # 如果偏移量不为 0,则对 hl2 进行偏移
    if offset != 0:
        hl2 = hl2.shift(offset)

    # 名称和类别
    # 设置 hl2 的名称为 "HL2",类别为 "overlap"
    hl2.name = "HL2"
    hl2.category = "overlap"

    return hl2

.\pandas-ta\pandas_ta\overlap\hlc3.py

# -*- coding: utf-8 -*-
# 从 pandas_ta 库中导入 Imports 模块
from pandas_ta import Imports
# 从 pandas_ta.utils 中导入 get_offset 和 verify_series 函数
from pandas_ta.utils import get_offset, verify_series

# 定义函数 hlc3,计算 HLC3 指标
def hlc3(high, low, close, talib=None, offset=None, **kwargs):
    """Indicator: HLC3"""
    # 验证参数
   # 验证 high、low、close 是否为 Series 类型
    high = verify_series(high)
    low = verify_series(low)
    close = verify_series(close)
   # 获取偏移量
    offset = get_offset(offset)
   # 判断是否使用 talib 库,默认为 True
    mode_tal = bool(talib) if isinstance(talib, bool) else True

    # 计算结果
   # 如果导入了 talib 库并且 mode_tal 为 True
    if Imports["talib"] and mode_tal:
       # 从 talib 库中导入 TYPPRICE 函数,计算 HLC3
        from talib import TYPPRICE
        hlc3 = TYPPRICE(high, low, close)
    else:
       # 否则,使用普通方法计算 HLC3
        hlc3 = (high + low + close) / 3.0

    # 偏移
   # 如果偏移量不为 0,则对结果进行偏移
    if offset != 0:
        hlc3 = hlc3.shift(offset)

    # 名称和类别
   # 设置结果的名称为 "HLC3",类别为 "overlap"
    hlc3.name = "HLC3"
    hlc3.category = "overlap"

    # 返回计算结果
    return hlc3

.\pandas-ta\pandas_ta\overlap\hma.py

# -*- coding: utf-8 -*-

# 从 numpy 库中导入 sqrt 函数并重命名为 npSqrt
from numpy import sqrt as npSqrt
# 从当前目录下的 wma 模块中导入 wma 函数
from .wma import wma
# 从 pandas_ta.utils 模块中导入 get_offset 和 verify_series 函数
from pandas_ta.utils import get_offset, verify_series

# 定义 Hull Moving Average (HMA) 指标函数
def hma(close, length=None, offset=None, **kwargs):
    """Indicator: Hull Moving Average (HMA)"""
    # 验证参数
    # 如果 length 存在且大于 0,则将其转换为整数,否则设为默认值 10
    length = int(length) if length and length > 0 else 10
    # 验证 close 数据为 pd.Series 类型,并且长度符合要求
    close = verify_series(close, length)
    # 获取 offset 值
    offset = get_offset(offset)

    # 如果 close 为空,则返回空值
    if close is None: return

    # 计算结果
    half_length = int(length / 2)
    sqrt_length = int(npSqrt(length))

    # 计算 wmaf 和 wmas
    wmaf = wma(close=close, length=half_length)
    wmas = wma(close=close, length=length)
    # 计算 HMA
    hma = wma(close=2 * wmaf - wmas, length=sqrt_length)

    # 调整偏移量
    if offset != 0:
        hma = hma.shift(offset)

    # 处理填充值
    if "fillna" in kwargs:
        hma.fillna(kwargs["fillna"], inplace=True)
    if "fill_method" in kwargs:
        hma.fillna(method=kwargs["fill_method"], inplace=True)

    # 设置指标名称和类别
    hma.name = f"HMA_{length}"
    hma.category = "overlap"

    return hma

# 设置 HMA 函数的文档字符串
hma.__doc__ = \
"""Hull Moving Average (HMA)

The Hull Exponential Moving Average attempts to reduce or remove lag in moving
averages.

Sources:
    https://alanhull.com/hull-moving-average

Calculation:
    Default Inputs:
        length=10
    WMA = Weighted Moving Average
    half_length = int(0.5 * length)
    sqrt_length = int(sqrt(length))

    wmaf = WMA(close, half_length)
    wmas = WMA(close, length)
    HMA = WMA(2 * wmaf - wmas, sqrt_length)

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:
    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\hwma.py

# -*- coding: utf-8 -*-
# 从 pandas 库中导入 Series 类
from pandas import Series
# 从 pandas_ta.utils 模块中导入 get_offset 和 verify_series 函数
from pandas_ta.utils import get_offset, verify_series


# 定义函数 hwma,计算 Holt-Winter 移动平均值
def hwma(close, na=None, nb=None, nc=None, offset=None, **kwargs):
    """Indicator: Holt-Winter Moving Average"""
    # 验证参数有效性并设置默认值
    na = float(na) if na and na > 0 and na < 1 else 0.2
    nb = float(nb) if nb and nb > 0 and nb < 1 else 0.1
    nc = float(nc) if nc and nc > 0 and nc < 1 else 0.1
    # 验证 close 参数并转换为 pd.Series 类型
    close = verify_series(close)
    # 获取偏移量
    offset = get_offset(offset)

    # 计算结果
    last_a = last_v = 0
    last_f = close.iloc[0]

    result = []
    m = close.size
    for i in range(m):
        # 计算 F
        F = (1.0 - na) * (last_f + last_v + 0.5 * last_a) + na * close.iloc[i]
        # 计算 V
        V = (1.0 - nb) * (last_v + last_a) + nb * (F - last_f)
        # 计算 A
        A = (1.0 - nc) * last_a + nc * (V - last_v)
        result.append((F + V + 0.5 * A))
        # 更新变量值
        last_a, last_f, last_v = A, F, V

    # 创建 Series 对象
    hwma = Series(result, index=close.index)

    # 处理偏移
    if offset != 0:
        hwma = hwma.shift(offset)

    # 处理填充值
    if "fillna" in kwargs:
        hwma.fillna(kwargs["fillna"], inplace=True)
    if "fill_method" in kwargs:
        hwma.fillna(method=kwargs["fill_method"], inplace=True)

    # 设置名称和分类
    suffix = f"{na}_{nb}_{nc}"
    hwma.name = f"HWMA_{suffix}"
    hwma.category = "overlap"

    return hwma



# 为 hwma 函数添加文档字符串
hwma.__doc__ = \
"""HWMA (Holt-Winter Moving Average)

Indicator HWMA (Holt-Winter Moving Average) is a three-parameter moving average
by the Holt-Winter method; the three parameters should be selected to obtain a
forecast.

This version has been implemented for Pandas TA by rengel8 based
on a publication for MetaTrader 5.

Sources:
    https://www.mql5.com/en/code/20856

Calculation:
    HWMA[i] = F[i] + V[i] + 0.5 * A[i]
    where..
    F[i] = (1-na) * (F[i-1] + V[i-1] + 0.5 * A[i-1]) + na * Price[i]
    V[i] = (1-nb) * (V[i-1] + A[i-1]) + nb * (F[i] - F[i-1])
    A[i] = (1-nc) * A[i-1] + nc * (V[i] - V[i-1])

Args:
    close (pd.Series): Series of 'close's
    na (float): Smoothed series parameter (from 0 to 1). Default: 0.2
    nb (float): Trend parameter (from 0 to 1). Default: 0.1
    nc (float): Seasonality parameter (from 0 to 1). Default: 0.1
    close (pd.Series): Series of 'close's

Kwargs:
    fillna (value, optional): pd.DataFrame.fillna(value)
    fill_method (value, optional): Type of fill method

Returns:
    pd.Series: hwma
"""

.\pandas-ta\pandas_ta\overlap\ichimoku.py

# -*- coding: utf-8 -*-
# 导入所需的库
from pandas import date_range, DataFrame, RangeIndex, Timedelta
from .midprice import midprice
from pandas_ta.utils import get_offset, verify_series

# 定义 Ichimoku 函数,计算 Ichimoku Kinkō Hyō 指标
def ichimoku(high, low, close, tenkan=None, kijun=None, senkou=None, include_chikou=True, offset=None, **kwargs):
    """Indicator: Ichimoku Kinkō Hyō (Ichimoku)"""
    # 设置默认的参数值
    tenkan = int(tenkan) if tenkan and tenkan > 0 else 9
    kijun = int(kijun) if kijun and kijun > 0 else 26
    senkou = int(senkou) if senkou and senkou > 0 else 52
    _length = max(tenkan, kijun, senkou)
    # 验证输入的数据
    high = verify_series(high, _length)
    low = verify_series(low, _length)
    close = verify_series(close, _length)
    offset = get_offset(offset)
    # 根据参数设置是否包含未来数据
    if not kwargs.get("lookahead", True):
        include_chikou = False

    # 如果输入数据有缺失,则返回空值
    if high is None or low is None or close is None: return None, None

    # 计算 Ichimoku 指标的各个线
    tenkan_sen = midprice(high=high, low=low, length=tenkan)
    kijun_sen = midprice(high=high, low=low, length=kijun)
    span_a = 0.5 * (tenkan_sen + kijun_sen)
    span_b = midprice(high=high, low=low, length=senkou)

    # 复制 Span A 和 Span B 在移动之前的值
    _span_a = span_a[-kijun:].copy()
    _span_b = span_b[-kijun:].copy()

    # 移动 Span A 和 Span B 的值
    span_a = span_a.shift(kijun)
    span_b = span_b.shift(kijun)
    chikou_span = close.shift(-kijun)

    # 根据偏移量对数据进行偏移
    if offset != 0:
        tenkan_sen = tenkan_sen.shift(offset)
        kijun_sen = kijun_sen.shift(offset)
        span_a = span_a.shift(offset)
        span_b = span_b.shift(offset)
        chikou_span = chikou_span.shift(offset)

    # 处理缺失值
    if "fillna" in kwargs:
        span_a.fillna(kwargs["fillna"], inplace=True)
        span_b.fillna(kwargs["fillna"], inplace=True)
        chikou_span.fillna(kwargs["fillna"], inplace=True)
    if "fill_method" in kwargs:
        span_a.fillna(method=kwargs["fill_method"], inplace=True)
        span_b.fillna(method=kwargs["fill_method"], inplace=True)
        chikou_span.fillna(method=kwargs["fill_method"], inplace=True)

    # 设置各个线的名称和类别
    span_a.name = f"ISA_{tenkan}"
    span_b.name = f"ISB_{kijun}"
    tenkan_sen.name = f"ITS_{tenkan}"
    kijun_sen.name = f"IKS_{kijun}"
    chikou_span.name = f"ICS_{kijun}"

    chikou_span.category = kijun_sen.category = tenkan_sen.category = "trend"
    span_b.category = span_a.category = chikou_span

    # 准备 Ichimoku DataFrame
    data = {
        span_a.name: span_a,
        span_b.name: span_b,
        tenkan_sen.name: tenkan_sen,
        kijun_sen.name: kijun_sen,
    }
    if include_chikou:
        data[chikou_span.name] = chikou_span

    ichimokudf = DataFrame(data)
    ichimokudf.name = f"ICHIMOKU_{tenkan}_{kijun}_{senkou}"
    ichimokudf.category = "overlap"

    # 准备 Span DataFrame
    last = close.index[-1]
    # 如果收盘价索引的数据类型为 "int64",执行以下操作
    if close.index.dtype == "int64":
        # 创建一个新的范围索引,起始于 last + 1,结束于 last + kijun + 1
        ext_index = RangeIndex(start=last + 1, stop=last + kijun + 1)
        # 创建一个空的 DataFrame,索引为 ext_index,列为 span_a.name 和 span_b.name
        spandf = DataFrame(index=ext_index, columns=[span_a.name, span_b.name])
        # 将 _span_a 和 _span_b 的索引设置为 ext_index
        _span_a.index = _span_b.index = ext_index
    # 如果收盘价索引的数据类型不为 "int64",执行以下操作
    else:
        # 统计收盘价索引中各值的频次,并取出出现频次最多的值
        df_freq = close.index.value_counts().mode()[0]
        # 创建一个时间增量对象,时间间隔为 df_freq 天
        tdelta = Timedelta(df_freq, unit="d")
        # 创建一个新的日期范围,起始日期为 last + tdelta,包含 kijun 个工作日
        new_dt = date_range(start=last + tdelta, periods=kijun, freq="B")
        # 创建一个空的 DataFrame,索引为 new_dt,列为 span_a.name 和 span_b.name
        spandf = DataFrame(index=new_dt, columns=[span_a.name, span_b.name])
        # 将 _span_a 和 _span_b 的索引设置为 new_dt
    
    spandf[span_a.name] = _span_a
    spandf[span_b.name] = _span_b
    # 设置 spandf 的名称为特定字符串,包含 tenkan 和 kijun 的值
    spandf.name = f"ICHISPAN_{tenkan}_{kijun}"
    # 设置 spandf 的类别为 "overlap"
    spandf.category = "overlap"
    
    # 返回 ichimokudf 和 spandf
    return ichimokudf, spandf
# 将 ichimoku.__doc__ 的值设为字符串,用于描述 Ichimoku Kinkō Hyō(一种用于金融市场预测的模型)的计算方法和参数
ichimoku.__doc__ = \
"""Ichimoku Kinkō Hyō (ichimoku)

Developed Pre WWII as a forecasting model for financial markets.

Sources:
    https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/ichimoku-ich/

Calculation:
    Default Inputs:
        tenkan=9, kijun=26, senkou=52
    MIDPRICE = Midprice
    TENKAN_SEN = MIDPRICE(high, low, close, length=tenkan)
    KIJUN_SEN = MIDPRICE(high, low, close, length=kijun)
    CHIKOU_SPAN = close.shift(-kijun)

    SPAN_A = 0.5 * (TENKAN_SEN + KIJUN_SEN)
    SPAN_A = SPAN_A.shift(kijun)

    SPAN_B = MIDPRICE(high, low, close, length=senkou)
    SPAN_B = SPAN_B.shift(kijun)

Args:
    high (pd.Series): Series of 'high's  # high 数据序列
    low (pd.Series): Series of 'low's  # low 数据序列
    close (pd.Series): Series of 'close's  # close 数据序列
    tenkan (int): Tenkan period. Default: 9  # Tenkan 周期,默认为 9
    kijun (int): Kijun period. Default: 26  # Kijun 周期,默认为 26
    senkou (int): Senkou period. Default: 52  # Senkou 周期,默认为 52
    include_chikou (bool): Whether to include chikou component. Default: True  # 是否包含 chikou 组件,默认为 True
    offset (int): How many periods to offset the result. Default: 0  # 结果偏移的周期数,默认为 0

Kwargs:
    fillna (value, optional): pd.DataFrame.fillna(value)  # fillna 方法的参数,用于填充缺失值
    fill_method (value, optional): Type of fill method  # 填充方法的类型

Returns:
    pd.DataFrame: Two DataFrames.  # 返回两个 DataFrame
        For the visible period: spanA, spanB, tenkan_sen, kijun_sen,  # 可见期间的 DataFrame,包含 spanA、spanB、tenkan_sen、kijun_sen
            and chikou_span columns  # 以及 chikou_span 列
        For the forward looking period: spanA and spanB columns  # 未来观察期间的 DataFrame,包含 spanA 和 spanB 列
"""
posted @ 2024-04-15 13:40  绝不原创的飞龙  阅读(25)  评论(0编辑  收藏  举报