class_docstr: An FXRateReader backed by HDF5.
  
  Parameters
  ----------
  group : h5py.Group
      Top-level group written by an :class:`HDF5FXRateWriter`.
  default_rate : str
      Rate to use when ``get_rates`` is called requesting the default rate.
docstr: Get rates to convert ``bases`` into ``quote``.
  
  See :class:`zipline.data.fx.base.FXRateReader` for details.
docstr_tok: ["Get","rates","to","convert","``","bases","``","into","``","quote","``",".","See",":","class",":","`","zipline.data.fx.base.FXRateReader","`","for","details","."]
code: def get_rates(self, rate, quote, bases, dts):
      """Get rates to convert ``bases`` into ``quote``.
  
      See :class:`zipline.data.fx.base.FXRateReader` for details.
      """
      if rate == DEFAULT_FX_RATE:
          rate = self._default_rate
  
      check_dts(dts)
  
      col_ixs = self.dts.searchsorted(dts, side="right") - 1
      row_ixs = self.currencies.get_indexer(bases)
  
      try:
          dataset = self._group[DATA][rate][quote][RATES]
      except KeyError:
          raise ValueError(
              "FX rates not available for rate={}, quote_currency={}.".format(
                  rate, quote
              )
          )
  
      # OPTIMIZATION: Column indices correspond to dates, which must be in
      # sorted order. Rather than reading the entire dataset from h5, we can
      # read just the interval from min_col to max_col inclusive
      #
      # However, we also need to handle two important edge cases:
      #
      #   1. row_ixs contains -1 for any currencies we don't know about.
      #   2. col_ixs contains -1 for dts before the start of self.dts.
      #
      # If either of the above cases obtains, we want to return NaN for the
      # corresponding output locations.
  
      # We handle each of these cases by reading raw data into a buffer with
      # one extra column and one extra row. When we then permute the raw data
      # into the correct order, any row or column indices with values of -1
      # will pull from the extra row/column, which will always contain NaN.
  
      slice_begin = max(col_ixs[0], 0)
      slice_end = (
          max(col_ixs[-1], 0) + 1
      )  # +1 to be inclusive of end date.
  
      # Allocate a buffer full of NaNs with one extra column and row. See
      # OPTIMIZATION notes above.
      buf = np.full(
          (len(self.currencies) + 1, slice_end - slice_begin + 1),
          np.nan,
      )
  
      buf[:-1, :-1] = dataset[:, slice_begin:slice_end]
  
      # Permute the rows into place, pulling from the empty NaN locations for
      # row and column indices of -1.
      out = buf[:, col_ixs - slice_begin][row_ixs]
  
      # Transpose everything to maintain dts as row labels, currencies as col
      # labels which is expected everywhere else.
      return out.transpose()
  
imports: from interface import implements
  import h5py
  from logbook import Logger
  import numpy
  import pandas
  from zipline.utils.memoize import lazyval
  from zipline.utils.numpy_utils import bytes_array_to_native_str_object_array
  from .base import FXRateReader, DEFAULT_FX_RATE
  from .utils import check_dts, is_sorted_ascending
label_desc: Use image node_id 6 for calling the HDF5FXRateReader obj's underlying member method code with example usage: obj.get_rates(rate, quote, bases, dts) and returns: out