.\pandas-ta\pandas_ta\volume\adosc.py
# -*- coding: utf-8 -*-
# 导入 ad 模块
from .ad import ad
# 从 pandas_ta 库中导入 Imports 模块
from pandas_ta import Imports
# 从 pandas_ta.overlap 模块中导入 ema 函数
from pandas_ta.overlap import ema
# 从 pandas_ta.utils 模块中导入 get_offset 和 verify_series 函数
from pandas_ta.utils import get_offset, verify_series
# 定义 adosc 函数,用于计算累积/分布振荡器指标
def adosc(high, low, close, volume, open_=None, fast=None, slow=None, talib=None, offset=None, **kwargs):
"""Indicator: Accumulation/Distribution Oscillator"""
# 验证参数有效性
# 如果 fast 参数存在且大于 0,则将其转换为整数类型,否则设为默认值 3
fast = int(fast) if fast and fast > 0 else 3
# 如果 slow 参数存在且大于 0,则将其转换为整数类型,否则设为默认值 10
slow = int(slow) if slow and slow > 0 else 10
# 计算 _length,即 fast 和 slow 中的较大值
_length = max(fast, slow)
# 验证 high、low、close、volume 系列数据的长度,使其与 _length 相同
high = verify_series(high, _length)
low = verify_series(low, _length)
close = verify_series(close, _length)
volume = verify_series(volume, _length)
# 获取偏移量,根据 offset 参数
offset = get_offset(offset)
# 如果 kwargs 中存在 "length" 键,则将其移除
if "length" in kwargs: kwargs.pop("length")
# 如果 talib 参数为布尔类型且为真,则将 mode_tal 设为 True,否则设为 False
mode_tal = bool(talib) if isinstance(talib, bool) else True
# 如果 high、low、close、volume 中存在空值,则返回空值
if high is None or low is None or close is None or volume is None: return
# 计算结果
if Imports["talib"] and mode_tal:
# 如果导入了 TA Lib 并且 mode_tal 为 True,则使用 TA Lib 计算 adosc
from talib import ADOSC
adosc = ADOSC(high, low, close, volume, fast, slow)
else:
# 否则,使用自定义的 ad 函数计算 ad_,然后分别计算其快速和慢速移动平均线
ad_ = ad(high=high, low=low, close=close, volume=volume, open_=open_)
fast_ad = ema(close=ad_, length=fast, **kwargs)
slow_ad = ema(close=ad_, length=slow, **kwargs)
adosc = fast_ad - slow_ad
# 根据偏移量对结果进行偏移
if offset != 0:
adosc = adosc.shift(offset)
# 处理填充值
if "fillna" in kwargs:
adosc.fillna(kwargs["fillna"], inplace=True)
if "fill_method" in kwargs:
adosc.fillna(method=kwargs["fill_method"], inplace=True)
# 设置指标名称和类别
adosc.name = f"ADOSC_{fast}_{slow}"
adosc.category = "volume"
# 返回计算结果
return adosc
# 设置 adosc 函数的文档字符串
adosc.__doc__ = \
"""Accumulation/Distribution Oscillator or Chaikin Oscillator
Accumulation/Distribution Oscillator indicator utilizes
Accumulation/Distribution and treats it similarily to MACD
or APO.
Sources:
https://www.investopedia.com/articles/active-trading/031914/understanding-chaikin-oscillator.asp
Calculation:
Default Inputs:
fast=12, slow=26
AD = Accum/Dist
ad = AD(high, low, close, open)
fast_ad = EMA(ad, fast)
slow_ad = EMA(ad, slow)
ADOSC = fast_ad - slow_ad
Args:
high (pd.Series): Series of 'high's
low (pd.Series): Series of 'low's
close (pd.Series): Series of 'close's
open (pd.Series): Series of 'open's
volume (pd.Series): Series of 'volume's
fast (int): The short period. Default: 12
slow (int): The long period. Default: 26
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\volume\aobv.py
# -*- coding: utf-8 -*-
# 从 pandas 库中导入 DataFrame 类
from pandas import DataFrame
# 从当前目录下的 obv 模块中导入 obv 函数
from .obv import obv
# 从 pandas_ta.overlap 模块中导入 ma 函数
from pandas_ta.overlap import ma
# 从 pandas_ta.trend 模块中导入 long_run 和 short_run 函数
from pandas_ta.trend import long_run, short_run
# 从 pandas_ta.utils 模块中导入 get_offset 和 verify_series 函数
from pandas_ta.utils import get_offset, verify_series
# 定义名为 aobv 的函数,计算 Archer On Balance Volume (AOBV) 指标
def aobv(close, volume, fast=None, slow=None, max_lookback=None, min_lookback=None, mamode=None, offset=None, **kwargs):
"""Indicator: Archer On Balance Volume (AOBV)"""
# 验证参数
# 如果 fast 存在且大于 0,则将其转换为整数,否则设为默认值 4
fast = int(fast) if fast and fast > 0 else 4
# 如果 slow 存在且大于 0,则将其转换为整数,否则设为默认值 12
slow = int(slow) if slow and slow > 0 else 12
# 如果 max_lookback 存在且大于 0,则将其转换为整数,否则设为默认值 2
max_lookback = int(max_lookback) if max_lookback and max_lookback > 0 else 2
# 如果 min_lookback 存在且大于 0,则将其转换为整数,否则设为默认值 2
min_lookback = int(min_lookback) if min_lookback and min_lookback > 0 else 2
# 如果 slow 小于 fast,则交换它们的值
if slow < fast:
fast, slow = slow, fast
# 如果 mamode 不是字符串类型,则设为默认值 "ema"
mamode = mamode if isinstance(mamode, str) else "ema"
# 计算需要处理的数据长度
_length = max(fast, slow, max_lookback, min_lookback)
# 验证 close 和 volume 是否为有效的数据序列,长度为 _length
close = verify_series(close, _length)
volume = verify_series(volume, _length)
# 获取偏移量
offset = get_offset(offset)
# 如果 kwargs 中存在 "length" 键,则将其移除
if "length" in kwargs: kwargs.pop("length")
# 从 kwargs 中获取 "run_length" 键的值,如果不存在则设为默认值 2
run_length = kwargs.pop("run_length", 2)
# 如果 close 或 volume 为 None,则返回空
if close is None or volume is None: return
# 计算结果
# 计算 On Balance Volume(OBV)
obv_ = obv(close=close, volume=volume, **kwargs)
# 计算 OBV 的快速移动平均线
maf = ma(mamode, obv_, length=fast, **kwargs)
# 计算 OBV 的慢速移动平均线
mas = ma(mamode, obv_, length=slow, **kwargs)
# 当快速和慢速移动平均线长度为指定长度时
obv_long = long_run(maf, mas, length=run_length)
obv_short = short_run(maf, mas, length=run_length)
# 考虑偏移量
if offset != 0:
obv_ = obv_.shift(offset)
maf = maf.shift(offset)
mas = mas.shift(offset)
obv_long = obv_long.shift(offset)
obv_short = obv_short.shift(offset)
# 处理填充值
if "fillna" in kwargs:
obv_.fillna(kwargs["fillna"], inplace=True)
maf.fillna(kwargs["fillna"], inplace=True)
mas.fillna(kwargs["fillna"], inplace=True)
obv_long.fillna(kwargs["fillna"], inplace=True)
obv_short.fillna(kwargs["fillna"], inplace=True)
if "fill_method" in kwargs:
obv_.fillna(method=kwargs["fill_method"], inplace=True)
maf.fillna(method=kwargs["fill_method"], inplace=True)
mas.fillna(method=kwargs["fill_method"], inplace=True)
obv_long.fillna(method=kwargs["fill_method"], inplace=True)
obv_short.fillna(method=kwargs["fill_method"], inplace=True)
# 准备返回的 DataFrame
_mode = mamode.lower()[0] if len(mamode) else ""
data = {
obv_.name: obv_,
f"OBV_min_{min_lookback}": obv_.rolling(min_lookback).min(),
f"OBV_max_{max_lookback}": obv_.rolling(max_lookback).max(),
f"OBV{_mode}_{fast}": maf,
f"OBV{_mode}_{slow}": mas,
f"AOBV_LR_{run_length}": obv_long,
f"AOBV_SR_{run_length}": obv_short,
}
# 创建 DataFrame
aobvdf = DataFrame(data)
# 给 DataFrame 命名并分类
aobvdf.name = f"AOBV{_mode}_{fast}_{slow}_{min_lookback}_{max_lookback}_{run_length}"
aobvdf.category = "volume"
return aobvdf
.\pandas-ta\pandas_ta\volume\cmf.py
# -*- coding: utf-8 -*-
# 从 pandas_ta.utils 导入一些必要的函数
from pandas_ta.utils import get_offset, non_zero_range, verify_series
# 定义 CMF 函数,计算 Chaikin Money Flow 指标
def cmf(high, low, close, volume, open_=None, length=None, offset=None, **kwargs):
"""Indicator: Chaikin Money Flow (CMF)"""
# 验证参数
# 确保 length 是整数且大于 0,若未指定则默认为 20
length = int(length) if length and length > 0 else 20
# 最小期数为 length 或者 kwargs 中 min_periods 的值,若未指定则为 length
min_periods = int(kwargs["min_periods"]) if "min_periods" in kwargs and kwargs["min_periods"] is not None else length
# 取 length 和 min_periods 中的较大值作为真正的 length
_length = max(length, min_periods)
# 确保传入的数据是合法的 Series 类型,长度为 _length
high = verify_series(high, _length)
low = verify_series(low, _length)
close = verify_series(close, _length)
volume = verify_series(volume, _length)
# 获取偏移量
offset = get_offset(offset)
# 若传入的数据有缺失,则返回 None
if high is None or low is None or close is None or volume is None: return
# 计算结果
if open_ is not None:
# 若存在开盘价数据,则使用开盘价计算 AD
open_ = verify_series(open_)
ad = non_zero_range(close, open_) # 使用开盘价计算 AD
else:
# 若不存在开盘价数据,则使用高、低、收盘价计算 AD
ad = 2 * close - (high + low) # 使用高、低、收盘价计算 AD
# 计算 CMF
ad *= volume / non_zero_range(high, low)
cmf = ad.rolling(length, min_periods=min_periods).sum()
cmf /= volume.rolling(length, min_periods=min_periods).sum()
# 偏移结果
if offset != 0:
cmf = cmf.shift(offset)
# 处理填充值
if "fillna" in kwargs:
cmf.fillna(kwargs["fillna"], inplace=True)
if "fill_method" in kwargs:
cmf.fillna(method=kwargs["fill_method"], inplace=True)
# 命名并分类
cmf.name = f"CMF_{length}"
cmf.category = "volume"
# 返回结果
return cmf
# 设置 CMF 函数的文档字符串
cmf.__doc__ = \
"""Chaikin Money Flow (CMF)
Chailin Money Flow measures the amount of money flow volume over a specific
period in conjunction with Accumulation/Distribution.
Sources:
https://www.tradingview.com/wiki/Chaikin_Money_Flow_(CMF)
https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:chaikin_money_flow_cmf
Calculation:
Default Inputs:
length=20
if 'open':
ad = close - open
else:
ad = 2 * close - high - low
hl_range = high - low
ad = ad * volume / hl_range
CMF = SUM(ad, length) / SUM(volume, length)
Args:
high (pd.Series): Series of 'high's
low (pd.Series): Series of 'low's
close (pd.Series): Series of 'close's
volume (pd.Series): Series of 'volume's
open_ (pd.Series): Series of 'open's. Default: None
length (int): The short period. Default: 20
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\efi.py
# -*- coding: utf-8 -*-
# 从 pandas_ta.overlap 模块导入 ma 函数
from pandas_ta.overlap import ma
# 从 pandas_ta.utils 模块导入 get_drift、get_offset、verify_series 函数
from pandas_ta.utils import get_drift, get_offset, verify_series
# 定义 EFI 函数,计算 Elder's Force Index (EFI)
def efi(close, volume, length=None, mamode=None, drift=None, offset=None, **kwargs):
"""Indicator: Elder's Force Index (EFI)"""
# 验证参数
# 将 length 转换为整数,如果未提供或小于等于 0,则设为默认值 13
length = int(length) if length and length > 0 else 13
# 如果未提供 mamode 或不是字符串,则设为默认值 'ema'
mamode = mamode if isinstance(mamode, str) else "ema"
# 验证 close 和 volume 是否为有效序列,长度为 length
close = verify_series(close, length)
volume = verify_series(volume, length)
# 获取漂移和偏移量
drift = get_drift(drift)
offset = get_offset(offset)
# 如果 close 或 volume 为空,则返回空
if close is None or volume is None: return
# 计算结果
# 计算价格和成交量的差值,再乘以漂移量
pv_diff = close.diff(drift) * volume
# 计算 EFI,使用指定的移动平均模式和长度
efi = ma(mamode, pv_diff, length=length)
# 偏移
# 如果偏移量不为零,则对 EFI 进行偏移
if offset != 0:
efi = efi.shift(offset)
# 处理填充
# 如果 kwargs 中包含 'fillna',则用指定值填充 EFI 的缺失值
if "fillna" in kwargs:
efi.fillna(kwargs["fillna"], inplace=True)
# 如果 kwargs 中包含 'fill_method',则使用指定的填充方法填充 EFI 的缺失值
if "fill_method" in kwargs:
efi.fillna(method=kwargs["fill_method"], inplace=True)
# 设置名称和分类
# 将 EFI 的名称设为字符串模板 "EFI_{length}"
efi.name = f"EFI_{length}"
# 将 EFI 的分类设为 "volume"
efi.category = "volume"
# 返回 EFI
return efi
# 设置 EFI 函数的文档字符串
efi.__doc__ = \
"""Elder's Force Index (EFI)
Elder's Force Index measures the power behind a price movement using price
and volume as well as potential reversals and price corrections.
Sources:
https://www.tradingview.com/wiki/Elder%27s_Force_Index_(EFI)
https://www.motivewave.com/studies/elders_force_index.htm
Calculation:
Default Inputs:
length=20, drift=1, mamode=None
EMA = Exponential Moving Average
SMA = Simple Moving Average
pv_diff = close.diff(drift) * volume
if mamode == 'sma':
EFI = SMA(pv_diff, length)
else:
EFI = EMA(pv_diff, length)
Args:
close (pd.Series): Series of 'close's
volume (pd.Series): Series of 'volume's
length (int): The short period. Default: 13
drift (int): The diff period. Default: 1
mamode (str): See ```help(ta.ma)```py. 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\volume\eom.py
# -*- coding: utf-8 -*-
# 导入需要的库
from pandas_ta.overlap import hl2, sma
from pandas_ta.utils import get_drift, get_offset, non_zero_range, verify_series
# 定义 Ease of Movement (EOM) 函数
def eom(high, low, close, volume, length=None, divisor=None, drift=None, offset=None, **kwargs):
"""Indicator: Ease of Movement (EOM)"""
# 验证参数
length = int(length) if length and length > 0 else 14
divisor = divisor if divisor and divisor > 0 else 100000000
high = verify_series(high, length)
low = verify_series(low, length)
close = verify_series(close, length)
volume = verify_series(volume, length)
drift = get_drift(drift)
offset = get_offset(offset)
# 如果任何一个输入序列为 None,则返回 None
if high is None or low is None or close is None or volume is None: return
# 计算结果
# 计算高低价范围
high_low_range = non_zero_range(high, low)
# 计算距离
distance = hl2(high=high, low=low)
distance -= hl2(high=high.shift(drift), low=low.shift(drift))
# 计算箱比率
box_ratio = volume / divisor
box_ratio /= high_low_range
# 计算 EOM
eom = distance / box_ratio
# 对 EOM 序列进行简单移动平均
eom = sma(eom, length=length)
# 偏移
if offset != 0:
eom = eom.shift(offset)
# 处理填充
if "fillna" in kwargs:
eom.fillna(kwargs["fillna"], inplace=True)
if "fill_method" in kwargs:
eom.fillna(method=kwargs["fill_method"], inplace=True)
# 设置名称和类别
eom.name = f"EOM_{length}_{divisor}"
eom.category = "volume"
return eom
# 设置 EOM 函数的文档字符串
eom.__doc__ = \
"""Ease of Movement (EOM)
Ease of Movement is a volume based oscillator that is designed to measure the
relationship between price and volume flucuating across a zero line.
Sources:
https://www.tradingview.com/wiki/Ease_of_Movement_(EOM)
https://www.motivewave.com/studies/ease_of_movement.htm
https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:ease_of_movement_emv
Calculation:
Default Inputs:
length=14, divisor=100000000, drift=1
SMA = Simple Moving Average
hl_range = high - low
distance = 0.5 * (high - high.shift(drift) + low - low.shift(drift))
box_ratio = (volume / divisor) / hl_range
eom = distance / box_ratio
EOM = SMA(eom, length)
Args:
high (pd.Series): Series of 'high's
low (pd.Series): Series of 'low's
close (pd.Series): Series of 'close's
volume (pd.Series): Series of 'volume's
length (int): The short period. Default: 14
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\kvo.py
# 设置文件编码为 UTF-8
# 导入 DataFrame 类
from pandas import DataFrame
# 从 pandas_ta.overlap 模块导入 hlc3 和 ma 函数
from pandas_ta.overlap import hlc3, ma
# 从 pandas_ta.utils 模块导入 get_drift, get_offset, signed_series, verify_series 函数
from pandas_ta.utils import get_drift, get_offset, signed_series, verify_series
# 定义 Klinger Volume Oscillator (KVO) 指标函数
def kvo(high, low, close, volume, fast=None, slow=None, signal=None, mamode=None, drift=None, offset=None, **kwargs):
"""Indicator: Klinger Volume Oscillator (KVO)"""
# 验证参数
# 如果 fast 存在且大于 0,则将其转换为整数;否则默认为 34
fast = int(fast) if fast and fast > 0 else 34
# 如果 slow 存在且大于 0,则将其转换为整数;否则默认为 55
slow = int(slow) if slow and slow > 0 else 55
# 如果 signal 存在且大于 0,则将其转换为整数;否则默认为 13
signal = int(signal) if signal and signal > 0 else 13
# 如果 mamode 存在且是字符串类型,则将其转换为小写;否则默认为 'ema'
mamode = mamode.lower() if mamode and isinstance(mamode, str) else "ema"
# 计算参数中最大的长度
_length = max(fast, slow, signal)
# 验证输入序列的长度
high = verify_series(high, _length)
low = verify_series(low, _length)
close = verify_series(close, _length)
volume = verify_series(volume, _length)
# 获取漂移值
drift = get_drift(drift)
# 获取偏移值
offset = get_offset(offset)
# 如果输入的 high、low、close、volume 有任何一个为 None,则返回 None
if high is None or low is None or close is None or volume is None: return
# 计算结果
# 计算带符号的成交量
signed_volume = volume * signed_series(hlc3(high, low, close), 1)
# 从第一个有效索引开始取值
sv = signed_volume.loc[signed_volume.first_valid_index():,]
# 计算 KVO 指标
kvo = ma(mamode, sv, length=fast) - ma(mamode, sv, length=slow)
# 计算 KVO 的信号线
kvo_signal = ma(mamode, kvo.loc[kvo.first_valid_index():,], length=signal)
# 调整偏移
if offset != 0:
kvo = kvo.shift(offset)
kvo_signal = kvo_signal.shift(offset)
# 处理填充值
if "fillna" in kwargs:
kvo.fillna(kwargs["fillna"], inplace=True)
kvo_signal.fillna(kwargs["fillna"], inplace=True)
if "fill_method" in kwargs:
kvo.fillna(method=kwargs["fill_method"], inplace=True)
kvo_signal.fillna(method=kwargs["fill_method"], inplace=True)
# 设置指标的名称和分类
_props = f"_{fast}_{slow}_{signal}"
kvo.name = f"KVO{_props}"
kvo_signal.name = f"KVOs{_props}"
kvo.category = kvo_signal.category = "volume"
# 准备返回的 DataFrame
data = {kvo.name: kvo, kvo_signal.name: kvo_signal}
df = DataFrame(data)
df.name = f"KVO{_props}"
df.category = kvo.category
return df
# 设置函数文档字符串
kvo.__doc__ = \
"""Klinger Volume Oscillator (KVO)
This indicator was developed by Stephen J. Klinger. It is designed to predict
price reversals in a market by comparing volume to price.
Sources:
https://www.investopedia.com/terms/k/klingeroscillator.asp
https://www.daytrading.com/klinger-volume-oscillator
Calculation:
Default Inputs:
fast=34, slow=55, signal=13, drift=1
EMA = Exponential Moving Average
SV = volume * signed_series(HLC3, 1)
KVO = EMA(SV, fast) - EMA(SV, slow)
Signal = EMA(KVO, signal)
Args:
high (pd.Series): Series of 'high's
low (pd.Series): Series of 'low's
close (pd.Series): Series of 'close's
volume (pd.Series): Series of 'volume's
fast (int): The fast period. Default: 34
long (int): The long period. Default: 55
length_sig (int): The signal period. Default: 13
mamode (str): See ```help(ta.ma)```py. Default: 'ema'
"""
offset (int): How many periods to offset the result. Default: 0
# 偏移量(int):结果要偏移的周期数。默认值为0。
# 参数说明部分,描述函数的参数和返回值
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
fill_method (value, optional): Type of fill method
Returns:
pd.DataFrame: KVO and Signal columns.
.\pandas-ta\pandas_ta\volume\mfi.py
# -*- coding: utf-8 -*-
# 从 pandas 库中导入 DataFrame 类
from pandas import DataFrame
# 从 pandas_ta 库中导入 Imports 模块
from pandas_ta import Imports
# 从 pandas_ta.overlap 模块中导入 hlc3 函数
from pandas_ta.overlap import hlc3
# 从 pandas_ta.utils 模块中导入 get_drift, get_offset, verify_series 函数
from pandas_ta.utils import get_drift, get_offset, verify_series
# 定义 Money Flow Index (MFI) 函数
def mfi(high, low, close, volume, length=None, talib=None, drift=None, offset=None, **kwargs):
"""Indicator: Money Flow Index (MFI)"""
# 验证参数
length = int(length) if length and length > 0 else 14
high = verify_series(high, length)
low = verify_series(low, length)
close = verify_series(close, length)
volume = verify_series(volume, length)
drift = get_drift(drift)
offset = get_offset(offset)
mode_tal = bool(talib) if isinstance(talib, bool) else True
# 如果任何一个输入序列为空,则返回空值
if high is None or low is None or close is None or volume is None: return
# 计算结果
if Imports["talib"] and mode_tal:
# 如果 TA Lib 已安装且 talib 参数为 True,则使用 TA Lib 实现的 MFI 函数计算结果
from talib import MFI
mfi = MFI(high, low, close, volume, length)
else:
# 否则,使用自定义方法计算 MFI 指标
# 计算典型价格和原始资金流
typical_price = hlc3(high=high, low=low, close=close)
raw_money_flow = typical_price * volume
# 创建包含不同情况的数据框
tdf = DataFrame({"diff": 0, "rmf": raw_money_flow, "+mf": 0, "-mf": 0})
# 根据典型价格的变化情况更新数据框中的不同列
tdf.loc[(typical_price.diff(drift) > 0), "diff"] = 1
tdf.loc[tdf["diff"] == 1, "+mf"] = raw_money_flow
tdf.loc[(typical_price.diff(drift) < 0), "diff"] = -1
tdf.loc[tdf["diff"] == -1, "-mf"] = raw_money_flow
# 计算正和负资金流的滚动和
psum = tdf["+mf"].rolling(length).sum()
nsum = tdf["-mf"].rolling(length).sum()
# 计算资金流比率和 MFI 指标
tdf["mr"] = psum / nsum
mfi = 100 * psum / (psum + nsum)
tdf["mfi"] = mfi
# 偏移
if offset != 0:
mfi = mfi.shift(offset)
# 处理填充
if "fillna" in kwargs:
mfi.fillna(kwargs["fillna"], inplace=True)
if "fill_method" in kwargs:
mfi.fillna(method=kwargs["fill_method"], inplace=True)
# 设置名称和分类
mfi.name = f"MFI_{length}"
mfi.category = "volume"
return mfi
# 设置 MFI 函数的文档字符串
mfi.__doc__ = \
"""Money Flow Index (MFI)
Money Flow Index is an oscillator indicator that is used to measure buying and
selling pressure by utilizing both price and volume.
Sources:
https://www.tradingview.com/wiki/Money_Flow_(MFI)
Calculation:
Default Inputs:
length=14, drift=1
tp = typical_price = hlc3 = (high + low + close) / 3
rmf = raw_money_flow = tp * volume
pmf = pos_money_flow = SUM(rmf, length) if tp.diff(drift) > 0 else 0
nmf = neg_money_flow = SUM(rmf, length) if tp.diff(drift) < 0 else 0
MFR = money_flow_ratio = pmf / nmf
MFI = money_flow_index = 100 * pmf / (pmf + nmf)
Args:
high (pd.Series): Series of 'high's
low (pd.Series): Series of 'low's
close (pd.Series): Series of 'close's
volume (pd.Series): Series of 'volume's
length (int): The sum period. Default: 14
talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
version. Default: True
drift (int): The difference period. Default: 1
"""
offset (int): How many periods to offset the result. Default: 0
# 定义函数参数 offset,表示结果偏移的周期数,默认值为 0。
# 定义函数参数
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value) # 填充缺失值的方法和值
fill_method (value, optional): Type of fill method # 填充方法的类型
# 返回一个新的 pandas Series 对象,表示生成的新特征
Returns:
pd.Series: New feature generated. # 返回新生成的特征,类型为 pandas 的 Series 对象
.\pandas-ta\pandas_ta\volume\nvi.py
# -*- coding: utf-8 -*-
# 从 pandas_ta 库中导入动量指标 roc
from pandas_ta.momentum import roc
# 从 pandas_ta 库中导入工具函数 get_offset, signed_series, verify_series
from pandas_ta.utils import get_offset, signed_series, verify_series
# 定义函数 nvi,计算负量指数(NVI)
def nvi(close, volume, length=None, initial=None, offset=None, **kwargs):
"""Indicator: Negative Volume Index (NVI)"""
# 验证参数
length = int(length) if length and length > 0 else 1
initial = int(initial) if initial and initial > 0 else 1000
close = verify_series(close, length)
volume = verify_series(volume, length)
offset = get_offset(offset)
if close is None or volume is None: return
# 计算结果
roc_ = roc(close=close, length=length)
signed_volume = signed_series(volume, 1)
nvi = signed_volume[signed_volume < 0].abs() * roc_
nvi.fillna(0, inplace=True)
nvi.iloc[0] = initial
nvi = nvi.cumsum()
# 偏移
if offset != 0:
nvi = nvi.shift(offset)
# 处理填充
if "fillna" in kwargs:
nvi.fillna(kwargs["fillna"], inplace=True)
if "fill_method" in kwargs:
nvi.fillna(method=kwargs["fill_method"], inplace=True)
# 命名和分类
nvi.name = f"NVI_{length}"
nvi.category = "volume"
return nvi
# 设置 nvi 函数的文档字符串
nvi.__doc__ = \
"""Negative Volume Index (NVI)
The Negative Volume Index is a cumulative indicator that uses volume change in
an attempt to identify where smart money is active.
Sources:
https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:negative_volume_inde
https://www.motivewave.com/studies/negative_volume_index.htm
Calculation:
Default Inputs:
length=1, initial=1000
ROC = Rate of Change
roc = ROC(close, length)
signed_volume = signed_series(volume, initial=1)
nvi = signed_volume[signed_volume < 0].abs() * roc_
nvi.fillna(0, inplace=True)
nvi.iloc[0]= initial
nvi = nvi.cumsum()
Args:
close (pd.Series): Series of 'close's
volume (pd.Series): Series of 'volume's
length (int): The short period. Default: 13
initial (int): The short period. Default: 1000
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\obv.py
# -*- coding: utf-8 -*-
# 导入所需的库
from pandas_ta import Imports
from pandas_ta.utils import get_offset, signed_series, verify_series
# 定义 On Balance Volume (OBV) 指标函数
def obv(close, volume, talib=None, offset=None, **kwargs):
"""Indicator: On Balance Volume (OBV)"""
# 验证参数
# 确保 'close' 和 'volume' 是有效的 Series 对象
close = verify_series(close)
volume = verify_series(volume)
# 获取偏移量
offset = get_offset(offset)
# 确定是否使用 TA Lib
mode_tal = bool(talib) if isinstance(talib, bool) else True
# 计算结果
if Imports["talib"] and mode_tal:
# 如果 TA Lib 可用且 talib 参数为 True,则使用 TA Lib 中的 OBV 函数
from talib import OBV
obv = OBV(close, volume)
else:
# 否则,计算 signed_volume 并累积求和得到 OBV
signed_volume = signed_series(close, initial=1) * volume
obv = signed_volume.cumsum()
# 偏移结果
if offset != 0:
obv = obv.shift(offset)
# 处理填充
# 如果 'fillna' 参数存在,则使用指定值填充缺失值
if "fillna" in kwargs:
obv.fillna(kwargs["fillna"], inplace=True)
# 如果 'fill_method' 参数存在,则使用指定的填充方法填充缺失值
if "fill_method" in kwargs:
obv.fillna(method=kwargs["fill_method"], inplace=True)
# 为结果添加名称和分类信息
obv.name = f"OBV"
obv.category = "volume"
return obv
# 设置函数文档字符串
obv.__doc__ = \
"""On Balance Volume (OBV)
On Balance Volume is a cumulative indicator to measure buying and selling
pressure.
Sources:
https://www.tradingview.com/wiki/On_Balance_Volume_(OBV)
https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/on-balance-volume-obv/
https://www.motivewave.com/studies/on_balance_volume.htm
Calculation:
signed_volume = signed_series(close, initial=1) * volume
obv = signed_volume.cumsum()
Args:
close (pd.Series): Series of 'close's
volume (pd.Series): Series of 'volume'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\volume\pvi.py
# -*- coding: utf-8 -*-
# 从 pandas_ta 库中导入动量模块中的 roc 函数
from pandas_ta.momentum import roc
# 从 pandas_ta 库中导入工具模块中的 get_offset, signed_series, verify_series 函数
from pandas_ta.utils import get_offset, signed_series, verify_series
# 定义 Positive Volume Index (PVI) 指标函数
def pvi(close, volume, length=None, initial=None, offset=None, **kwargs):
"""Indicator: Positive Volume Index (PVI)"""
# 验证参数
length = int(length) if length and length > 0 else 1
# initial 默认为 1000
initial = int(initial) if initial and initial > 0 else 1000
# 验证 close 和 volume 参数是否为 Series 类型,并且长度符合要求
close = verify_series(close, length)
volume = verify_series(volume, length)
# 获取偏移量
offset = get_offset(offset)
# 如果 close 或 volume 为 None,则返回空
if close is None or volume is None: return
# 计算结果
# 将 volume 序列转换为带符号的序列
signed_volume = signed_series(volume, 1)
# 计算 PVI
pvi = roc(close=close, length=length) * signed_volume[signed_volume > 0].abs()
# 将 NaN 值填充为 0
pvi.fillna(0, inplace=True)
# 将第一个值设置为 initial
pvi.iloc[0] = initial
# 对 PVI 序列进行累积求和
pvi = pvi.cumsum()
# 偏移
if offset != 0:
pvi = pvi.shift(offset)
# 处理填充
if "fillna" in kwargs:
pvi.fillna(kwargs["fillna"], inplace=True)
if "fill_method" in kwargs:
pvi.fillna(method=kwargs["fill_method"], inplace=True)
# 设置指标名称和分类
pvi.name = f"PVI_{length}"
pvi.category = "volume"
return pvi
# 设置 PVI 函数的文档字符串
pvi.__doc__ = \
"""Positive Volume Index (PVI)
The Positive Volume Index is a cumulative indicator that uses volume change in
an attempt to identify where smart money is active.
Used in conjunction with NVI.
Sources:
https://www.investopedia.com/terms/p/pvi.asp
Calculation:
Default Inputs:
length=1, initial=1000
ROC = Rate of Change
roc = ROC(close, length)
signed_volume = signed_series(volume, initial=1)
pvi = signed_volume[signed_volume > 0].abs() * roc_
pvi.fillna(0, inplace=True)
pvi.iloc[0]= initial
pvi = pvi.cumsum()
Args:
close (pd.Series): Series of 'close's
volume (pd.Series): Series of 'volume's
length (int): The short period. Default: 13
initial (int): The short period. Default: 1000
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.
"""