Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GH-171] Add support for PVO #172

Merged
merged 1 commit into from
Jul 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ Supported statistics/indicators are:
* KST: Know Sure Thing
* PGO: Pretty Good Oscillator
* PSL: Psychological Line
* PVO: Percentage Volume Oscillator

## Installation

Expand Down Expand Up @@ -1022,6 +1023,27 @@ Example:
* `df['psl_10']` retrieves the PSL with window 10.
* `df['high_12_psl']` retrieves the PSL of high price with window 10.

#### [Percentage Volume Oscillator(PVO)](https://school.stockcharts.com/doku.php?id=technical_indicators:percentage_volume_oscillator_pvo)

The Percentage Volume Oscillator (PVO) is a momentum oscillator for volume.
The PVO measures the difference between two volume-based moving averages as
a percentage of the larger moving average.

Formular:

* Percentage Volume Oscillator (PVO):
((12-day EMA of Volume - 26-day EMA of Volume)/26-day EMA of Volume) x 100
* Signal Line: 9-day EMA of PVO
* PVO Histogram: PVO - Signal Line

Example:
* `df['pvo']` derives from the difference of 2 exponential moving average.
* `df['pvos]` is the signal line.
* `df['pvoh']` is he histogram line.

The period of short, long EMA and signal line can be tuned with
`set_dft_window('pvo', (short, long, signal))`. The default
windows are 12 and 26 and 9.

## Issues

Expand Down
41 changes: 34 additions & 7 deletions stockstats.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class StockStatsError(Exception):
'pdi': 14,
'pgo': 14,
'ppo': (12, 26, 9), # short, long, signal
'pvo': (12, 26, 9), # short, long, signal
'psl': 12,
'rsi': 14,
'rsv': 9,
Expand Down Expand Up @@ -1120,6 +1121,37 @@ def _get_macd(self, meta: _Meta):
self[macds] = self.ema(self[macd], signal_w)
self[macdh] = self[macd] - self[macds]

def _ppo_and_pvo(self, name: str, col_name: str, meta: _Meta):
volume = self[col_name]
short_w, long_w, signal_w = meta.int0, meta.int1, meta.int2
pvo_short = self.ema(volume, short_w)
pvo_long = self.ema(volume, long_w)
self[name] = (pvo_short - pvo_long) / pvo_long * 100
self[f'{name}s'] = self.ema(self[name], signal_w)
self[f'{name}h'] = self[name] - self[f'{name}s']

def _get_pvo(self, meta: _Meta):
""" Percentage Volume Oscillator

The Percentage Volume Oscillator (PVO) is a momentum oscillator for
volume. The PVO measures the difference between two volume-based
moving averages as a percentage of the larger moving average.

https://school.stockcharts.com/doku.php?id=technical_indicators:percentage_volume_oscillator_pvo

Percentage Volume Oscillator (PVO):
{(12_EOV - 26_EOV)/26_EOV} x 100

Where:
* 12_EOV is the 12-day EMA of Volume
* 26_EOV is the 26-day EMA of Volume

Signal Line: 9-day EMA of PVO

PVO Histogram: PVO - Signal Line
"""
return self._ppo_and_pvo('pvo', 'volume', meta)

def _get_ppo(self, meta: _Meta):
""" Percentage Price Oscillator

Expand All @@ -1132,13 +1164,7 @@ def _get_ppo(self, meta: _Meta):

PPO Histogram: PPO - Signal Line
"""
close = self['close']
short_w, long_w, signal_w = meta.int0, meta.int1, meta.int2
ppo_short = self.ema(close, short_w)
ppo_long = self.ema(close, long_w)
self['ppo'] = (ppo_short - ppo_long) / ppo_long * 100
self['ppos'] = self.ema(self['ppo'], signal_w)
self['ppoh'] = self['ppo'] - self['ppos']
return self._ppo_and_pvo('ppo', 'close', meta)

def _eri(self, window):
ema = self.ema(self['close'], window, adjust=False)
Expand Down Expand Up @@ -1738,6 +1764,7 @@ def handler(self):
('tp',): self._get_tp,
('boll', 'boll_ub', 'boll_lb'): self._get_boll,
('macd', 'macds', 'macdh'): self._get_macd,
('pvo', 'pvos', 'pvoh'): self._get_pvo,
('ppo', 'ppos', 'ppoh'): self._get_ppo,
('cr', 'cr-ma1', 'cr-ma2', 'cr-ma3'): self._get_cr,
('tr',): self._get_tr,
Expand Down
7 changes: 7 additions & 0 deletions test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1079,3 +1079,10 @@ def test_psl(self):
high_psl12 = stock['high_12_psl']
assert_that(high_psl12[20110118], near_to(41.666))
assert_that(high_psl12[20110127], near_to(41.666))

def test_pvo(self):
stock = self.get_stock_90days()
_ = stock[['pvo', 'pvos', 'pvoh']]
assert_that(stock['pvo'].loc[20110331], near_to(3.4708))
assert_that(stock['pvos'].loc[20110331], near_to(-3.7464))
assert_that(stock['pvoh'].loc[20110331], near_to(7.2173))