Repository: quantopian/zipline
File: tests/pipeline/test_technical.py (Python)

Code before:

        check_allclose(expected, out)

    def test_rsi_edge_cases(self):
        """
        Test against example RSI calculation found online. Test cases where
        close prices are always increasing and where close prices are always
        decreasing. Scaling price series by a factor should not affect
        the result.
        """

        rsi = RSI()

        today = np.datetime64(1, 'ns')
        assets = np.arange(4)
        out = np.empty((4,), dtype=float)

        example_case = np.array([46.125, 47.125, 46.4375, 46.9375, 44.9375,
                                 44.25, 44.625, 45.75, 47.8125, 47.5625, 47.,
                                 44.5625, 46.3125, 47.6875, 46.6875])
        starting_val = 46.0
        increasing = np.linspace(starting_val, starting_val + 1.4, num=15)
        decreasing = np.linspace(starting_val, starting_val - 1.4, num=15)
        double = example_case * 2

        closes = np.vstack((increasing, decreasing, example_case, double)).T
        rsi.compute(today, assets, out, closes)
        np.testing.assert_almost_equal(
            out,
            np.array([100, 0, 51.779, 51.779], dtype=float),
            decimal=3
        )


class AnnualizedVolatilityTestCase(ZiplineTestCase):
    """
    Test Annualized Volatility
    """
    def test_simple_volatility(self):
        """
        Simple test for uniform returns should generate 0 volatility
        """
        nassets = 3
        ann_vol = AnnualizedVolatility()
        today = pd.Timestamp('2016', tz='utc')
        assets = np.arange(nassets, dtype=np.float64)
        returns = np.full((ann_vol.window_length, nassets),
                          0.004,
                          dtype=np.float64)
        out = np.empty(shape=(nassets,), dtype=np.float64)


Review comment (bug):
What do you think of breaking this into 3 separate tests? One for `always_increasing`, one for `always_decreasing`, and one for `same_returns`?

Each of those cases may independently fail, and it would be useful to isolate which one fails if they do.


Code after:

        check_allclose(expected, out)

    def test_rsi_all_positive_returns(self):
        """
        RSI indicator should be 100 in the case of 14 days of positive returns.
        """

        rsi = RSI()

        today = np.datetime64(1, 'ns')
        assets = np.arange(1)
        out = np.empty((1,), dtype=float)

        closes = np.linspace(46, 60, num=15)
        closes.shape = (15, 1)
        rsi.compute(today, assets, out, closes)
        self.assertEqual(out[0], 100.0)

    def test_rsi_all_negative_returns(self):
        """
        RSI indicator should be 0 in the case of 14 days of negative returns.
        """
        rsi = RSI()

        today = np.datetime64(1, 'ns')
        assets = np.arange(1)
        out = np.empty((1,), dtype=float)

        closes = np.linspace(46, 32, num=15)
        closes.shape = (15, 1)

        rsi.compute(today, assets, out, closes)
        self.assertEqual(out[0], 0.0)

    def test_rsi_same_returns(self):
        """
        RSI indicator should be the same for two price series with the same
        returns, even if the prices are different.
        """
        rsi = RSI()

        today = np.datetime64(1, 'ns')
        assets = np.arange(2)
        out = np.empty((2,), dtype=float)

        example_case = np.array([46.125, 47.125, 46.4375, 46.9375, 44.9375,
                                 44.25, 44.625, 45.75, 47.8125, 47.5625, 47.,
                                 44.5625, 46.3125, 47.6875, 46.6875])
        double = example_case * 2