text: #
  # Copyright 2013 Quantopian, Inc.
  #
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  #
  #     http://www.apache.org/licenses/LICENSE-2.0
  #
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  
  from collections import defaultdict
  
  from zipline.errors import WrongDataForTransform
  from zipline.transforms.utils import EventWindow, TransformMeta
  
  
  class MovingVWAP(object):
      """
      Class that maintains a dictionary from sids to VWAPEventWindows.
      """
      __metaclass__ = TransformMeta
  
      def __init__(self, market_aware=True, delta=None, window_length=None):
  
          self.market_aware = market_aware
          self.delta = delta
          self.window_length = window_length
  
          # Market-aware mode only works with full-day windows.
          if self.market_aware:
              assert self.window_length and not self.delta,\
                  "Market-aware mode only works with full-day windows."
  
          # Non-market-aware mode requires a timedelta.
          else:
              assert self.delta and not self.window_length, \
                  "Non-market-aware mode requires a timedelta."
  
          # No way to pass arguments to the defaultdict factory, so we
          # need to define a method to generate the correct EventWindows.
          self.sid_windows = defaultdict(self.create_window)
  
      def create_window(self):
          """Factory method for self.sid_windows."""
          return VWAPEventWindow(
              self.market_aware,
              window_length=self.window_length,
              delta=self.delta
          )
  
      def update(self, event):
          """
          Update the event window for this event's sid. Returns the
          current vwap for the sid.
          """
          # This will create a new EventWindow if this is the first
          # message for this sid.
          window = self.sid_windows[event.sid]
          window.update(event)
          return window.get_vwap()
  
  
  class VWAPEventWindow(EventWindow):
      """
      Iteratively maintains a vwap for a single sid over a given
      timedelta.
      """
      def __init__(self, market_aware=True, window_length=None, delta=None):
          EventWindow.__init__(self, market_aware, window_length, delta)
          self.flux = 0.0
          self.totalvolume = 0.0
  
      # Subclass customization for adding new events.
      def handle_add(self, event):
          # Sanity check on the event.
          self.assert_required_fields(event)
          self.flux += event.volume * event.price
          self.totalvolume += event.volume
  
      # Subclass customization for removing expired events.
      def handle_remove(self, event):
          self.flux -= event.volume * event.price
          self.totalvolume -= event.volume
  
      def get_vwap(self):
          """
          Return the calculated vwap for this sid.
          """
          # By convention, vwap is None if we have no events.
          if len(self.ticks) == 0:
              return None
          else:
              return (self.flux / self.totalvolume)
  
      # We need numerical price and volume to calculate a vwap.
      def assert_required_fields(self, event):
          if 'price' not in event or 'volume' not in event:
              raise WrongDataForTransform(
                  transform="VWAPEventWindow",
                  fields=self.fields)
  