def rolling_time_window( self, window_length: int, step: int, func: Callable[[Union["QFDataFrame", np.ndarray]], "QFSeries"]) \ -> Union[None, "QFSeries", "QFDataFrame"]: """ Runs a given function on each rolling window in the dataframe. The content of a rolling window is also a QFDataFrame thus the funciton which should be applied should accept a QFDataFrame as an argument. The function may return either a QFSeries (then the output of rolling_time_window will be QFDataFrame) or a scalar value (then the output of rolling_time_window will be QFSeries). The rolling window is moved along the time index (rows). Parameters ---------- window_length number of rows which should be taken into rolling window step number of rows by which rolling window should be moved func function to apply on each rolling window. If it returns a QFSeries then the output of rolling_time_window() will be a QFDataFrame; if it returns a scalar value, the return value of rolling_time_window() will be a QFSeries Returns ------- None (if the result of running the rolling window was empty) or QFSeries (if the function applied returned scalar value for each window) or QFDataFrame (if the function applied returned QFSeries for each window) """ results_dict = dict() # type: Dict[datetime, pd.Series] end_idx = self.num_of_rows while True: start_idx = end_idx - window_length if start_idx < 0: break patch = self.iloc[start_idx:end_idx, :] end_date = self.index[end_idx - 1] results_dict[end_date] = func(patch) end_idx -= step if not results_dict: return None first_element = next(iter(results_dict.values())) # type: "QFSeries" if isinstance(first_element, pd.Series): result = QFDataFrame.from_dict(results_dict, orient='index') result = cast_dataframe(result, QFDataFrame) else: from qf_lib.containers.series.qf_series import QFSeries dates_and_values = [(date, value) for date, value in results_dict.items()] dates, values = zip(*dates_and_values) result = QFSeries(index=dates, data=values) result = result.sort_index() return result
def _compute_aggregated_volume(self, ticker: FutureTicker, start_date: datetime, end_date: datetime) \ -> Optional[QFSeries]: # Compute the TOTAL VOLUME (aggregated across contracts) futures_chain_tickers_df = self.data_provider.get_futures_chain_tickers( ticker, ExpirationDateField.all_dates())[ticker] # Get the minimum date futures_chain_tickers = futures_chain_tickers_df.min(axis=1) futures_chain_tickers = QFSeries(data=futures_chain_tickers.index, index=futures_chain_tickers.values) futures_chain_tickers.index = to_datetime(futures_chain_tickers.index) futures_chain_tickers = futures_chain_tickers.sort_index() futures_chain_tickers = futures_chain_tickers.loc[start_date:end_date + RelativeDelta( months=6)] all_specific_tickers = futures_chain_tickers.values.tolist() volume_df = self.data_provider.get_price( all_specific_tickers, PriceField.Volume, start_date, end_date, Frequency.DAILY).dropna(axis=1, how="all").fillna(0) return volume_df.sum(axis=1) if not volume_df.empty else None