PandasTA 原始碼解析(八)

绝不原创的飞龙發表於2024-04-15

.\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 列
"""

相關文章