.\pandas-ta\pandas_ta\volume\pvol.py
# -*- coding: utf-8 -*-
# 匯入所需的庫和函式
from pandas_ta.utils import get_offset, signed_series, verify_series
# 定義函式 pvol,計算價格和成交量的乘積
def pvol(close, volume, offset=None, **kwargs):
"""Indicator: Price-Volume (PVOL)"""
# 驗證引數的有效性
close = verify_series(close) # 驗證價格序列
volume = verify_series(volume) # 驗證成交量序列
offset = get_offset(offset) # 獲取偏移量
signed = kwargs.pop("signed", False) # 獲取 signed 引數,預設為 False
# 計算結果
pvol = close * volume # 計算價格和成交量的乘積
if signed:
pvol *= signed_series(close, 1) # 如果 signed 為 True,則乘以 close 的符號系列
# 偏移
if offset != 0:
pvol = pvol.shift(offset) # 對結果進行偏移
# 處理填充
if "fillna" in kwargs:
pvol.fillna(kwargs["fillna"], inplace=True) # 使用指定值填充缺失值
if "fill_method" in kwargs:
pvol.fillna(method=kwargs["fill_method"], inplace=True) # 使用指定的填充方法填充缺失值
# 設定名稱和分類
pvol.name = f"PVOL" # 設定結果的名稱
pvol.category = "volume" # 設定結果的分類
return pvol # 返回計算結果
pvol.__doc__ = \
"""Price-Volume (PVOL)
Returns a series of the product of price and volume.
Calculation:
if signed:
pvol = signed_series(close, 1) * close * volume
else:
pvol = close * volume
Args:
close (pd.Series): Series of 'close's
volume (pd.Series): Series of 'volume's
signed (bool): Keeps the sign of the difference in 'close's. 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\volume\pvr.py
# -*- coding: utf-8 -*-
# 從pandas_ta.utils模組中匯入verify_series函式
from pandas_ta.utils import verify_series
# 從numpy中匯入別名為npNaN的nan值
from numpy import nan as npNaN
# 從pandas模組中匯入Series類
from pandas import Series
# 定義函式pvr,計算價格成交量等級指標
def pvr(close, volume):
""" Indicator: Price Volume Rank"""
# 驗證引數
close = verify_series(close)
volume = verify_series(volume)
# 計算結果
# 計算收盤價的差分並填充NaN值為0
close_diff = close.diff().fillna(0)
# 計算成交量的差分並填充NaN值為0
volume_diff = volume.diff().fillna(0)
# 建立與close索引相同的Series物件,並填充NaN值為npNaN
pvr_ = Series(npNaN, index=close.index)
# 根據條件設定pvr_中的值
pvr_.loc[(close_diff >= 0) & (volume_diff >= 0)] = 1
pvr_.loc[(close_diff >= 0) & (volume_diff < 0)] = 2
pvr_.loc[(close_diff < 0) & (volume_diff >= 0)] = 3
pvr_.loc[(close_diff < 0) & (volume_diff < 0)] = 4
# 設定名稱和分類
pvr_.name = f"PVR"
pvr_.category = "volume"
return pvr_
# 設定函式pvr的文件字串
pvr.__doc__ = \
"""Price Volume Rank
The Price Volume Rank was developed by Anthony J. Macek and is described in his
article in the June, 1994 issue of Technical Analysis of Stocks & Commodities
Magazine. It was developed as a simple indicator that could be calculated even
without a computer. The basic interpretation is to buy when the PV Rank is below
2.5 and sell when it is above 2.5.
Sources:
https://www.fmlabs.com/reference/default.htm?url=PVrank.htm
Calculation:
return 1 if 'close change' >= 0 and 'volume change' >= 0
return 2 if 'close change' >= 0 and 'volume change' < 0
return 3 if 'close change' < 0 and 'volume change' >= 0
return 4 if 'close change' < 0 and 'volume change' < 0
Args:
close (pd.Series): Series of 'close's
volume (pd.Series): Series of 'volume's
Returns:
pd.Series: New feature generated.
"""
.\pandas-ta\pandas_ta\volume\pvt.py
# -*- coding: utf-8 -*-
# 從 pandas_ta.momentum 模組中匯入 roc 函式
from pandas_ta.momentum import roc
# 從 pandas_ta.utils 模組中匯入 get_drift、get_offset、verify_series 函式
from pandas_ta.utils import get_drift, get_offset, verify_series
# 定義函式 pvt,計算價格-成交量趨勢指標(Price-Volume Trend,PVT)
def pvt(close, volume, drift=None, offset=None, **kwargs):
"""Indicator: Price-Volume Trend (PVT)"""
# 驗證引數
close = verify_series(close) # 驗證並確保 close 是有效的 Series 型別
volume = verify_series(volume) # 驗證並確保 volume 是有效的 Series 型別
drift = get_drift(drift) # 獲取漂移引數的值
offset = get_offset(offset) # 獲取偏移引數的值
# 計算結果
# 計算 ROC(收盤價的變化率)並乘以成交量
pv = roc(close=close, length=drift) * volume
# 計算 PVT 的累積值
pvt = pv.cumsum()
# 調整偏移
if offset != 0:
pvt = pvt.shift(offset) # 將結果向前或向後偏移指定的週期數
# 處理填充值
if "fillna" in kwargs:
pvt.fillna(kwargs["fillna"], inplace=True) # 使用指定的值填充缺失值
if "fill_method" in kwargs:
pvt.fillna(method=kwargs["fill_method"], inplace=True) # 使用指定的填充方法填充缺失值
# 命名並分類化結果
pvt.name = f"PVT" # 設定結果 Series 的名稱
pvt.category = "volume" # 設定結果 Series 的分類
return pvt # 返回 PVT 結果的 Series
# 設定函式 pvt 的文件字串
pvt.__doc__ = \
"""Price-Volume Trend (PVT)
The Price-Volume Trend utilizes the Rate of Change with volume to
and it's cumulative values to determine money flow.
Sources:
https://www.tradingview.com/wiki/Price_Volume_Trend_(PVT)
Calculation:
Default Inputs:
drift=1
ROC = Rate of Change
pv = ROC(close, drift) * volume
PVT = pv.cumsum()
Args:
close (pd.Series): Series of 'close's
volume (pd.Series): Series of 'volume's
drift (int): The diff 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\volume\vp.py
# -*- coding: utf-8 -*-
# 從 numpy 庫中匯入 array_split 函式
from numpy import array_split
# 從 numpy 庫中匯入 mean 函式
from numpy import mean
# 從 pandas 庫中匯入 cut、concat、DataFrame 函式
from pandas import cut, concat, DataFrame
# 從 pandas_ta.utils 模組中匯入 signed_series、verify_series 函式
from pandas_ta.utils import signed_series, verify_series
def vp(close, volume, width=None, **kwargs):
"""Indicator: Volume Profile (VP)"""
# 驗證引數
# 如果寬度引數存在且大於 0,則將其轉換為整數型別,否則設為預設值 10
width = int(width) if width and width > 0 else 10
# 驗證 close 資料序列,確保長度為 width
close = verify_series(close, width)
# 驗證 volume 資料序列,確保長度為 width
volume = verify_series(volume, width)
# 從 kwargs 中彈出 sort_close 引數,預設值為 False
sort_close = kwargs.pop("sort_close", False)
# 如果 close 或 volume 為空,則返回 None
if close is None or volume is None: return
# 設定
# 生成符號價格序列,即 close 的漲跌情況,用於後續計算正負成交量
signed_price = signed_series(close, 1)
# 正成交量為 volume 與符號價格序列大於 0 的乘積
pos_volume = volume * signed_price[signed_price > 0]
pos_volume.name = volume.name
# 負成交量為 volume 與符號價格序列小於 0 的乘積,乘以 -1
neg_volume = -volume * signed_price[signed_price < 0]
neg_volume.name = volume.name
# 合併 close、正成交量、負成交量 到一個 DataFrame 中
vp = concat([close, pos_volume, neg_volume], axis=1)
close_col = f"{vp.columns[0]}"
high_price_col = f"high_{close_col}"
low_price_col = f"low_{close_col}"
mean_price_col = f"mean_{close_col}"
volume_col = f"{vp.columns[1]}"
pos_volume_col = f"pos_{volume_col}"
neg_volume_col = f"neg_{volume_col}"
total_volume_col = f"total_{volume_col}"
vp.columns = [close_col, pos_volume_col, neg_volume_col]
# sort_close: 在將資料切分為範圍之前,是否根據收盤價進行排序。預設值為 False
# 如果為 False,則根據日期索引或時間順序排序,而不是根據價格
if sort_close:
# 將 mean_price_col 列設定為 close_col 列的值
vp[mean_price_col] = vp[close_col]
# 按照 close_col 列的值進行分組,並計算各範圍內的平均價、正成交量、負成交量
vpdf = vp.groupby(cut(vp[close_col], width, include_lowest=True, precision=2)).agg({
mean_price_col: mean,
pos_volume_col: sum,
neg_volume_col: sum,
})
# 從索引中獲取範圍的最低價格和最高價格
vpdf[low_price_col] = [x.left for x in vpdf.index]
vpdf[high_price_col] = [x.right for x in vpdf.index]
# 重置索引並重新排列列的順序
vpdf = vpdf.reset_index(drop=True)
vpdf = vpdf[[low_price_col, mean_price_col, high_price_col, pos_volume_col, neg_volume_col]]
else:
# 將 vp DataFrame 切分為若干子 DataFrame,每個子 DataFrame 包含近似相等數量的資料點
vp_ranges = array_split(vp, width)
# 遍歷每個子 DataFrame,計算範圍內的最低價、平均價、最高價、正成交量、負成交量,並生成生成器物件
result = ({
low_price_col: r[close_col].min(),
mean_price_col: r[close_col].mean(),
high_price_col: r[close_col].max(),
pos_volume_col: r[pos_volume_col].sum(),
neg_volume_col: r[neg_volume_col].sum(),
} for r in vp_ranges)
# 將生成器物件轉換為 DataFrame
vpdf = DataFrame(result)
# 計算總成交量,並新增到 DataFrame 中
vpdf[total_volume_col] = vpdf[pos_volume_col] + vpdf[neg_volume_col]
# 處理填充值
# 如果 kwargs 中包含 fillna 引數,則使用該引數填充 NaN 值
if "fillna" in kwargs:
vpdf.fillna(kwargs["fillna"], inplace=True)
# 如果 kwargs 中包含 fill_method 引數,則使用該引數填充 NaN 值
if "fill_method" in kwargs:
vpdf.fillna(method=kwargs["fill_method"], inplace=True)
# 命名和分類
vpdf.name = f"VP_{width}"
vpdf.category = "volume"
# 返回結果 DataFrame
return vpdf
# 將函式文件字串設為指定內容
vp.__doc__ = \
"""Volume Profile (VP)
Calculates the Volume Profile by slicing price into ranges.
Note: Value Area is not calculated.
Sources:
https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:volume_by_price
https://www.tradingview.com/wiki/Volume_Profile
http://www.ranchodinero.com/volume-tpo-essentials/
"""
# 訪問指定網址以獲取相關資訊,這是一個網頁連結
https://www.tradingtechnologies.com/blog/2013/05/15/volume-at-price/
# 計算函式
Calculation:
# 預設輸入引數:寬度為10
Default Inputs:
width=10
# 將 'close'、'pos_volume'、'neg_volume' 三個 Series 按列合併成一個 DataFrame
vp = pd.concat([close, pos_volume, neg_volume], axis=1)
# 如果需要按 'close' 排序
if sort_close:
# 將 'close' 列按照指定寬度切割成不同範圍的區間
vp_ranges = cut(vp[close_col], width)
# 對於每個區間,計算以下統計量:左邊界、平均 'close'、右邊界、'pos_volume'、'neg_volume',結果為一個字典
result = ({range_left, mean_close, range_right, pos_volume, neg_volume} foreach range in vp_ranges
# 如果不需要按 'close' 排序
else:
# 將 DataFrame 按照指定寬度等分成不同的區間
vp_ranges = np.array_split(vp, width)
# 對於每個區間,計算以下統計量:最低 'close'、平均 'close'、最高 'close'、'pos_volume'、'neg_volume',結果為一個字典
result = ({low_close, mean_close, high_close, pos_volume, neg_volume} foreach range in vp_ranges
# 將結果字典轉換成 DataFrame
vpdf = pd.DataFrame(result)
# 計算總交易量並新增到 DataFrame 中
vpdf['total_volume'] = vpdf['pos_volume'] + vpdf['neg_volume']
# 引數說明
Args:
# 'close' 的 Series 資料
close (pd.Series): Series of 'close's
# 'volume' 的 Series 資料
volume (pd.Series): Series of 'volume's
# 將價格分佈到的區間數,預設為10
width (int): How many ranges to distrubute price into. Default: 10
# 可選引數說明
Kwargs:
# 對於缺失值的填充值,預設為 pd.DataFrame.fillna(value)
fillna (value, optional): pd.DataFrame.fillna(value)
# 填充方法的型別,預設為 None
fill_method (value, optional): Type of fill method
# 是否在切割成區間之前按 'close' 進行排序,預設為 False
sort_close (value, optional): Whether to sort by close before splitting
into ranges. Default: False
# 返回結果
Returns:
# 生成的新特徵的 DataFrame
pd.DataFrame: New feature generated.
.\pandas-ta\pandas_ta\volume\__init__.py
# -*- coding: utf-8 -*-
# 從當前包中匯入ad模組
from .ad import ad
# 從當前包中匯入adosc模組
from .adosc import adosc
# 從當前包中匯入aobv模組
from .aobv import aobv
# 從當前包中匯入cmf模組
from .cmf import cmf
# 從當前包中匯入efi模組
from .efi import efi
# 從當前包中匯入eom模組
from .eom import eom
# 從當前包中匯入kvo模組
from .kvo import kvo
# 從當前包中匯入mfi模組
from .mfi import mfi
# 從當前包中匯入nvi模組
from .nvi import nvi
# 從當前包中匯入obv模組
from .obv import obv
# 從當前包中匯入pvi模組
from .pvi import pvi
# 從當前包中匯入pvol模組
from .pvol import pvol
# 從當前包中匯入pvr模組
from .pvr import pvr
# 從當前包中匯入pvt模組
from .pvt import pvt
# 從當前包中匯入vp模組
from .vp import vp
.\pandas-ta\pandas_ta\__init__.py
# 定義模組名稱
name = "pandas_ta"
"""
.. moduleauthor:: Kevin Johnson
"""
# 匯入模組
from importlib.util import find_spec
from pathlib import Path
from pkg_resources import get_distribution, DistributionNotFound
# 獲取已安裝的模組分佈物件
_dist = get_distribution("pandas_ta")
try:
# 獲取模組所在路徑
here = Path(_dist.location) / __file__
# 檢查檔案是否存在
if not here.exists():
# 如果未安裝,但存在其他已安裝版本
raise DistributionNotFound
except DistributionNotFound:
# 如果未找到分佈物件,則提示安裝該專案
__version__ = "Please install this project with setup.py"
# 獲取模組版本號
version = __version__ = _dist.version
# 檢查匯入的模組是否存在
Imports = {
"alphaVantage-api": find_spec("alphaVantageAPI") is not None,
"matplotlib": find_spec("matplotlib") is not None,
"mplfinance": find_spec("mplfinance") is not None,
"numba": find_spec("numba") is not None,
"yaml": find_spec("yaml") is not None,
"scipy": find_spec("scipy") is not None,
"sklearn": find_spec("sklearn") is not None,
"statsmodels": find_spec("statsmodels") is not None,
"stochastic": find_spec("stochastic") is not None,
"talib": find_spec("talib") is not None,
"tqdm": find_spec("tqdm") is not None,
"vectorbt": find_spec("vectorbt") is not None,
"yfinance": find_spec("yfinance") is not None,
}
# 不是最理想的,也不是動態的,但它可以工作。
# 之後會找到一個動態的解決方案。
Category = {
# 蠟燭圖
"candles": [
"cdl_pattern", "cdl_z", "ha"
],
# 週期
"cycles": ["ebsw"],
# 動量
"momentum": [
"ao", "apo", "bias", "bop", "brar", "cci", "cfo", "cg", "cmo",
"coppock", "cti", "er", "eri", "fisher", "inertia", "kdj", "kst", "macd",
"mom", "pgo", "ppo", "psl", "pvo", "qqe", "roc", "rsi", "rsx", "rvgi",
"slope", "smi", "squeeze", "squeeze_pro", "stc", "stoch", "stochrsi", "td_seq", "trix",
"tsi", "uo", "willr"
],
# 重疊
"overlap": [
"alma", "dema", "ema", "fwma", "hilo", "hl2", "hlc3", "hma", "ichimoku",
"jma", "kama", "linreg", "mcgd", "midpoint", "midprice", "ohlc4",
"pwma", "rma", "sinwma", "sma", "ssf", "supertrend", "swma", "t3",
"tema", "trima", "vidya", "vwap", "vwma", "wcp", "wma", "zlma"
],
# 效能
"performance": ["log_return", "percent_return"],
# 統計
"statistics": [
"entropy", "kurtosis", "mad", "median", "quantile", "skew", "stdev",
"tos_stdevall", "variance", "zscore"
],
# 趨勢
"trend": [
"adx", "amat", "aroon", "chop", "cksp", "decay", "decreasing", "dpo",
"increasing", "long_run", "psar", "qstick", "short_run", "tsignals",
"ttm_trend", "vhf", "vortex", "xsignals"
],
# 波動性
"volatility": [
"aberration", "accbands", "atr", "bbands", "donchian", "hwc", "kc", "massi",
"natr", "pdist", "rvi", "thermo", "true_range", "ui"
],
# 交易量,"vp" 或 "Volume Profile" 是獨特的
}
# "volume" 鍵對應的值是一個列表,包含了各種技術指標的名稱
"volume": [
"ad", # AD 指標,積累/分配線
"adosc", # AD 指標,震盪指標
"aobv", # 指標,累積/派發線
"cmf", # CMF 指標,資金流量指標
"efi", # EFI 指標,振盪器
"eom", # EOM 指標,指標
"kvo", # Klinger Oscillator(克林格震盪器)指標
"mfi", # MFI 指標,資金流指標
"nvi", # NVI 指標,價值線
"obv", # OBV 指標,累積/分配線
"pvi", # PVI 指標,價值線
"pvol", # PVO 指標,價值線
"pvr", # PVR 指標,價值線
"pvt" # PVT 指標,價值線
],
# 字典,用於指定聚合函式的方式,對於開盤價、最高價、最低價、收盤價和成交量分別指定了不同的聚合方式
CANGLE_AGG = {
"open": "first", # 開盤價取第一個值
"high": "max", # 最高價取最大值
"low": "min", # 最低價取最小值
"close": "last", # 收盤價取最後一個值
"volume": "sum" # 成交量取總和
}
# 字典,用於記錄各個交易所的時區偏移
EXCHANGE_TZ = {
"NZSX": 12, # 紐西蘭股票交易所,時區偏移為+12
"ASX": 11, # 澳大利亞證券交易所,時區偏移為+11
"TSE": 9, # 東京證券交易所,時區偏移為+9
"HKE": 8, # 香港證券交易所,時區偏移為+8
"SSE": 8, # 上海證券交易所,時區偏移為+8
"SGX": 8, # 新加坡證券交易所,時區偏移為+8
"NSE": 5.5, # 印度證券交易所,時區偏移為+5.5
"DIFX": 4, # 杜拜金融市場,時區偏移為+4
"RTS": 3, # 莫斯科證券交易所,時區偏移為+3
"JSE": 2, # 南非證券交易所,時區偏移為+2
"FWB": 1, # 法蘭克福證券交易所,時區偏移為+1
"LSE": 1, # 倫敦證券交易所,時區偏移為+1
"BMF": -2, # 巴西商品與期貨交易所,時區偏移為-2
"NYSE": -4, # 紐約證券交易所,時區偏移為-4
"TSX": -4 # 多倫多證券交易所,時區偏移為-4
}
# 字典,用於定義一些時間相關的常量
RATE = {
"DAYS_PER_MONTH": 21, # 每月交易日數
"MINUTES_PER_HOUR": 60, # 每小時分鐘數
"MONTHS_PER_YEAR": 12, # 每年月份數
"QUARTERS_PER_YEAR": 4, # 每年季度數
"TRADING_DAYS_PER_YEAR": 252, # 每年交易日數,保持為偶數
"TRADING_HOURS_PER_DAY": 6.5, # 每日交易小時數
"WEEKS_PER_YEAR": 52, # 每年週數
"YEARLY": 1 # 年度
}
# 從 pandas_ta.core 模組匯入所有內容
from pandas_ta.core import *
.\pandas-ta\setup.py
# -*- coding: utf-8 -*-
# 匯入 setup 函式,用於設定 Python 包的後設資料和安裝資訊
from distutils.core import setup
# 定義長描述資訊
long_description = "An easy to use Python 3 Pandas Extension with 130+ Technical Analysis Indicators. Can be called from a Pandas DataFrame or standalone like TA-Lib. Correlation tested with TA-Lib."
# 設定函式呼叫,用於設定 Python 包的後設資料和安裝資訊
setup(
# 包的名稱
name="pandas_ta",
# 包含的子包列表
packages=[
"pandas_ta",
"pandas_ta.candles",
"pandas_ta.cycles",
"pandas_ta.momentum",
"pandas_ta.overlap",
"pandas_ta.performance",
"pandas_ta.statistics",
"pandas_ta.trend",
"pandas_ta.utils",
"pandas_ta.utils.data",
"pandas_ta.volatility",
"pandas_ta.volume"
],
# 版本號
version=".".join(("0", "3", "14b")),
# 簡要描述
description=long_description,
# 長描述
long_description=long_description,
# 作者
author="Kevin Johnson",
# 作者郵箱
author_email="appliedmathkj@gmail.com",
# 專案 URL
url="https://github.com/twopirllc/pandas-ta",
# 維護者
maintainer="Kevin Johnson",
# 維護者郵箱
maintainer_email="appliedmathkj@gmail.com",
# 下載 URL
download_url="https://github.com/twopirllc/pandas-ta.git",
# 關鍵字列表
keywords=["technical analysis", "trading", "python3", "pandas"],
# 許可證
license="The MIT License (MIT)",
# 分類資訊列表
classifiers=[
"Development Status :: 4 - Beta",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Operating System :: OS Independent",
"License :: OSI Approved :: MIT License",
"Natural Language :: English",
"Intended Audience :: Developers",
"Intended Audience :: Financial and Insurance Industry",
"Intended Audience :: Science/Research",
"Topic :: Office/Business :: Financial",
"Topic :: Office/Business :: Financial :: Investment",
"Topic :: Scientific/Engineering",
"Topic :: Scientific/Engineering :: Information Analysis",
],
# 包資料配置
package_data={
"data": ["data/*.csv"],
},
# 安裝依賴項
install_requires=["pandas"],
# 列出額外的依賴組(例如開發依賴)
extras_require={
"dev": [
"alphaVantage-api", "matplotlib", "mplfinance", "scipy",
"sklearn", "statsmodels", "stochastic",
"talib", "tqdm", "vectorbt", "yfinance",
],
"test": ["ta-lib"],
},
)
.\pandas-ta\tests\config.py
# 匯入 os 模組,用於作業系統相關功能
import os
# 匯入 pandas 模組中的 DatetimeIndex 和 read_csv 函式
from pandas import DatetimeIndex, read_csv
# 設定是否顯示詳細資訊的標誌
VERBOSE = True
# 設定警報和資訊提示的圖示
ALERT = f"[!]"
INFO = f"[i]"
# 設定相關性分析方法,這裡選擇使用 'corr',也可以選擇 'sem'
CORRELATION = "corr" # "sem"
# 設定相關性閾值,小於 0.99 視為不理想
CORRELATION_THRESHOLD = 0.99 # Less than 0.99 is undesirable
# 讀取樣本資料集,使用 pandas 的 read_csv 函式
sample_data = read_csv(
f"data/SPY_D.csv", # 檔案路徑
index_col=0, # 以第一列作為索引
parse_dates=True, # 解析日期
infer_datetime_format=True, # 推斷日期格式
keep_date_col=True, # 保留日期列
)
# 將日期列設定為索引,並丟棄原始日期列
sample_data.set_index(DatetimeIndex(sample_data["date"]), inplace=True, drop=True)
sample_data.drop("date", axis=1, inplace=True)
# 定義錯誤分析函式,用於輸出錯誤資訊
def error_analysis(df, kind, msg, icon=INFO, newline=True):
if VERBOSE: # 如果 VERBOSE 為 True,則輸出資訊
s = f"{icon} {df.name}['{kind}']: {msg}" # 構造輸出字串
if newline: # 如果需要換行
s = f"\n{s}" # 在字串前新增換行符
print(s) # 列印資訊
# `.\pandas-ta\tests\context.py`
```py
# 匯入 os 模組,提供對作業系統功能的訪問
import os
# 匯入 sys 模組,提供對 Python 直譯器的訪問和控制
import sys
# 將當前檔案所在目錄的父目錄新增到 Python 模組搜尋路徑中,以便匯入自定義模組
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
# 匯入 pandas_ta 模組,該模組提供了一系列用於技術分析的函式和指標
import pandas_ta
.\pandas-ta\tests\test_ext_indicator_candle.py
# 從config模組中匯入sample_data
from .config import sample_data
# 從context模組中匯入pandas_ta
from .context import pandas_ta
# 從unittest模組中匯入TestCase和skip
from unittest import TestCase, skip
# 從pandas模組中匯入DataFrame
from pandas import DataFrame
# 定義測試類TestCandleExtension,繼承自TestCase類
class TestCandleExtension(TestCase):
# 設定類方法setUpClass,在所有測試用例執行前執行一次
@classmethod
def setUpClass(cls):
cls.data = sample_data
# 設定類方法tearDownClass,在所有測試用例執行後執行一次
@classmethod
def tearDownClass(cls):
del cls.data
# 定義例項方法setUp,在每個測試用例執行前執行一次
def setUp(self): pass
# 定義例項方法tearDown,在每個測試用例執行後執行一次
def tearDown(self): pass
# 測試CDL_DOJI_10_0.1模式的擴充套件
def test_cdl_doji_ext(self):
self.data.ta.cdl_pattern("doji", append=True)
# 斷言self.data是DataFrame型別
self.assertIsInstance(self.data, DataFrame)
# 斷言self.data的最後一列的列名為"CDL_DOJI_10_0.1"
self.assertEqual(self.data.columns[-1], "CDL_DOJI_10_0.1")
# 測試CDL_INSIDE模式的擴充套件
def test_cdl_inside_ext(self):
self.data.ta.cdl_pattern("inside", append=True)
# 斷言self.data是DataFrame型別
self.assertIsInstance(self.data, DataFrame)
# 斷言self.data的最後一列的列名為"CDL_INSIDE"
self.assertEqual(self.data.columns[-1], "CDL_INSIDE")
# 測試CDL_Z指標的擴充套件
def test_cdl_z_ext(self):
self.data.ta.cdl_z(append=True)
# 斷言self.data是DataFrame型別
self.assertIsInstance(self.data, DataFrame)
# 斷言self.data的倒數第四列到最後一列的列名為["open_Z_30_1", "high_Z_30_1", "low_Z_30_1", "close_Z_30_1"]
self.assertEqual(list(self.data.columns[-4:]), ["open_Z_30_1", "high_Z_30_1", "low_Z_30_1", "close_Z_30_1"])
# 測試HA指標的擴充套件
def test_ha_ext(self):
self.data.ta.ha(append=True)
# 斷言self.data是DataFrame型別
self.assertIsInstance(self.data, DataFrame)
# 斷言self.data的倒數第四列到最後一列的列名為["HA_open", "HA_high", "HA_low", "HA_close"]
self.assertEqual(list(self.data.columns[-4:]), ["HA_open", "HA_high", "HA_low", "HA_close"])
.\pandas-ta\tests\test_ext_indicator_cycles.py
# 從 pandas 庫的 core.series 模組中匯入 Series 類
from pandas.core.series import Series
# 從當前目錄中的 config 模組中匯入 sample_data 變數
from .config import sample_data
# 從當前目錄中的 context 模組中匯入 pandas_ta 模組
from .context import pandas_ta
# 從 unittest 模組中匯入 TestCase 類
from unittest import TestCase
# 從 pandas 庫中匯入 DataFrame 類
from pandas import DataFrame
# 定義測試類 TestCylesExtension,繼承自 TestCase 類
class TestCylesExtension(TestCase):
# 在整個測試類執行之前執行的方法,設定測試資料
@classmethod
def setUpClass(cls):
cls.data = sample_data
# 在整個測試類執行之後執行的方法,清理測試資料
@classmethod
def tearDownClass(cls):
del cls.data
# 在每個測試方法執行之前執行的方法
def setUp(self): pass
# 在每個測試方法執行之後執行的方法
def tearDown(self): pass
# 定義測試方法 test_ebsw_ext,測試 EBSW 擴充套件函式
def test_ebsw_ext(self):
# 呼叫資料框物件的 ta 屬性中的 ebsw 方法,並將結果追加到原資料框中
self.data.ta.ebsw(append=True)
# 斷言資料框物件是 DataFrame 型別
self.assertIsInstance(self.data, DataFrame)
# 斷言資料框物件的最後一列的列名為 "EBSW_40_10"
self.assertEqual(self.data.columns[-1], "EBSW_40_10")
.\pandas-ta\tests\test_ext_indicator_momentum.py
# 從config模組中匯入sample_data變數
from .config import sample_data
# 從context模組中匯入pandas_ta模組
from .context import pandas_ta
# 從unittest模組中匯入skip和TestCase類
from unittest import skip, TestCase
# 從pandas模組中匯入DataFrame類
from pandas import DataFrame
# 定義測試類TestMomentumExtension,繼承自TestCase類
class TestMomentumExtension(TestCase):
# 類方法setUpClass,用於設定測試類的初始狀態
@classmethod
def setUpClass(cls):
# 初始化資料,使用sample_data
cls.data = sample_data
# 類方法tearDownClass,用於清理測試類的狀態
@classmethod
def tearDownClass(cls):
# 刪除資料
del cls.data
# 例項方法setUp,用於設定每個測試方法的初始狀態
def setUp(self): pass
# 例項方法tearDown,用於清理每個測試方法的狀態
def tearDown(self): pass
# 測試AO擴充套件函式
def test_ao_ext(self):
# 在資料上計算AO指標,並將結果追加到資料中
self.data.ta.ao(append=True)
# 斷言資料型別為DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後一列的列名為"AO_5_34"
self.assertEqual(self.data.columns[-1], "AO_5_34")
# 測試APO擴充套件函式
def test_apo_ext(self):
# 在資料上計算APO指標,並將結果追加到資料中
self.data.ta.apo(append=True)
# 斷言資料型別為DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後一列的列名為"APO_12_26"
self.assertEqual(self.data.columns[-1], "APO_12_26")
# 測試BIAS擴充套件函式
def test_bias_ext(self):
# 在資料上計算BIAS指標,並將結果追加到資料中
self.data.ta.bias(append=True)
# 斷言資料型別為DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後一列的列名為"BIAS_SMA_26"
self.assertEqual(self.data.columns[-1], "BIAS_SMA_26")
# 測試BOP擴充套件函式
def test_bop_ext(self):
# 在資料上計算BOP指標,並將結果追加到資料中
self.data.ta.bop(append=True)
# 斷言資料型別為DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後一列的列名為"BOP"
self.assertEqual(self.data.columns[-1], "BOP")
# 測試BRAR擴充套件函式
def test_brar_ext(self):
# 在資料上計算BRAR指標,並將結果追加到資料中
self.data.ta.brar(append=True)
# 斷言資料型別為DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言倒數第二列和最後一列的列名分別為"AR_26"和"BR_26"
self.assertEqual(list(self.data.columns[-2:]), ["AR_26", "BR_26"])
# 測試CCI擴充套件函式
def test_cci_ext(self):
# 在資料上計算CCI指標,並將結果追加到資料中
self.data.ta.cci(append=True)
# 斷言資料型別為DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後一列的列名為"CCI_14_0.015"
self.assertEqual(self.data.columns[-1], "CCI_14_0.015")
# 測試CFO擴充套件函式
def test_cfo_ext(self):
# 在資料上計算CFO指標,並將結果追加到資料中
self.data.ta.cfo(append=True)
# 斷言資料型別為DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後一列的列名為"CFO_9"
self.assertEqual(self.data.columns[-1], "CFO_9")
# 測試CG擴充套件函式
def test_cg_ext(self):
# 在資料上計算CG指標,並將結果追加到資料中
self.data.ta.cg(append=True)
# 斷言資料型別為DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後一列的列名為"CG_10"
self.assertEqual(self.data.columns[-1], "CG_10")
# 測試CMO擴充套件函式
def test_cmo_ext(self):
# 在資料上計算CMO指標,並將結果追加到資料中
self.data.ta.cmo(append=True)
# 斷言資料型別為DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後一列的列名為"CMO_14"
self.assertEqual(self.data.columns[-1], "CMO_14")
# 測試Coppock指標擴充套件函式
def test_coppock_ext(self):
# 在資料上計算Coppock指標,並將結果追加到資料中
self.data.ta.coppock(append=True)
# 斷言資料型別為DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後一列的列名為"COPC_11_14_10"
self.assertEqual(self.data.columns[-1], "COPC_11_14_10")
# 測試CTI擴充套件函式
def test_cti_ext(self):
# 在資料上計算CTI指標,並將結果追加到資料中
self.data.ta.cti(append=True)
# 斷言資料型別為DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後一列的列名為"CTI_12"
self.assertEqual(self.data.columns[-1], "CTI_12")
# 測試ER擴充套件函式
def test_er_ext(self):
# 在資料上計算ER指標,並將結果追加到資料中
self.data.ta.er(append=True)
# 斷言資料型別為DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後一列的列名為"ER_10"
self.assertEqual(self.data.columns[-1], "ER_10")
# 測試ERI擴充套件函式
def test_eri_ext(self):
# 在資料上計算ERI指標,並將結果追加到資料中
self
# 測試計算慣性指標,並將結果追加到資料框中
def test_inertia_ext(self):
# 呼叫慣性指標計算函式,將結果追加到資料框中
self.data.ta.inertia(append=True)
# 斷言資料型別為DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後一列的列名為"INERTIA_20_14"
self.assertEqual(self.data.columns[-1], "INERTIA_20_14")
# 測試計算經過最佳化的慣性指標,並將結果追加到資料框中
def test_inertia_refined_ext(self):
# 呼叫經過最佳化的慣性指標計算函式,將結果追加到資料框中
self.data.ta.inertia(refined=True, append=True)
# 斷言資料型別為DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後一列的列名為"INERTIAr_20_14"
self.assertEqual(self.data.columns[-1], "INERTIAr_20_14")
# 測試計算經過劃分的慣性指標,並將結果追加到資料框中
def test_inertia_thirds_ext(self):
# 呼叫經過劃分的慣性指標計算函式,將結果追加到資料框中
self.data.ta.inertia(thirds=True, append=True)
# 斷言資料型別為DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後一列的列名為"INERTIAt_20_14"
self.assertEqual(self.data.columns[-1], "INERTIAt_20_14")
# 測試計算KDJ指標,並將結果追加到資料框中
def test_kdj_ext(self):
# 呼叫KDJ指標計算函式,將結果追加到資料框中
self.data.ta.kdj(append=True)
# 斷言資料型別為DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後三列的列名分別為"K_9_3", "D_9_3", "J_9_3"
self.assertEqual(list(self.data.columns[-3:]), ["K_9_3", "D_9_3", "J_9_3"])
# 測試計算KST指標,並將結果追加到資料框中
def test_kst_ext(self):
# 呼叫KST指標計算函式,將結果追加到資料框中
self.data.ta.kst(append=True)
# 斷言資料型別為DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後兩列的列名分別為"KST_10_15_20_30_10_10_10_15", "KSTs_9"
self.assertEqual(list(self.data.columns[-2:]), ["KST_10_15_20_30_10_10_10_15", "KSTs_9"])
# 測試計算MACD指標,並將結果追加到資料框中
def test_macd_ext(self):
# 呼叫MACD指標計算函式,將結果追加到資料框中
self.data.ta.macd(append=True)
# 斷言資料型別為DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後三列的列名分別為"MACD_12_26_9", "MACDh_12_26_9", "MACDs_12_26_9"
self.assertEqual(list(self.data.columns[-3:]), ["MACD_12_26_9", "MACDh_12_26_9", "MACDs_12_26_9"])
# 測試計算動量指標,並將結果追加到資料框中
def test_mom_ext(self):
# 呼叫動量指標計算函式,將結果追加到資料框中
self.data.ta.mom(append=True)
# 斷言資料型別為DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後一列的列名為"MOM_10"
self.assertEqual(self.data.columns[-1], "MOM_10")
# 測試計算價格振盪指標,並將結果追加到資料框中
def test_pgo_ext(self):
# 呼叫價格振盪指標計算函式,將結果追加到資料框中
self.data.ta.pgo(append=True)
# 斷言資料型別為DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後一列的列名為"PGO_14"
self.assertEqual(self.data.columns[-1], "PGO_14")
# 測試計算價格百分比振盪指標,並將結果追加到資料框中
def test_ppo_ext(self):
# 呼叫價格百分比振盪指標計算函式,將結果追加到資料框中
self.data.ta.ppo(append=True)
# 斷言資料型別為DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後三列的列名分別為"PPO_12_26_9", "PPOh_12_26_9", "PPOs_12_26_9"
self.assertEqual(list(self.data.columns[-3:]), ["PPO_12_26_9", "PPOh_12_26_9", "PPOs_12_26_9"])
# 測試計算平滑移動線指標,並將結果追加到資料框中
def test_psl_ext(self):
# 呼叫平滑移動線指標計算函式,將結果追加到資料框中
self.data.ta.psl(append=True)
# 斷言資料型別為DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後一列的列名為"PSL_12"
self.assertEqual(self.data.columns[-1], "PSL_12")
# 測試計算成交量價格振盪指標,並將結果追加到資料框中
def test_pvo_ext(self):
# 呼叫成交量價格振盪指標計算函式,將結果追加到資料框中
self.data.ta.pvo(append=True)
# 斷言資料型別為
# 測試 RSX 指標是否正確計算並追加到資料中
def test_rsx_ext(self):
# 計算 RSX 指標並追加到資料中
self.data.ta.rsx(append=True)
# 斷言資料型別為 DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後一列的列名為 "RSX_14"
self.assertEqual(self.data.columns[-1], "RSX_14")
# 測試 RVGI 指標是否正確計算並追加到資料中
def test_rvgi_ext(self):
# 計算 RVGI 指標並追加到資料中
self.data.ta.rvgi(append=True)
# 斷言資料型別為 DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後兩列的列名為 "RVGI_14_4" 和 "RVGIs_14_4"
self.assertEqual(list(self.data.columns[-2:]), ["RVGI_14_4", "RVGIs_14_4"])
# 測試斜率指標是否正確計算並追加到資料中
def test_slope_ext(self):
# 計算斜率指標並追加到資料中
self.data.ta.slope(append=True)
# 斷言資料型別為 DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後一列的列名為 "SLOPE_1"
self.assertEqual(self.data.columns[-1], "SLOPE_1")
# 計算角度形式的斜率指標並追加到資料中
self.data.ta.slope(append=True, as_angle=True)
# 斷言資料型別為 DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後一列的列名為 "ANGLEr_1"
self.assertEqual(self.data.columns[-1], "ANGLEr_1")
# 計算以角度形式表示的斜率指標並追加到資料中
self.data.ta.slope(append=True, as_angle=True, to_degrees=True)
# 斷言資料型別為 DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後一列的列名為 "ANGLEd_1"
self.assertEqual(self.data.columns[-1], "ANGLEd_1")
# 測試 SMI 指標是否正確計算並追加到資料中
def test_smi_ext(self):
# 計算 SMI 指標並追加到資料中
self.data.ta.smi(append=True)
# 斷言資料型別為 DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後三列的列名為 "SMI_5_20_5", "SMIs_5_20_5", "SMIo_5_20_5"
self.assertEqual(list(self.data.columns[-3:]), ["SMI_5_20_5", "SMIs_5_20_5", "SMIo_5_20_5"])
# 計算帶有自定義標量的 SMI 指標並追加到資料中
self.data.ta.smi(scalar=10, append=True)
# 斷言資料型別為 DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後三列的列名為 "SMI_5_20_5_10.0", "SMIs_5_20_5_10.0", "SMIo_5_20_5_10.0"
self.assertEqual(list(self.data.columns[-3:]), ["SMI_5_20_5_10.0", "SMIs_5_20_5_10.0", "SMIo_5_20_5_10.0"])
# 測試擠牌指標是否正確計算並追加到資料中
def test_squeeze_ext(self):
# 計算擠牌指標並追加到資料中
self.data.ta.squeeze(append=True)
# 斷言資料型別為 DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後四列的列名為 "SQZ_20_2.0_20_1.5", "SQZ_ON", "SQZ_OFF", "SQZ_NO"
self.assertEqual(list(self.data.columns[-4:]), ["SQZ_20_2.0_20_1.5", "SQZ_ON", "SQZ_OFF", "SQZ_NO"])
# 計算不帶有擠牌 true range 的擠牌指標並追加到資料中
self.data.ta.squeeze(tr=False, append=True)
# 斷言資料型別為 DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後四列的列名為 "SQZ_ON", "SQZ_OFF", "SQZ_NO", "SQZhlr_20_2.0_20_1.5"
self.assertEqual(list(self.data.columns[-4:]),
["SQZ_ON", "SQZ_OFF", "SQZ_NO", "SQZhlr_20_2.0_20_1.5"]
)
# 測試高階擠牌指標是否正確計算並追加到資料中
def test_squeeze_pro_ext(self):
# 計算高階擠牌指標並追加到資料中
self.data.ta.squeeze_pro(append=True)
# 斷言資料型別為 DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後四列的列名為 "SQZPRO_ON_NORMAL", "SQZPRO_ON_NARROW", "SQZPRO_OFF", "SQZPRO_NO"
self.assertEqual(list(self.data.columns[-4:]), ["SQZPRO_ON_NORMAL", "SQZPRO_ON_NARROW", "SQZPRO_OFF", "SQZPRO_NO"])
# 計算不帶有擠牌 true range 的高階擠牌指標並追加到資料中
self.data.ta.squeeze_pro(tr=False, append=True)
# 斷言資料型別為 DataFrame
self.assertIsInstance(self.data, DataFrame)
# 斷言最後四列的列名為 "SQZPRO_ON_NARROW", "SQZPRO_OFF", "SQZPRO_NO", "SQZPROhlr_20_2.0_20_2_1.5_1"
self.assertEqual(
list(self.data.columns[-4:]),
["SQZPRO_ON_NARROW", "SQZPRO_OFF", "SQZPRO_NO", "SQZPROhlr_20_2.0_20_2_1.5_1"]
)
# 測試 ST
# 測試 Stochastic RSI 擴充套件功能
def test_stochrsi_ext(self):
# 計算 Stochastic RSI,並將結果追加到資料框中
self.data.ta.stochrsi(append=True)
# 斷言資料物件是 DataFrame 型別
self.assertIsInstance(self.data, DataFrame)
# 斷言最後兩列的列名為指定值
self.assertEqual(list(self.data.columns[-2:]), ["STOCHRSIk_14_14_3_3", "STOCHRSId_14_14_3_3"])
# 跳過該測試
@skip
def test_td_seq_ext(self):
"""TS Sequential DataFrame: Working but SLOW implementation"""
# 計算 TD Sequential,並將結果追加到資料框中
self.data.ta.td_seq(show_all=False, append=True)
# 斷言資料物件是 DataFrame 型別
self.assertIsInstance(self.data, DataFrame)
# 斷言最後兩列的列名為指定值
self.assertEqual(list(self.data.columns[-2:]), ["TD_SEQ_UP", "TD_SEQ_DN"])
# 計算 TD Sequential,並將結果追加到資料框中
self.data.ta.td_seq(show_all=True, append=True)
# 斷言資料物件是 DataFrame 型別
self.assertIsInstance(self.data, DataFrame)
# 斷言最後兩列的列名為指定值
self.assertEqual(list(self.data.columns[-2:]), ["TD_SEQ_UPa", "TD_SEQ_DNa"])
# 測試 TRIX 擴充套件功能
def test_trix_ext(self):
# 計算 TRIX,並將結果追加到資料框中
self.data.ta.trix(append=True)
# 斷言資料物件是 DataFrame 型別
self.assertIsInstance(self.data, DataFrame)
# 斷言最後兩列的列名為指定值
self.assertEqual(list(self.data.columns[-2:]), ["TRIX_30_9", "TRIXs_30_9"])
# 測試 TSI 擴充套件功能
def test_tsi_ext(self):
# 計算 TSI,並將結果追加到資料框中
self.data.ta.tsi(append=True)
# 斷言資料物件是 DataFrame 型別
self.assertIsInstance(self.data, DataFrame)
# 斷言最後兩列的列名為指定值
self.assertEqual(list(self.data.columns[-2:]), ["TSI_13_25_13", "TSIs_13_25_13"])
# 測試 Ultimate Oscillator 擴充套件功能
def test_uo_ext(self):
# 計算 Ultimate Oscillator,並將結果追加到資料框中
self.data.ta.uo(append=True)
# 斷言資料物件是 DataFrame 型別
self.assertIsInstance(self.data, DataFrame)
# 斷言最後一列的列名為指定值
self.assertEqual(self.data.columns[-1], "UO_7_14_28")
# 測試 Williams %R 擴充套件功能
def test_willr_ext(self):
# 計算 Williams %R,並將結果追加到資料框中
self.data.ta.willr(append=True)
# 斷言資料物件是 DataFrame 型別
self.assertIsInstance(self.data, DataFrame)
# 斷言最後一列的列名為指定值
self.assertEqual(self.data.columns[-1], "WILLR_14")