PVO(Percentage Volume Oscillator)는 PPO(Percentage Price Oscillator)와 유사하다. 차이라고 하면 가격 대신에 거개량을 넣어 PPO나 MACD와 같은 지표를 뽑아낸다는 것. 거래량의 12일, 26일 지수 이동 평균(EMA, Exponential Moving Average)을 만들고 이 차이를 장기(26일) 이동 평균으로 나눈 값을 PVO로 사용한다. 그리고 PVO를 9일 지수 이동 평균하여 이 값을 Signal로 사용한다. PVO와 시그널의 차이를 히스토그램으로 그려 표현하는데 이 방식은 PPO와 동일하다.
PVO는 거래량을 활용한 보조지표이다. 그러다 보니 PPO에 비해 변동이 심하다. 주가의 경우에는 특히 국내 주식 같은 경우에는 변동 폭의 제한이 있고(-30% ~ +30%), 가격 변동 폭 제한이 없다고 하더라도 가격변동이 두 배씩 움직이는 경우가 드물다. 하지만 거래량의 경우에는 빈번하게 두 배이상 차이나는 경우가 발생하고, 거래량이 두 배 이상 치솟았다가도 다음날 다시 원상태로 복귀되는 경우가 빈번하다. 이렇기 때문에 적당히 노이즈를 제거하여 사용하는 경우가 많은데 PVO는 이런 거래량 변화를 이동평균하여 스무싱 하고 추세적 거래량 변화를 관찰할 수 있는 보조지표이다.
PVO는 그 자체로 매매전략에 적용하지 않는다. PVO는 가격에 대한 데이터가 없기 때문에 MACD, PPO 등 다른 모멘텀 지표와 함께 사용한다. 이때 PVO를 타 보조지표와 결합하는 방법은 PVO 혹은 시그널이 양수일 경우, 보조지표에서 발생한 시그널의 적중 확률을 더 높다고 본다. 이는 추세가 형성될 때, 거래량을 동반하는 경우가 많은데 이 점을 이용하는 것. 따라서 PVO를 이용해 거래량을 늘려가면서 시그널이 발생하는 경우를 포착한다고 보면 된다.
마지막으로 트레이딩 뷰 파인 스크립트 소스와 pandas-ta 소스를 공유하며 마친다.
- PVO(Percentage Volume Oscillator) 트레이딩 뷰 파인 스크립트 지표 소스
//@version=5
indicator(title="Percentage Volume Oscillator", shorttitle="PVO", format=format.price, precision=2, timeframe="", timeframe_gaps=true)
import TradingView/ta/7 as ta7
import blackcat1402/pandas_ta/7 as pta
ma(source, length, _type) =>
switch _type
"SMA" => ta.sma(source, length)
"EMA" => ta.ema(source, length)
"DEMA" => ta7.dema(source,length)
"TEMA" => ta7.tema(source,length)
"FRAMA" => ta7.frama(source,length)
"T3" => ta7.t3(source,length)
"TRIMA" => ta7.trima(source,length)
"RMA" => ta.rma(source, length)
"WMA" => ta.wma(source, length)
"HMA" => ta.hma(source, length)
"VWMA" => ta.vwma(source * volume, length)
"ALMA" => pta.alma(source, length)
"JMA" => pta.jma(source, length)
"SINWMA" => pta.sinwma(source, length)
"FWMA" => pta.fwma(source, length)
"LINREG" => pta.linreg(source, length)
"SWMA" => pta.swma(source)
"YIDYA" => pta.vidya(source, length)
"VWAP" => pta.vwap(source)
"ZLMA" => pta.zlma(source, length)
fastLengthInput = input.int(12, title="Fast Length", group="Fast", minval=1)
fastmaTypeInput = input.string("EMA", title="Fast MA Type", options = ["SMA", "EMA", "DEMA", "TEMA", "FRAMA", "T3", "TRIMA", "RMA", "WMA", "HMA", "VWMA", "ALMA", "JMA", "SINWMA", "FWMA", "LINREG", "SWMA", "VIDYA", "VWAP", "ZLMA"], group="Fast", display = display.data_window)
slowLengthInput = input.int(26, title="Slow Length", group="Slow", minval=1)
slowmaTypeInput = input.string("EMA", title="Fast MA Type", options = ["SMA", "EMA", "DEMA", "TEMA", "FRAMA", "T3", "TRIMA", "RMA", "WMA", "HMA", "VWMA", "ALMA", "JMA", "SINWMA", "FWMA", "LINREG", "SWMA", "VIDYA", "VWAP", "ZLMA"], group="Slow", display = display.data_window)
signalLengthInput = input.int(9, title="Slow Length", group="Signal", minval=1)
signalmaTypeInput = input.string("EMA", title="Fast MA Type", options = ["SMA", "EMA", "DEMA", "TEMA", "FRAMA", "T3", "TRIMA", "RMA", "WMA", "HMA", "VWMA", "ALMA", "JMA", "SINWMA", "FWMA", "LINREG", "SWMA", "VIDYA", "VWAP", "ZLMA"], group="Signal", display = display.data_window)
upperInput = input.float(1.0, title="Upper Band", group="Band")
lowerInput = input.float(-1.0, title="Lower Band", group="Band")
fastMA = ma(volume, fastLengthInput, fastmaTypeInput)
slowtMA = ma(volume, slowLengthInput, slowmaTypeInput)
PVO = ( fastMA - slowtMA ) / slowtMA * 100
signal = ma(PVO, signalLengthInput, signalmaTypeInput)
histogram = PVO - signal
plot(PVO, title="PPO", color=color.blue)
plot(signal, title="Signal", color=color.red)
hline(0, "Middle Band", linestyle=hline.style_dotted, color=color.gray)
plot(histogram, title = "Histogram", style = plot.style_columns, color = (histogram >= 0 ? (histogram[1] < histogram ? #26A69A : #B2DFDB) : (histogram[1] < histogram ? #FFCDD2 : #FF5252)))
upperBand = hline(upperInput, "Upper Band", linestyle=hline.style_dotted, color=color.gray)
lowerBand = hline(lowerInput, "Lower Band", linestyle=hline.style_dotted, color=color.gray)
fill(upperBand, lowerBand, title="Background", color=color.new(color.gray, 80))
- PVO(Percentage Volume Oscillator) pandas-ta 소스
import pandas as pd
import pandas_ta as ta
import FinanceDataReader as fdr
data = fdr.DataReader('005930')
pvo = ta.pvo(volume=data['Volume'], fast=12, slow=26, signal=9, mamode="EMA")
data = pd.concat([data, pvo], axis=1)
data.dropna(inplace=True)