PandasTA 原始碼解析(十一)

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

.\pandas-ta\pandas_ta\overlap\wcp.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


# 定義函式 wcp,計算加權收盤價(WCP)
def wcp(high, low, close, talib=None, offset=None, **kwargs):
    """Indicator: Weighted Closing Price (WCP)"""
    # 驗證引數
   high = verify_series(high)
   low = verify_series(low)
   close = verify_series(close)
    offset = get_offset(offset)
    mode_tal = bool(talib) if isinstance(talib, bool) else True

    # 計算結果
   if Imports["talib"] and mode_tal:
        from talib import WCLPRICE
        wcp = WCLPRICE(high, low, close)
    else:
        wcp = (high + low + 2 * close) / 4

    # 偏移
   if offset != 0:
        wcp = wcp.shift(offset)

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

    # 設定名稱和類別
    wcp.name = "WCP"
    wcp.category = "overlap"

    return wcp


# 設定函式 wcp 的文件字串
wcp.__doc__ = \
"""Weighted Closing Price (WCP)

Weighted Closing Price is the weighted price given: high, low
and double the close.

Sources:
    https://www.fmlabs.com/reference/default.htm?url=WeightedCloses.htm

Calculation:
    WCP = (2 * close + high + low) / 4

Args:
    high (pd.Series): Series of 'high's
    low (pd.Series): Series of 'low's
    close (pd.Series): Series of 'close's
    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\wma.py

# -*- coding: utf-8 -*-
# 匯入需要的模組和函式
from pandas import Series
from pandas_ta import Imports
from pandas_ta.utils import get_offset, verify_series


def wma(close, length=None, asc=None, talib=None, offset=None, **kwargs):
    """Indicator: Weighted Moving Average (WMA)"""
    # 驗證引數
    length = int(length) if length and length > 0 else 10  # 確定長度為正整數,預設為10
    asc = asc if asc else True  # 預設為升序
    close = verify_series(close, length)  # 確保close為Series,長度為length
    offset = get_offset(offset)  # 獲取偏移量
    mode_tal = bool(talib) if isinstance(talib, bool) else True  # 是否使用TA Lib,預設為True

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

    # 計算結果
    if Imports["talib"] and mode_tal:  # 如果安裝了TA Lib且使用TA Lib模式
        from talib import WMA
        wma = WMA(close, length)  # 使用TA Lib中的WMA函式計算WMA
    else:
        from numpy import arange as npArange
        from numpy import dot as npDot

        total_weight = 0.5 * length * (length + 1)  # 計算總權重
        weights_ = Series(npArange(1, length + 1))  # 建立1到length的Series
        weights = weights_ if asc else weights_[::-1]  # 如果升序,則不變;否則倒序

        def linear(w):
            def _compute(x):
                return npDot(x, w) / total_weight  # 線性權重計算WMA
            return _compute

        close_ = close.rolling(length, min_periods=length)  # 建立長度為length的rolling物件
        wma = close_.apply(linear(weights), raw=True)  # 應用線性權重計算WMA

    # 偏移
    if offset != 0:
        wma = wma.shift(offset)  # 偏移結果

    # 處理填充
    if "fillna" in kwargs:
        wma.fillna(kwargs["fillna"], inplace=True)  # 使用指定值填充空值
    if "fill_method" in kwargs:
        wma.fillna(method=kwargs["fill_method"], inplace=True)  # 使用指定填充方法填充空值

    # 名稱和類別
    wma.name = f"WMA_{length}"  # 設定名稱
    wma.category = "overlap"  # 設定類別

    return wma  # 返回WMA


wma.__doc__ = \
"""Weighted Moving Average (WMA)

The Weighted Moving Average where the weights are linearly increasing and
the most recent data has the heaviest weight.

Sources:
    https://en.wikipedia.org/wiki/Moving_average#Weighted_moving_average

Calculation:
    Default Inputs:
        length=10, asc=True
    total_weight = 0.5 * length * (length + 1)
    weights_ = [1, 2, ..., length + 1]  # Ascending
    weights = weights if asc else weights[::-1]

    def linear_weights(w):
        def _compute(x):
            return (w * x).sum() / total_weight
        return _compute

    WMA = close.rolling(length)_.apply(linear_weights(weights), 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
    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\zlma.py

# -*- coding: utf-8 -*-
# 匯入所需的函式庫
from . import (
    dema, ema, hma, linreg, rma, sma, swma, t3, tema, trima, vidya, wma
)
# 匯入輔助函式
from pandas_ta.utils import get_offset, verify_series

# 定義 Zero Lag Moving Average (ZLMA) 函式
def zlma(close, length=None, mamode=None, offset=None, **kwargs):
    """Indicator: Zero Lag Moving Average (ZLMA)"""
    # 驗證引數
    length = int(length) if length and length > 0 else 10
    mamode = mamode.lower() if isinstance(mamode, str) else "ema"
    close = verify_series(close, length)
    offset = get_offset(offset)

    if close is None: return

    # 計算結果
    lag = int(0.5 * (length - 1))
    close_ = 2 * close - close.shift(lag)
    # 根據不同的 mamode 選擇不同的移動平均方法
    if   mamode == "dema":   zlma = dema(close_, length=length, **kwargs)
    elif mamode == "hma":    zlma = hma(close_, length=length, **kwargs)
    elif mamode == "linreg": zlma = linreg(close_, length=length, **kwargs)
    elif mamode == "rma":    zlma = rma(close_, length=length, **kwargs)
    elif mamode == "sma":    zlma = sma(close_, length=length, **kwargs)
    elif mamode == "swma":   zlma = swma(close_, length=length, **kwargs)
    elif mamode == "t3":     zlma = t3(close_, length=length, **kwargs)
    elif mamode == "tema":   zlma = tema(close_, length=length, **kwargs)
    elif mamode == "trima":  zlma = trima(close_, length=length, **kwargs)
    elif mamode == "vidya":  zlma = vidya(close_, length=length, **kwargs)
    elif mamode == "wma":    zlma = wma(close_, length=length, **kwargs)
    else:                    zlma = ema(close_, length=length, **kwargs) # "ema"

    # 偏移結果
    if offset != 0:
        zlma = zlma.shift(offset)

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

    # 設定名稱和類別
    zlma.name = f"ZL_{zlma.name}"
    zlma.category = "overlap"

    return zlma

# 設定 ZLMA 函式的文件字串
zlma.__doc__ = \
"""Zero Lag Moving Average (ZLMA)

The Zero Lag Moving Average attempts to eliminate the lag associated
with moving averages.  This is an adaption created by John Ehler and Ric Way.

Sources:
    https://en.wikipedia.org/wiki/Zero_lag_exponential_moving_average

Calculation:
    Default Inputs:
        length=10, mamode=EMA
    EMA = Exponential Moving Average
    lag = int(0.5 * (length - 1))

    SOURCE = 2 * close - close.shift(lag)
    ZLMA = MA(kind=mamode, SOURCE, length)

Args:
    close (pd.Series): Series of 'close's
    length (int): It's period. Default: 10
    mamode (str): Options: 'ema', 'hma', 'sma', 'wma'. Default: 'ema'
    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\__init__.py

# 匯入 alma 指標計算模組
from .alma import alma
# 匯入 dema 指標計算模組
from .dema import dema
# 匯入 ema 指標計算模組
from .ema import ema
# 匯入 fwma 指標計算模組
from .fwma import fwma
# 匯入 hilo 指標計算模組
from .hilo import hilo
# 匯入 hl2 指標計算模組
from .hl2 import hl2
# 匯入 hlc3 指標計算模組
from .hlc3 import hlc3
# 匯入 hma 指標計算模組
from .hma import hma
# 匯入 hwma 指標計算模組
from .hwma import hwma
# 匯入 ichimoku 指標計算模組
from .ichimoku import ichimoku
# 匯入 jma 指標計算模組
from .jma import jma
# 匯入 kama 指標計算模組
from .kama import kama
# 匯入 linreg 指標計算模組
from .linreg import linreg
# 匯入 ma 指標計算模組
from .ma import ma
# 匯入 mcgd 指標計算模組
from .mcgd import mcgd
# 匯入 midpoint 指標計算模組
from .midpoint import midpoint
# 匯入 midprice 指標計算模組
from .midprice import midprice
# 匯入 ohlc4 指標計算模組
from .ohlc4 import ohlc4
# 匯入 pwma 指標計算模組
from .pwma import pwma
# 匯入 rma 指標計算模組
from .rma import rma
# 匯入 sinwma 指標計算模組
from .sinwma import sinwma
# 匯入 sma 指標計算模組
from .sma import sma
# 匯入 ssf 指標計算模組
from .ssf import ssf
# 匯入 supertrend 指標計算模組
from .supertrend import supertrend
# 匯入 swma 指標計算模組
from .swma import swma
# 匯入 t3 指標計算模組
from .t3 import t3
# 匯入 tema 指標計算模組
from .tema import tema
# 匯入 trima 指標計算模組
from .trima import trima
# 匯入 vidya 指標計算模組
from .vidya import vidya
# 匯入 vwap 指標計算模組
from .vwap import vwap
# 匯入 vwma 指標計算模組
from .vwma import vwma
# 匯入 wcp 指標計算模組
from .wcp import wcp
# 匯入 wma 指標計算模組
from .wma import wma
# 匯入 zlma 指標計算模組
from .zlma import zlma

.\pandas-ta\pandas_ta\performance\drawdown.py

# 匯入所需模組
# -*- coding: utf-8 -*-
# 從 numpy 模組中匯入 log 函式並重新命名為 nplog
from numpy import log as nplog
# 從 numpy 模組中匯入 seterr 函式
from numpy import seterr
# 從 pandas 模組中匯入 DataFrame 類
from pandas import DataFrame
# 從 pandas_ta.utils 模組中匯入 get_offset 和 verify_series 函式
from pandas_ta.utils import get_offset, verify_series

# 定義函式 drawdown,用於計算資產或投資組合的回撤情況
def drawdown(close, offset=None, **kwargs) -> DataFrame:
    """Indicator: Drawdown (DD)"""
    # 驗證引數合法性,確保 close 是一個 Series 物件
    close = verify_series(close)
    # 獲取偏移量
    offset = get_offset(offset)

    # 計算結果
    # 計算歷史最高收盤價
    max_close = close.cummax()
    # 計算回撤
    dd = max_close - close
    # 計算回撤百分比
    dd_pct = 1 - (close / max_close)

    # 臨時忽略 numpy 的警告
    _np_err = seterr()
    seterr(divide="ignore", invalid="ignore")
    # 計算回撤的對數
    dd_log = nplog(max_close) - nplog(close)
    # 恢復 numpy 的警告設定
    seterr(divide=_np_err["divide"], invalid=_np_err["invalid"])

    # 調整偏移量
    if offset != 0:
        dd = dd.shift(offset)
        dd_pct = dd_pct.shift(offset)
        dd_log = dd_log.shift(offset)

    # 處理填充值
    if "fillna" in kwargs:
        dd.fillna(kwargs["fillna"], inplace=True)
        dd_pct.fillna(kwargs["fillna"], inplace=True)
        dd_log.fillna(kwargs["fillna"], inplace=True)
    if "fill_method" in kwargs:
        dd.fillna(method=kwargs["fill_method"], inplace=True)
        dd_pct.fillna(method=kwargs["fill_method"], inplace=True)
        dd_log.fillna(method=kwargs["fill_method"], inplace=True)

    # 設定列名和分類
    dd.name = "DD"
    dd_pct.name = f"{dd.name}_PCT"
    dd_log.name = f"{dd.name}_LOG"
    dd.category = dd_pct.category = dd_log.category = "performance"

    # 準備返回的 DataFrame
    data = {dd.name: dd, dd_pct.name: dd_pct, dd_log.name: dd_log}
    df = DataFrame(data)
    df.name = dd.name
    df.category = dd.category

    return df

# 設定函式文件字串
drawdown.__doc__ = \
"""Drawdown (DD)

Drawdown is a peak-to-trough decline during a specific period for an investment,
trading account, or fund. It is usually quoted as the percentage between the
peak and the subsequent trough.

Sources:
    https://www.investopedia.com/terms/d/drawdown.asp

Calculation:
    PEAKDD = close.cummax()
    DD = PEAKDD - close
    DD% = 1 - (close / PEAKDD)
    DDlog = log(PEAKDD / close)

Args:
    close (pd.Series): Series of 'close's.
    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.DataFrame: drawdown, drawdown percent, drawdown log columns
"""

.\pandas-ta\pandas_ta\performance\log_return.py

# -*- coding: utf-8 -*-
# 從 numpy 中匯入 log 函式並重新命名為 nplog
from numpy import log as nplog
# 從 pandas_ta.utils 中匯入 get_offset 和 verify_series 函式
from pandas_ta.utils import get_offset, verify_series


def log_return(close, length=None, cumulative=None, offset=None, **kwargs):
    """Indicator: Log Return"""
    # 驗證引數
    # 如果 length 存在且大於 0,則將其轉換為整數,否則設為 1
    length = int(length) if length and length > 0 else 1
    # 如果 cumulative 存在且為真,則設為 True,否則設為 False
    cumulative = bool(cumulative) if cumulative is not None and cumulative else False
    # 驗證 close 是否為有效的 Series,並設定長度
    close = verify_series(close, length)
    # 獲取偏移量
    offset = get_offset(offset)

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

    # 計算結果
    if cumulative:
        # 計算累積對數收益率
        log_return = nplog(close / close.iloc[0])
    else:
        # 計算對數收益率
        log_return = nplog(close / close.shift(length))

    # 偏移結果
    if offset != 0:
        log_return = log_return.shift(offset)

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

    # 設定名稱和類別
    log_return.name = f"{'CUM' if cumulative else ''}LOGRET_{length}"
    log_return.category = "performance"

    return log_return


# 設定 log_return 函式的文件字串
log_return.__doc__ = \
"""Log Return

Calculates the logarithmic return of a Series.
See also: help(df.ta.log_return) for additional **kwargs a valid 'df'.

Sources:
    https://stackoverflow.com/questions/31287552/logarithmic-returns-in-pandas-dataframe

Calculation:
    Default Inputs:
        length=1, cumulative=False
    LOGRET = log( close.diff(periods=length) )
    CUMLOGRET = LOGRET.cumsum() if cumulative

Args:
    close (pd.Series): Series of 'close's
    length (int): It's period. Default: 20
    cumulative (bool): If True, returns the cumulative returns. Default: False
    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\performance\percent_return.py

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

# 從 pandas_ta.utils 模組中匯入 get_offset 和 verify_series 函式
from pandas_ta.utils import get_offset, verify_series

# 定義一個名為 percent_return 的函式,用於計算百分比收益率
def percent_return(close, length=None, cumulative=None, offset=None, **kwargs):
    """Indicator: Percent Return"""
    
    # 驗證引數
    length = int(length) if length and length > 0 else 1
    cumulative = bool(cumulative) if cumulative is not None and cumulative else False
    close = verify_series(close, length)
    offset = get_offset(offset)

    if close is None: return

    # 計算結果
    if cumulative:
        pct_return = (close / close.iloc[0]) - 1
    else:
        pct_return = close.pct_change(length) # (close / close.shift(length)) - 1

    # 偏移
    if offset != 0:
        pct_return = pct_return.shift(offset)

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

    # 設定名稱和類別
    pct_return.name = f"{'CUM' if cumulative else ''}PCTRET_{length}"
    pct_return.category = "performance"

    return pct_return

# 設定 percent_return 函式的文件字串
percent_return.__doc__ = \
"""Percent Return

Calculates the percent return of a Series.
See also: help(df.ta.percent_return) for additional **kwargs a valid 'df'.

Sources:
    https://stackoverflow.com/questions/31287552/logarithmic-returns-in-pandas-dataframe

Calculation:
    Default Inputs:
        length=1, cumulative=False
    PCTRET = close.pct_change(length)
    CUMPCTRET = PCTRET.cumsum() if cumulative

Args:
    close (pd.Series): Series of 'close's
    length (int): It's period. Default: 20
    cumulative (bool): If True, returns the cumulative returns. Default: False
    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\performance\__init__.py

# 設定檔案編碼為 UTF-8
# 匯入 drawdown 模組中的 drawdown 函式
# 匯入 log_return 模組中的 log_return 函式
# 匯入 percent_return 模組中的 percent_return 函式

.\pandas-ta\pandas_ta\statistics\entropy.py

# -*- coding: utf-8 -*-
# 匯入 log 函式並將其命名為 npLog
from numpy import log as npLog
# 匯入 get_offset 和 verify_series 函式
from pandas_ta.utils import get_offset, verify_series


# 定義熵指標函式,接受收盤價、週期、對數的基數、偏移量和其他引數
def entropy(close, length=None, base=None, offset=None, **kwargs):
    """Indicator: Entropy (ENTP)"""
    # 驗證引數
    # 如果 length 存在且大於 0,則將其轉換為整數,否則設為預設值 10
    length = int(length) if length and length > 0 else 10
    # 如果 base 存在且大於 0,則將其轉換為浮點數,否則設為預設值 2.0
    base = float(base) if base and base > 0 else 2.0
    # 驗證收盤價是否是一個有效的 Series,如果不是則返回 None
    close = verify_series(close, length)
    # 獲取偏移量
    offset = get_offset(offset)

    # 如果收盤價為 None,則返回 None
    if close is None: return

    # 計算結果
    # 計算每個價格佔總和的比例
    p = close / close.rolling(length).sum()
    # 計算熵
    entropy = (-p * npLog(p) / npLog(base)).rolling(length).sum()

    # 偏移結果
    if offset != 0:
        entropy = entropy.shift(offset)

    # 處理填充
    # 如果引數中包含 "fillna",則使用指定值填充空值
    if "fillna" in kwargs:
        entropy.fillna(kwargs["fillna"], inplace=True)
    # 如果引數中包含 "fill_method",則使用指定的填充方法填充空值
    if "fill_method" in kwargs:
        entropy.fillna(method=kwargs["fill_method"], inplace=True)

    # 設定名稱和類別
    entropy.name = f"ENTP_{length}"
    entropy.category = "statistics"

    return entropy


# 設定熵指標函式的文件字串
entropy.__doc__ = \
"""Entropy (ENTP)

Introduced by Claude Shannon in 1948, entropy measures the unpredictability
of the data, or equivalently, of its average information. A die has higher
entropy (p=1/6) versus a coin (p=1/2).

Sources:
    https://en.wikipedia.org/wiki/Entropy_(information_theory)

Calculation:
    Default Inputs:
        length=10, base=2

    P = close / SUM(close, length)
    E = SUM(-P * npLog(P) / npLog(base), length)

Args:
    close (pd.Series): Series of 'close's
    length (int): It's period. Default: 10
    base (float): Logarithmic Base. Default: 2
    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\statistics\kurtosis.py

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

# 從 pandas_ta.utils 模組中匯入 get_offset 和 verify_series 函式
from pandas_ta.utils import get_offset, verify_series

# 定義函式 kurtosis,計算某個時間段內的峰度
def kurtosis(close, length=None, offset=None, **kwargs):
    """Indicator: Kurtosis"""
    # 驗證引數
    # 如果 length 存在且大於 0,則將其轉換為整數;否則將 length 設為預設值 30
    length = int(length) if length and length > 0 else 30
    # 如果 kwargs 中有 "min_periods" 引數且不為 None,則將其轉換為整數;否則將 min_periods 設為 length 的值
    min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else length
    # 驗證 close 引數,並確保其長度不小於 length 和 min_periods 的最大值
    close = verify_series(close, max(length, min_periods))
    # 獲取偏移量
    offset = get_offset(offset)

    # 如果 close 為 None,則返回空值
    if close is None: return

    # 計算結果
    # 計算 close 的滾動視窗長度為 length 的峰度,並使用 min_periods 引數指定最小期數
    kurtosis = close.rolling(length, min_periods=min_periods).kurt()

    # 處理偏移
    if offset != 0:
        # 對計算的峰度結果進行偏移
        kurtosis = kurtosis.shift(offset)

    # 處理填充
    if "fillna" in kwargs:
        # 使用指定的值填充缺失值
        kurtosis.fillna(kwargs["fillna"], inplace=True)
    if "fill_method" in kwargs:
        # 使用指定的填充方法填充缺失值
        kurtosis.fillna(method=kwargs["fill_method"], inplace=True)

    # 設定指標的名稱和類別
    kurtosis.name = f"KURT_{length}"
    kurtosis.category = "statistics"

    # 返回計算結果
    return kurtosis


# 為函式 kurtosis 新增文件字串
kurtosis.__doc__ = \
"""Rolling Kurtosis

Sources:

Calculation:
    Default Inputs:
        length=30
    KURTOSIS = close.rolling(length).kurt()

Args:
    close (pd.Series): Series of 'close's
    length (int): It's period. Default: 30
    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\statistics\mad.py

# -*- coding: utf-8 -*-
# 從 numpy 中匯入 fabs 函式並重新命名為 npfabs
from numpy import fabs as npfabs
# 從 pandas_ta.utils 中匯入 get_offset 和 verify_series 函式
from pandas_ta.utils import get_offset, verify_series


# 定義函式:均值絕對偏差
def mad(close, length=None, offset=None, **kwargs):
    """Indicator: Mean Absolute Deviation"""
    # 驗證引數
    # 如果 length 存在且大於 0,則將其轉換為整數,否則設為預設值 30
    length = int(length) if length and length > 0 else 30
    # 如果 kwargs 中存在 "min_periods",則將其轉換為整數,否則使用 length 作為預設值
    min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else length
    # 驗證 close 序列,保證長度至少為 length 和 min_periods 中的較大值
    close = verify_series(close, max(length, min_periods))
    # 獲取偏移量
    offset = get_offset(offset)

    # 如果 close 為空,則返回空值
    if close is None: return

    # 計算結果
    def mad_(series):
        """Mean Absolute Deviation"""
        # 計算序列與其均值的絕對差值的均值
        return npfabs(series - series.mean()).mean()

    # 使用 rolling 函式計算滾動均值絕對偏差
    mad = close.rolling(length, min_periods=min_periods).apply(mad_, raw=True)

    # 偏移
    if offset != 0:
        mad = mad.shift(offset)

    # 處理填充
    # 如果 kwargs 中存在 "fillna",則使用該值填充空值
    if "fillna" in kwargs:
        mad.fillna(kwargs["fillna"], inplace=True)
    # 如果 kwargs 中存在 "fill_method",則使用指定的填充方法
    if "fill_method" in kwargs:
        mad.fillna(method=kwargs["fill_method"], inplace=True)

    # 設定指標的名稱和類別
    mad.name = f"MAD_{length}"
    mad.category = "statistics"

    return mad


# 設定函式文件字串
mad.__doc__ = \
"""Rolling Mean Absolute Deviation

Sources:

Calculation:
    Default Inputs:
        length=30
    mad = close.rolling(length).mad()

Args:
    close (pd.Series): Series of 'close's
    length (int): It's period. Default: 30
    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\statistics\median.py

# -*- coding: utf-8 -*-
# 從 pandas_ta.utils 模組中匯入 get_offset 和 verify_series 函式
from pandas_ta.utils import get_offset, verify_series

# 定義一個名為 median 的函式,用於計算中位數指標
def median(close, length=None, offset=None, **kwargs):
    """Indicator: Median"""
    # 驗證引數
    # 如果 length 存在且大於 0,則將其轉換為整數,否則設為預設值 30
    length = int(length) if length and length > 0 else 30
    # 如果 kwargs 中存在 "min_periods",且其值不為 None,則將其轉換為整數,否則設為 length 的值
    min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else length
    # 驗證 close 是否為有效的 Series,並設定最小長度為 length 和 min_periods 中的較大值
    close = verify_series(close, max(length, min_periods))
    # 獲取偏移量
    offset = get_offset(offset)

    # 如果 close 為 None,則返回空值
    if close is None: return

    # 計算結果
    # 計算 close 的滾動中位數,視窗長度為 length,最小觀測數為 min_periods
    median = close.rolling(length, min_periods=min_periods).median()

    # 偏移結果
    if offset != 0:
        median = median.shift(offset)

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

    # 設定指標名稱和類別
    median.name = f"MEDIAN_{length}"
    median.category = "statistics"

    return median

# 設定 median 函式的文件字串
median.__doc__ = \
"""Rolling Median

Rolling Median of over 'n' periods. Sibling of a Simple Moving Average.

Sources:
    https://www.incrediblecharts.com/indicators/median_price.php

Calculation:
    Default Inputs:
        length=30
    MEDIAN = close.rolling(length).median()

Args:
    close (pd.Series): Series of 'close's
    length (int): It's period. Default: 30
    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\statistics\quantile.py

# -*- coding: utf-8 -*-
# 從 pandas_ta.utils 匯入 get_offset 和 verify_series 函式
from pandas_ta.utils import get_offset, verify_series

# 定義一個名為 quantile 的函式,用於計算滾動分位數
def quantile(close, length=None, q=None, offset=None, **kwargs):
    """Indicator: Quantile"""  # 函式文件字串,指示 quantile 函式的作用
    # 驗證引數
    # 如果 length 存在且大於 0,則將其轉換為整數,否則設為預設值 30
    length = int(length) if length and length > 0 else 30
    # 如果 kwargs 中存在 "min_periods" 鍵且其值不為 None,則將其轉換為整數,否則設為 length 的值
    min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else length
    # 如果 q 存在且大於 0 且小於 1,則將其轉換為浮點數,否則設為預設值 0.5
    q = float(q) if q and q > 0 and q < 1 else 0.5
    # 驗證 close 序列,確保其長度不小於 length 和 min_periods 中的較大值
    close = verify_series(close, max(length, min_periods))
    # 獲取偏移量
    offset = get_offset(offset)

    # 如果 close 為 None,則返回 None
    if close is None: return

    # 計算結果
    # 使用 close 序列進行滾動視窗計算分位數,視窗長度為 length,最小週期數為 min_periods
    quantile = close.rolling(length, min_periods=min_periods).quantile(q)

    # 偏移結果
    # 如果偏移量不為 0,則對 quantile 序列進行偏移
    if offset != 0:
        quantile = quantile.shift(offset)

    # 處理填充值
    # 如果 kwargs 中存在 "fillna" 鍵,則使用給定值填充 quantile 序列的缺失值
    if "fillna" in kwargs:
        quantile.fillna(kwargs["fillna"], inplace=True)
    # 如果 kwargs 中存在 "fill_method" 鍵,則使用指定的填充方法填充 quantile 序列的缺失值
    if "fill_method" in kwargs:
        quantile.fillna(method=kwargs["fill_method"], inplace=True)

    # 序列命名和分類
    # 設定 quantile 序列的名稱為 "QTL_{length}_{q}"
    quantile.name = f"QTL_{length}_{q}"
    # 設定 quantile 序列的分類為 "statistics"
    quantile.category = "statistics"

    return quantile  # 返回 quantile 序列


# 為 quantile 函式新增文件字串,說明其作用、源以及引數等資訊
quantile.__doc__ = \
"""Rolling Quantile

Sources:

Calculation:
    Default Inputs:
        length=30, q=0.5
    QUANTILE = close.rolling(length).quantile(q)

Args:
    close (pd.Series): Series of 'close's
    length (int): It's period. Default: 30
    q (float): The quantile. Default: 0.5
    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\statistics\skew.py

# -*- coding: utf-8 -*-
# 從 pandas_ta.utils 中匯入 get_offset 和 verify_series 函式
from pandas_ta.utils import get_offset, verify_series


def skew(close, length=None, offset=None, **kwargs):
    """Indicator: Skew"""
    # 驗證引數
    # 如果 length 存在且大於0,則將其轉換為整數,否則預設為30
    length = int(length) if length and length > 0 else 30
    # 如果 kwargs 中包含 "min_periods" 並且其值不為 None,則將其轉換為整數,否則預設為 length
    min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else length
    # 驗證 close 是否為 pd.Series 型別,並保證其長度不小於 length 和 min_periods 中的較大值
    close = verify_series(close, max(length, min_periods))
    # 獲取偏移量
    offset = get_offset(offset)

    # 如果 close 為 None,則返回空值
    if close is None: return

    # 計算結果
    # 計算 close 的滾動 skewness(偏度)
    skew = close.rolling(length, min_periods=min_periods).skew()

    # 偏移結果
    # 如果偏移量不為零,則對 skew 進行偏移
    if offset != 0:
        skew = skew.shift(offset)

    # 處理填充值
    # 如果 kwargs 中包含 "fillna",則使用指定值填充缺失值
    if "fillna" in kwargs:
        skew.fillna(kwargs["fillna"], inplace=True)
    # 如果 kwargs 中包含 "fill_method",則使用指定的填充方法填充缺失值
    if "fill_method" in kwargs:
        skew.fillna(method=kwargs["fill_method"], inplace=True)

    # 名稱和類別
    # 設定 skew 的名稱為 "SKEW_長度"
    skew.name = f"SKEW_{length}"
    # 設定 skew 的類別為 "statistics"
    skew.category = "statistics"

    # 返回結果
    return skew


# 更新 skew 函式的文件字串
skew.__doc__ = \
"""Rolling Skew

Sources:

Calculation:
    Default Inputs:
        length=30
    SKEW = close.rolling(length).skew()

Args:
    close (pd.Series): Series of 'close's
    length (int): It's period. Default: 30
    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.
"""

相關文章