class_docstr: The VolumeRollFinder calculates contract rolls based on when
  volume activity transfers from one contract to another.
class_docstr_tok: ["The","VolumeRollFinder","calculates","contract","rolls","based","on","when","volume","activity","transfers","from","one","contract","to","another","."]
docstr: Return the active contract based on the previous trading day's volume.
  
  In the rare case that a double volume switch occurs we treat the first
  switch as the roll. Take the following case for example:
  
  | +++++             _____
  |      +   __      /       <--- 'G'
  |       ++/++\++++/++
  |       _/    \__/   +
  |      /              +
  | ____/                +   <--- 'F'
  |_________|__|___|________
            a  b   c         <--- Switches
  
  We should treat 'a' as the roll date rather than 'c' because from the
  perspective of 'a', if a switch happens and we are pretty close to the
  auto-close date, we would probably assume it is time to roll. This
  means that for every date after 'a', `data.current(cf, 'contract')`
  should return the 'G' contract.
docstr_tok: ["Return","the","active","contract","based","on","the","previous","trading","day","'s","volume",".","In","the","rare","case","that","a","double","volume","switch","occurs","we","treat","the","first","switch","as","the","roll",".","Take","the","following","case","for","example",":","|","+++++","_____","|","+","__","\/","<","--","-","'","G'","|","++\/++\\++++\/++","|","_\/","\\__\/","+","|","\/","+","|","____\/","+","<","--","-","'","F'","|_________|__|___|________","a","b","c","<","--","-","Switches","We","should","treat","'","a","'","as","the","roll","date","rather","than","'","c","'","because","from","the","perspective","of","'","a","'",",","if","a","switch","happens","and","we","are","pretty","close","to","the","auto-close","date",",","we","would","probably","assume","it","is","time","to","roll",".","This","means","that","for","every","date","after","'","a","'",",","`","data.current","(","cf",",","'contract","'",")","`","should","return","the","'","G","'","contract","."]
code: def _active_contract(self, oc, front, back, dt):
      r"""
      Return the active contract based on the previous trading day's volume.
  
      In the rare case that a double volume switch occurs we treat the first
      switch as the roll. Take the following case for example:
  
      | +++++             _____
      |      +   __      /       <--- 'G'
      |       ++/++\++++/++
      |       _/    \__/   +
      |      /              +
      | ____/                +   <--- 'F'
      |_________|__|___|________
                a  b   c         <--- Switches
  
      We should treat 'a' as the roll date rather than 'c' because from the
      perspective of 'a', if a switch happens and we are pretty close to the
      auto-close date, we would probably assume it is time to roll. This
      means that for every date after 'a', `data.current(cf, 'contract')`
      should return the 'G' contract.
      """
      front_contract = oc.sid_to_contract[front].contract
      back_contract = oc.sid_to_contract[back].contract
  
      tc = self.trading_calendar
      trading_day = tc.day
      prev = dt - trading_day
      get_value = self.session_reader.get_value
  
      # If the front contract is past its auto close date it cannot be the
      # active contract, so return the back contract. Similarly, if the back
      # contract has not even started yet, just return the front contract.
      # The reason for using 'prev' to see if the contracts are alive instead
      # of using 'dt' is because we need to get each contract's volume on the
      # previous day, so we need to make sure that each contract exists on
      # 'prev' in order to call 'get_value' below.
      if dt > min(
          front_contract.auto_close_date, front_contract.end_date
      ):
          return back
      elif front_contract.start_date > prev:
          return back
      elif dt > min(
          back_contract.auto_close_date, back_contract.end_date
      ):
          return front
      elif back_contract.start_date > prev:
          return front
  
      front_vol = get_value(front, prev, "volume")
      back_vol = get_value(back, prev, "volume")
      if back_vol > front_vol:
          return back
  
      gap_start = max(
          back_contract.start_date,
          front_contract.auto_close_date
          - (trading_day * self.GRACE_DAYS),
      )
      gap_end = prev - trading_day
      if dt < gap_start:
          return front
  
      # If we are within `self.GRACE_DAYS` of the front contract's auto close
      # date, and a volume flip happened during that period, return the back
      # contract as the active one.
      sessions = tc.sessions_in_range(
          tc.minute_to_session_label(gap_start),
          tc.minute_to_session_label(gap_end),
      )
      for session in sessions:
          front_vol = get_value(front, session, "volume")
          back_vol = get_value(back, session, "volume")
          if back_vol > front_vol:
              return back
      return front
  
file_path: zipline/zipline/assets/roll_finder.py
imports: from abc import ABCMeta, abstractmethod
  from six import with_metaclass
label_desc: Use image node_id 2 for calling the VolumeRollFinder obj's underlying member method code with example usage: obj._active_contract(oc, front, back, dt) and returns: front, back, back, front, back, back, front, front