old_contents: """
  Technical Analysis Factors
  --------------------------
  """
  from bottleneck import (
      nanargmax,
      nanmax,
      nanmean,
      nansum,
  )
  from numpy import (
      clip,
      diff,
      fmax,
      inf,
      isnan,
      NINF,
  )
  from numexpr import evaluate
  
  from zipline.pipeline.data import USEquityPricing
  from zipline.pipeline.term import SingleInputMixin
  from zipline.utils.control_flow import ignore_nanwarnings
  from .factor import CustomFactor
  
  
  class RSI(CustomFactor, SingleInputMixin):
      """
      Factor computing rolling relative-strength index on a DataSet.
  
      Default Input: USEquityPricing.close
      Default Window Length: 14
      """
      window_length = 14
      inputs = (USEquityPricing.close,)
  
      def compute(self, today, assets, out, closes):
          diffs = diff(closes)
          ups = nanmean(clip(diffs, 0, inf), axis=0)
          downs = nanmean(clip(diffs, -inf, 0), axis=0)
          return evaluate(
              "100 - (100 / (1 + (ups / downs)))",
              locals_dict={'ups': ups, 'downs': downs},
              globals_dict={},
              out=out,
          )
  
  
  class SimpleMovingAverage(CustomFactor, SingleInputMixin):
      """
      Factor computing moving averages on a DataSet.
      """
      # numpy's nan functions throw warnings when passed an array containing only
      # nans, but they still returns the desired value (nan), so we ignore the
      # warning.
      ctx = ignore_nanwarnings()
  
      def compute(self, today, assets, out, data):
          out[:] = nanmean(data, axis=0)
  
  
  class WeightedAverageValue(CustomFactor):
      """
      Helper for VWAP-like computations.
      """
      def compute(self, today, assets, out, base, weight):
          out[:] = nansum(base * weight, axis=0) / nansum(weight, axis=0)
  
  
  class VWAP(WeightedAverageValue):
      """
      Volume-weighted average price
      """
      inputs = (USEquityPricing.close, USEquityPricing.volume)
  
  
  class MaxDrawdown(CustomFactor, SingleInputMixin):
      """
      Max Drawdown over a window
      """
      ctx = ignore_nanwarnings()
  
      def compute(self, today, assets, out, data):
          drawdowns = fmax.accumulate(data, axis=0) - data
          drawdowns[isnan(drawdowns)] = NINF
          drawdown_ends = nanargmax(drawdowns, axis=0)
  
          # TODO: Accelerate this loop in Cython or Numba.
          for i, end in enumerate(drawdown_ends):
              peak = nanmax(data[:end + 1, i])
              out[i] = (peak - data[end, i]) / data[end, i]
  
new_contents: """
  Technical Analysis Factors
  --------------------------
  """
  from bottleneck import (
      nanargmax,
      nanmax,
      nanmean,
      nansum,
  )
  from numpy import (
      clip,
      diff,
      fmax,
      inf,
      isnan,
      NINF,
  )
  from numexpr import evaluate
  
  from zipline.pipeline.data import USEquityPricing
  from zipline.pipeline.term import SingleInputMixin
  from zipline.utils.control_flow import ignore_nanwarnings
  from .factor import CustomFactor
  
  
  class RSI(CustomFactor, SingleInputMixin):
      """
      Relative Strength Index
  
      **Default Inputs**: [USEquityPricing.close]
  
      **Default Window Length**: 14
      """
      window_length = 14
      inputs = (USEquityPricing.close,)
  
      def compute(self, today, assets, out, closes):
          diffs = diff(closes)
          ups = nanmean(clip(diffs, 0, inf), axis=0)
          downs = nanmean(clip(diffs, -inf, 0), axis=0)
          return evaluate(
              "100 - (100 / (1 + (ups / downs)))",
              locals_dict={'ups': ups, 'downs': downs},
              globals_dict={},
              out=out,
          )
  
  
  class SimpleMovingAverage(CustomFactor, SingleInputMixin):
      """
      Average Value of an arbitrary column
  
      **Default Inputs**: None
  
      **Default Window Length**: None
      """
      # numpy's nan functions throw warnings when passed an array containing only
      # nans, but they still returns the desired value (nan), so we ignore the
      # warning.
      ctx = ignore_nanwarnings()
  
      def compute(self, today, assets, out, data):
          out[:] = nanmean(data, axis=0)
  
  
  class WeightedAverageValue(CustomFactor):
      """
      Helper for VWAP-like computations.
  
      **Default Inputs:** None
  
      **Default Window Length:** None
      """
      def compute(self, today, assets, out, base, weight):
          out[:] = nansum(base * weight, axis=0) / nansum(weight, axis=0)
  
  
  class VWAP(WeightedAverageValue):
      """
      Volume Weighted Average Price
  
      **Default Inputs:** [USEquityPricing.close, USEquityPricing.volume]
  
      **Default Window Length:** None
      """
      inputs = (USEquityPricing.close, USEquityPricing.volume)
  
  
  class MaxDrawdown(CustomFactor, SingleInputMixin):
      """
      Max Drawdown
  
      **Default Inputs:** None
  
      **Default Window Length:** None
      """
      ctx = ignore_nanwarnings()
  
      def compute(self, today, assets, out, data):
          drawdowns = fmax.accumulate(data, axis=0) - data
          drawdowns[isnan(drawdowns)] = NINF
          drawdown_ends = nanargmax(drawdowns, axis=0)
  
          # TODO: Accelerate this loop in Cython or Numba.
          for i, end in enumerate(drawdown_ends):
              peak = nanmax(data[:end + 1, i])
              out[i] = (peak - data[end, i]) / data[end, i]
  
subject: Update docstrings for built-in factors.