Ensure that there is a Float64Multiply window for each asset that can
        provide data for the given parameters.
        If the corresponding window for the (assets, len(dts), field) does not
        exist, then create a new one.
        If a corresponding window does exist for (assets, len(dts), field), but
        can not provide data for the current dts range, then create a new
        one and replace the expired window.

        Parameters
        ----------
        assets : iterable of Assets
            The assets in the window
        dts : iterable of datetime64-like
            The datetimes for which to fetch data.
            Makes an assumption that all dts are present and contiguous,
            in the calendar.
        field : str
            The OHLCV field for which to retrieve data.
        is_perspective_after : bool
            see: `PricingHistoryLoader.history`

        Returns
        -------
        out : list of Float64Window with sufficient data so that each asset's
        window can provide `get` for the index corresponding with the last
        value in `dts`

def _ensure_sliding_windows(self, assets, dts, field,
                                is_perspective_after):
        """
        Ensure that there is a Float64Multiply window for each asset that can
        provide data for the given parameters.
        If the corresponding window for the (assets, len(dts), field) does not
        exist, then create a new one.
        If a corresponding window does exist for (assets, len(dts), field), but
        can not provide data for the current dts range, then create a new
        one and replace the expired window.

        Parameters
        ----------
        assets : iterable of Assets
            The assets in the window
        dts : iterable of datetime64-like
            The datetimes for which to fetch data.
            Makes an assumption that all dts are present and contiguous,
            in the calendar.
        field : str
            The OHLCV field for which to retrieve data.
        is_perspective_after : bool
            see: `PricingHistoryLoader.history`

        Returns
        -------
        out : list of Float64Window with sufficient data so that each asset's
        window can provide `get` for the index corresponding with the last
        value in `dts`
        """
        end = dts[-1]
        size = len(dts)
        asset_windows = {}
        needed_assets = []
        cal = self._calendar

        assets = self._asset_finder.retrieve_all(assets)
        end_ix = find_in_sorted_index(cal, end)

        for asset in assets:
            try:
                window = self._window_blocks[field].get(
                    (asset, size, is_perspective_after), end)
            except KeyError:
                needed_assets.append(asset)
            else:
                if end_ix < window.most_recent_ix:
                    # Window needs reset. Requested end index occurs before the
                    # end index from the previous history call for this window.
                    # Grab new window instead of rewinding adjustments.
                    needed_assets.append(asset)
                else:
                    asset_windows[asset] = window

        if needed_assets:
            offset = 0
            start_ix = find_in_sorted_index(cal, dts[0])

            prefetch_end_ix = min(end_ix + self._prefetch_length, len(cal) - 1)
            prefetch_end = cal[prefetch_end_ix]
            prefetch_dts = cal[start_ix:prefetch_end_ix + 1]
            if is_perspective_after:
                adj_end_ix = min(prefetch_end_ix + 1, len(cal) - 1)
                adj_dts = cal[start_ix:adj_end_ix + 1]
            else:
                adj_dts = prefetch_dts
            prefetch_len = len(prefetch_dts)
            array = self._array(prefetch_dts, needed_assets, field)

            if field == 'sid':
                window_type = Int64Window
            else:
                window_type = Float64Window

            view_kwargs = {}
            if field == 'volume':
                array = array.astype(float64_dtype)

            for i, asset in enumerate(needed_assets):
                adj_reader = None
                try:
                    adj_reader = self._adjustment_readers[type(asset)]
                except KeyError:
                    adj_reader = None
                if adj_reader is not None:
                    adjs = adj_reader.load_pricing_adjustments(
                        [field], adj_dts, [asset])[0]
                else:
                    adjs = {}
                window = window_type(
                    array[:, i].reshape(prefetch_len, 1),
                    view_kwargs,
                    adjs,
                    offset,
                    size,
                    int(is_perspective_after),
                    self._decimal_places_for_asset(asset, dts[-1]),
                )
                sliding_window = SlidingWindow(window, size, start_ix, offset)
                asset_windows[asset] = sliding_window
                self._window_blocks[field].set(
                    (asset, size, is_perspective_after),
                    sliding_window,
                    prefetch_end)

        return [asset_windows[asset] for asset in assets]