From 8a32c2b7ce2d40806ae3da280418fbfeb7c3f520 Mon Sep 17 00:00:00 2001 From: Elizaveta239 Date: Sat, 4 Jun 2016 12:06:19 -0700 Subject: [PATCH 1/3] ENH: Add Rate of change Percentage indicator --- tests/pipeline/test_technical.py | 17 +++++++++++++++ zipline/pipeline/factors/__init__.py | 2 ++ zipline/pipeline/factors/technical.py | 30 +++++++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/tests/pipeline/test_technical.py b/tests/pipeline/test_technical.py index bcf233fc..5b672164 100644 --- a/tests/pipeline/test_technical.py +++ b/tests/pipeline/test_technical.py @@ -15,6 +15,7 @@ from zipline.pipeline.factors import ( Aroon, FastStochasticOscillator, IchimokuKinkoHyo, + RateOfChangePercentage, ) from zipline.testing import ExplodingObject, parameter_space from zipline.testing.fixtures import WithAssetFinder, ZiplineTestCase @@ -354,3 +355,19 @@ class IchimokuKinkoHyoTestCase(ZiplineTestCase): str(e.exception), '%s must be <= the window_length: 53 > 52' % arg, ) + + +class TestRateOfChangePercentage(ZiplineTestCase): + def test_rate_of_change_per(self): + rocp = RateOfChangePercentage( + inputs=(USEquityPricing.close,), + window_length=10 + ) + today = pd.Timestamp('2014') + assets = np.arange(5, dtype=np.int64) + + data = np.ones((10, 5)) + data[0, :] = np.full((1, 5), 2.0) + out = np.zeros(data.shape[1]) + rocp.compute(today, assets, out, data) + assert_equal(out, np.full((5,), -50.0)) diff --git a/zipline/pipeline/factors/__init__.py b/zipline/pipeline/factors/__init__.py index e32dac95..422cf750 100644 --- a/zipline/pipeline/factors/__init__.py +++ b/zipline/pipeline/factors/__init__.py @@ -24,6 +24,7 @@ from .technical import ( FastStochasticOscillator, IchimokuKinkoHyo, MaxDrawdown, + RateOfChangePercentage, Returns, RSI, SimpleMovingAverage, @@ -47,6 +48,7 @@ __all__ = [ 'IchimokuKinkoHyo', 'Latest', 'MaxDrawdown', + 'RateOfChangePercentage', 'RecarrayField', 'Returns', 'RollingLinearRegressionOfReturns', diff --git a/zipline/pipeline/factors/technical.py b/zipline/pipeline/factors/technical.py index 8344130a..66befec6 100644 --- a/zipline/pipeline/factors/technical.py +++ b/zipline/pipeline/factors/technical.py @@ -590,3 +590,33 @@ class IchimokuKinkoHyo(CustomFactor): out.senkou_span_a = (tenkan_sen + kijun_sen) / 2 out.senkou_span_b = (high.max(axis=0) + low.min(axis=0)) / 2 out.chikou_span = close[chikou_span_length] + + +class RateOfChangePercentage(CustomFactor): + """ + Rate of change Percentage + ROC measures the percentage change in price from one period to the next. + The ROC calculation compares the current price with the price `n` + periods ago. + Formula for calculation: ((price - prevPrice) / prevPrice) * 100 + price - the current price + prevPrice - the price n days ago, equals window length + + **Default Inputs**: [USEquityPricing.close] + **Default Window Length**: 10 + + """ + inputs = (USEquityPricing.close,) + window_length = 10 + + def compute(self, today, assets, out, close): + today_close = close[-1] + prev_close = close[0] + evaluate('((tc - pc) / pc) * 100', + local_dict={ + 'tc': today_close, + 'pc': prev_close + }, + global_dict={}, + out=out, + ) From dc0784b88d6532d88784fcdd9dae95f227ed9d4f Mon Sep 17 00:00:00 2001 From: Richard Frank Date: Wed, 13 Jul 2016 19:44:13 -0400 Subject: [PATCH 2/3] MAINT: Removed defaults from RateOfChangePercentage since it's general enough that we don't need to assume closes --- zipline/pipeline/factors/technical.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/zipline/pipeline/factors/technical.py b/zipline/pipeline/factors/technical.py index 66befec6..5802fff3 100644 --- a/zipline/pipeline/factors/technical.py +++ b/zipline/pipeline/factors/technical.py @@ -601,14 +601,7 @@ class RateOfChangePercentage(CustomFactor): Formula for calculation: ((price - prevPrice) / prevPrice) * 100 price - the current price prevPrice - the price n days ago, equals window length - - **Default Inputs**: [USEquityPricing.close] - **Default Window Length**: 10 - """ - inputs = (USEquityPricing.close,) - window_length = 10 - def compute(self, today, assets, out, close): today_close = close[-1] prev_close = close[0] From c9b0e4050d0357468fce128470a9766cca7fae7b Mon Sep 17 00:00:00 2001 From: Richard Frank Date: Wed, 13 Jul 2016 19:45:51 -0400 Subject: [PATCH 3/3] TST: Added more test cases for RateOfChangePercentage --- tests/pipeline/test_technical.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/tests/pipeline/test_technical.py b/tests/pipeline/test_technical.py index 5b672164..a34d88e3 100644 --- a/tests/pipeline/test_technical.py +++ b/tests/pipeline/test_technical.py @@ -1,6 +1,7 @@ from __future__ import division from nose_parameterized import parameterized +from six.moves import range import numpy as np import pandas as pd import talib @@ -358,16 +359,24 @@ class IchimokuKinkoHyoTestCase(ZiplineTestCase): class TestRateOfChangePercentage(ZiplineTestCase): - def test_rate_of_change_per(self): + @parameterized.expand([ + ('constant', [2.] * 10, 0.0), + ('step', [2.] + [1.] * 9, -50.0), + ('linear', [2. + x for x in range(10)], 450.0), + ('quadratic', [2. + x**2 for x in range(10)], 4050.0), + ]) + def test_rate_of_change_percentage(self, test_name, data, expected): + window_length = len(data) + rocp = RateOfChangePercentage( inputs=(USEquityPricing.close,), - window_length=10 + window_length=window_length, ) today = pd.Timestamp('2014') assets = np.arange(5, dtype=np.int64) + # broadcast data across assets + data = np.array(data)[:, np.newaxis] * np.ones(len(assets)) - data = np.ones((10, 5)) - data[0, :] = np.full((1, 5), 2.0) - out = np.zeros(data.shape[1]) + out = np.zeros(len(assets)) rocp.compute(today, assets, out, data) - assert_equal(out, np.full((5,), -50.0)) + assert_equal(out, np.full((len(assets),), expected))