Repository: quantopian/zipline
File: zipline/pipeline/factors/basic.py (Python)

Code before:
    """
    Calculates the percent change in close price over the given window_length.

    **Default Inputs**: [EquityPricing.close]
    """
    inputs = [EquityPricing.close]
    window_safe = True

    def _validate(self):
        super(Returns, self)._validate()
        if self.window_length < 2:
            raise ValueError(
                "'Returns' expected a window length of at least 2, but was "
                "given {window_length}. For daily returns, use a window "
                "length of 2.".format(window_length=self.window_length)
            )

    def compute(self, today, assets, out, close):
        out[:] = (close[-1] - close[0]) / close[0]


class PercentChange(CustomFactor):
    """
    Calculates the percent change in the input value over the given window_length.
    Note: Uses the formula "new - old / abs(old)" to handle negative input values

    **Default Inputs:** None
    """
    window_safe = True

    def _validate(self):
        super(PercentChange, self)._validate()
        if self.window_length < 2:
            raise ValueError(
                "'PercentChange' expected a window length of at least 2, but was "
                "given {window_length}. For daily percent change, use a window "
                "length of 2.".format(window_length=self.window_length)
            )

    def compute(self, today, assets, out, values):
        out[:] = (values[-1] - values[0]) / abs(values[0])


class DailyReturns(Returns):
    """
    Calculates daily percent change in close price.

    **Default Inputs**: [EquityPricing.close]
    """
    inputs = [EquityPricing.close]
    window_safe = True

Review comment (suggestion):
Looks like other factors mention `**Default Window Length**: None`, might be worth adding that here too.

Code after:
    """
    Calculates the percent change in close price over the given window_length.

    **Default Inputs**: [EquityPricing.close]
    """
    inputs = [EquityPricing.close]
    window_safe = True

    def _validate(self):
        super(Returns, self)._validate()
        if self.window_length < 2:
            raise ValueError(
                "'Returns' expected a window length of at least 2, but was "
                "given {window_length}. For daily returns, use a window "
                "length of 2.".format(window_length=self.window_length)
            )

    def compute(self, today, assets, out, close):
        out[:] = (close[-1] - close[0]) / close[0]


class PercentChange(SingleInputMixin, CustomFactor):
    """
    Calculates the percent change over the given window_length.

    **Default Inputs:** None

    **Default Window Length:** None

    Notes
    -----
    Percent change is calculated as ``(new - old) / abs(old)``.
    """
    window_safe = True

    def _validate(self):
        super(PercentChange, self)._validate()
        if self.window_length < 2:
            raise ValueError(
                "'PercentChange' expected a window length"
                "of at least 2, but was given {window_length}. "
                "For daily percent change, use a window "
                "length of 2.".format(window_length=self.window_length)
            )

    def compute(self, today, assets, out, values):
        out[:] = (values[-1] - values[0]) / abs(values[0])


class DailyReturns(Returns):
    """