From 53ecdea9ebe7c40fa0fa7e764ae999daedabcadc Mon Sep 17 00:00:00 2001 From: w31ha0 Date: Sun, 31 May 2020 07:45:25 -0700 Subject: [PATCH 1/4] ENH: Add new technical indicator: Fibonacci Retractment --- tests/pipeline/test_technical.py | 29 ++++++++++++++++++++++++ zipline/pipeline/factors/__init__.py | 2 ++ zipline/pipeline/factors/technical.py | 32 ++++++++++++++++++++++++++- 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/tests/pipeline/test_technical.py b/tests/pipeline/test_technical.py index 7727431b9b..0a4d4d27f4 100644 --- a/tests/pipeline/test_technical.py +++ b/tests/pipeline/test_technical.py @@ -20,6 +20,7 @@ MovingAverageConvergenceDivergenceSignal, AnnualizedVolatility, RSI, + FibonacciRetractment ) from zipline.testing import check_allclose, parameter_space from zipline.testing.fixtures import ZiplineTestCase @@ -663,3 +664,31 @@ def test_volatility(self): expected_vol, decimal=8 ) + +class FibonacciRetractmentTestCase(ZiplineTestCase): + """ + Test FibonacciRetractment Calculation + """ + def test_fibo(self): + + fibo = FibonacciRetractment() + + nassets = 3 + today = np.datetime64(1, 'ns') + assets = np.arange(nassets) + + np.random.seed(100) # Seed so we get deterministic results. + test_data = np.abs(np.random.randn(15, nassets)) + + out = np.empty((6, nassets), dtype=float) + fibo.compute(today, assets, out, test_data) + + expected = np.empty((6, 3), dtype=float) + expected[0] = [1.74976547, 1.69061683, 1.61898166] + expected[1] = [1.08414923, 1.14101903, 1.0217989] + expected[2] = [0.87854002, 0.97124798, 0.83732884] + expected[3] = [0.67293081, 0.80147694, 0.65285877] + expected[4] = [0.41853298, 0.59142123, 0.42461615] + expected[5] = [0.00731456, 0.25187914, 0.05567601] + + np.testing.assert_almost_equal(out, expected, 7) diff --git a/zipline/pipeline/factors/__init__.py b/zipline/pipeline/factors/__init__.py index 65fadd80f6..98764f14bb 100644 --- a/zipline/pipeline/factors/__init__.py +++ b/zipline/pipeline/factors/__init__.py @@ -41,6 +41,7 @@ RateOfChangePercentage, RSI, TrueRange, + FibonacciRetractment, ) __all__ = [ @@ -58,6 +59,7 @@ 'ExponentialWeightedMovingStdDev', 'Factor', 'FastStochasticOscillator', + 'FibonacciRetractment', 'IchimokuKinkoHyo', 'Latest', 'LinearWeightedMovingAverage', diff --git a/zipline/pipeline/factors/technical.py b/zipline/pipeline/factors/technical.py index ad490ed2b5..d4ad734983 100644 --- a/zipline/pipeline/factors/technical.py +++ b/zipline/pipeline/factors/technical.py @@ -11,6 +11,7 @@ diff, dstack, inf, + apply_along_axis ) from numexpr import evaluate @@ -387,6 +388,35 @@ def compute(self, today, assets, out, close, fast_period, slow_period, macd = fast_EWMA - slow_EWMA out[:] = self._ewma(macd.T, signal_period) - # Convenience aliases. MACDSignal = MovingAverageConvergenceDivergenceSignal + +class FibonacciRetractment(CustomFactor): + """ + FibonacciRetractment + + https://www.investopedia.com/ask/answers/05/fibonacciretracement.asp + + Given a period, 4 retractment levels are calculated between the peak and the trough, + where the ratio of each retractment level is based on Fibonacci sequence. + + Parameters + ---------- + period : int > 0, optional + The window length for the Fibonacci retractment levels calculation. Default is 0. + """ + + window_length = 15 + inputs = (EquityPricing.close,) + + def compute(self, today, assets, out, closes, period = 0): + windowed_closes = closes[-period:] + trough = apply_along_axis(min, 0, windowed_closes) + peak = apply_along_axis(max, 0, windowed_closes) + range = peak - trough + out[0] = peak + out[1] = trough + 0.618 * range + out[2] = trough + 0.5 * range + out[3] = trough + 0.382 * range + out[4] = trough + 0.236 * range + out[5] = trough From a181f6086e93677d995006b6f1eda683be373321 Mon Sep 17 00:00:00 2001 From: w31ha0 Date: Sun, 31 May 2020 08:16:38 -0700 Subject: [PATCH 2/4] ENH: Fix blank line --- tests/pipeline/test_technical.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/pipeline/test_technical.py b/tests/pipeline/test_technical.py index 0a4d4d27f4..42b8853b83 100644 --- a/tests/pipeline/test_technical.py +++ b/tests/pipeline/test_technical.py @@ -665,6 +665,7 @@ def test_volatility(self): decimal=8 ) + class FibonacciRetractmentTestCase(ZiplineTestCase): """ Test FibonacciRetractment Calculation From f75758534b6f8d8bf611f88dc1364a943ecb6f58 Mon Sep 17 00:00:00 2001 From: w31ha0 Date: Mon, 1 Jun 2020 01:38:22 -0700 Subject: [PATCH 3/4] ENH: Fix check style --- zipline/pipeline/factors/technical.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/zipline/pipeline/factors/technical.py b/zipline/pipeline/factors/technical.py index d4ad734983..1ab9e1408c 100644 --- a/zipline/pipeline/factors/technical.py +++ b/zipline/pipeline/factors/technical.py @@ -391,25 +391,28 @@ def compute(self, today, assets, out, close, fast_period, slow_period, # Convenience aliases. MACDSignal = MovingAverageConvergenceDivergenceSignal + class FibonacciRetractment(CustomFactor): """ FibonacciRetractment https://www.investopedia.com/ask/answers/05/fibonacciretracement.asp - Given a period, 4 retractment levels are calculated between the peak and the trough, - where the ratio of each retractment level is based on Fibonacci sequence. + Given a period, 4 retractment levels are calculated between the peak + and the trough, where the ratio of each retractment level is based on + Fibonacci sequence. Parameters ---------- period : int > 0, optional - The window length for the Fibonacci retractment levels calculation. Default is 0. + The window length for the Fibonacci retractment levels calculation. + Default is 0. """ window_length = 15 inputs = (EquityPricing.close,) - def compute(self, today, assets, out, closes, period = 0): + def compute(self, today, assets, out, closes, period=0): windowed_closes = closes[-period:] trough = apply_along_axis(min, 0, windowed_closes) peak = apply_along_axis(max, 0, windowed_closes) From 7b62c8892cbf9454ffd276a252a0c1e9b509e150 Mon Sep 17 00:00:00 2001 From: w31ha0 Date: Mon, 1 Jun 2020 01:58:50 -0700 Subject: [PATCH 4/4] ENH: Fix check style --- zipline/pipeline/factors/technical.py | 1 + 1 file changed, 1 insertion(+) diff --git a/zipline/pipeline/factors/technical.py b/zipline/pipeline/factors/technical.py index 1ab9e1408c..2a0e53ca56 100644 --- a/zipline/pipeline/factors/technical.py +++ b/zipline/pipeline/factors/technical.py @@ -388,6 +388,7 @@ def compute(self, today, assets, out, close, fast_period, slow_period, macd = fast_EWMA - slow_EWMA out[:] = self._ewma(macd.T, signal_period) + # Convenience aliases. MACDSignal = MovingAverageConvergenceDivergenceSignal