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