def _get_single_date_price( self, tickers: Union[Ticker, Sequence[Ticker]], nans_allowed: bool, frequency: Frequency = Frequency.DAILY) \ -> Union[float, QFSeries]: tickers, was_single_ticker_provided = convert_to_list(tickers, Ticker) # if an empty tickers list was supplied then return an empty result if not tickers: return QFSeries() # Compute the time ranges, used further by the get_price function current_datetime = self.timer.now() # We download the prices since the last 7 days. In case of getting the last available price, we assume that # within each 7 consecutive days, at least one price will occur. If not, in case e.g. future contracts, we # assume that the contract ended and we need to e.g. close the position for this ticker in the portfolio, if # open. start_date = current_datetime - RelativeDelta(days=7) current_date = self._zero_out_time_component(current_datetime) price_fields = [PriceField.Open, PriceField.Close] prices_data_array = self.data_provider.get_price( tickers, price_fields, start_date, current_date, frequency) prices_df = self._data_array_to_dataframe(prices_data_array) prices_df = prices_df.loc[:current_datetime] try: prices_series = prices_df.loc[current_datetime, :] except KeyError: prices_series = QFSeries(index=tickers) prices_series.name = "Current asset prices" if not nans_allowed: # fill NaNs with latest available prices last_available_close_prices = prices_df.apply( func=lambda series: series.asof(current_datetime)) if not last_available_close_prices.empty: unavailable_prices_tickers = prices_series.isnull() prices_series.loc[unavailable_prices_tickers] = \ last_available_close_prices.loc[unavailable_prices_tickers] prices_series.name = "Last available asset prices" prices_series = cast_series(prices_series, QFSeries) if was_single_ticker_provided: return prices_series[0] else: return prices_series
def _get_current_prices(self, tickers: Sequence[Ticker]): """ Function used to obtain the current prices for the tickers in order to further calculate fill prices for orders. The function uses data provider and not data handler, as it is necessary to get the current bar at each point in time to compute the fill prices. """ if not tickers: return QFSeries() assert self._frequency >= Frequency.DAILY, "Lower than daily frequency is not supported by the simulated" \ " executor" # Compute the time ranges, used further by the get_price function current_datetime = self._timer.now() market_close_time = current_datetime + MarketCloseEvent.trigger_time( ) == current_datetime market_open_time = current_datetime + MarketOpenEvent.trigger_time( ) == current_datetime # In case of daily frequency, current price may be returned only at the Market Open or Market Close time if self._frequency == Frequency.DAILY and not (market_open_time or market_close_time): return QFSeries(index=tickers) if self._frequency == Frequency.DAILY: # Remove the time part from the datetime in case of daily frequency current_datetime = date_to_datetime(current_datetime.date()) start_time_range = current_datetime - self._frequency.time_delta() end_time_range = current_datetime elif market_close_time: # At the market close, in order to get the current price we need to take a bar that ends at the current time # and use the close price value start_time_range = current_datetime - self._frequency.time_delta() end_time_range = current_datetime current_datetime = start_time_range else: # At any other time during the day, in order to get the current price we need to take the bar that starts at # the current time and use the open price value start_time_range = current_datetime end_time_range = current_datetime + self._frequency.time_delta() price_field = PriceField.Close if market_close_time else PriceField.Open prices_df = self._data_provider.get_price(tickers, price_field, start_time_range, end_time_range, self._frequency) try: prices_series = prices_df.loc[current_datetime] except KeyError: prices_series = QFSeries(index=tickers) prices_series.name = "Current prices series" return prices_series
def _get_single(haver_ticker, start_date: datetime, end_date) -> QFSeries: if start_date is not None: start_date = start_date.date() if end_date is not None: end_date = end_date.date() ticker_str = [haver_ticker.database_name + ':' + haver_ticker.ticker] raw_series = Haver.data(ticker_str, startdate=start_date, enddate=end_date) if isinstance(raw_series, DataFrame): if isinstance(raw_series.index, PeriodIndex): raw_series.index = raw_series.index.to_timestamp() result = QFSeries(raw_series.iloc[:, 0]) else: result = QFSeries() result.name = haver_ticker.as_string() return result
def get_current_price( self, tickers: Union[Ticker, Sequence[Ticker]], frequency: Frequency = None) -> Union[float, QFSeries]: """ Works just like get_last_available_price() but it can return NaNs if data is not available at the current moment (e.g. it returns NaN on a non-trading day). The frequency parameter is always casted into 1 minute frequency, to represent the most recent price. If the frequency parameter is an intraday frequency, the CLOSE price of the currently available bar will be returned. E.g. for 1 minute frequency, at 13:00 (if the market opens before 13:00), the CLOSE price of the 12:59 - 13:00 bar will be returned. If "now" contains non-zero seconds or microseconds, None will be returned. Parameters ----------- tickers: Ticker, Sequence[Ticker] tickers of the securities which prices should be downloaded frequency: Frequency frequency of the data Returns ------- float, QFSeries current_prices series where: - current_prices.name contains a date of current prices, - current_prices.index contains tickers - current_prices.data contains latest available prices for given tickers """ frequency = frequency or self.fixed_data_provider_frequency or Frequency.MIN_1 if frequency <= Frequency.DAILY: raise ValueError( "The Intraday Data Handler can be used only with the Intraday Frequency" ) tickers, was_single_ticker_provided = convert_to_list(tickers, Ticker) # if an empty tickers list was supplied then return an empty result if not tickers: return QFSeries() current_datetime = self.timer.now() # Check if the current time is at the market open, if so - take the Open price of the time range, starting # at current datetime if current_datetime + MarketOpenEvent.trigger_time( ) == current_datetime: time_range_start = current_datetime field = PriceField.Open else: time_range_start = current_datetime - frequency.time_delta() field = PriceField.Close prices_data_array = self.data_provider.get_price( tickers, field, time_range_start, time_range_start + frequency.time_delta(), frequency) try: # Below, the loc[time_range_start] is used instead of iloc[0], in order to return the price exactly from the # time_range_start, and not from the range between time_range_start and time_range_start + # frequency.time_delta() prices_series = prices_data_array.loc[time_range_start] except KeyError: prices_series = QFSeries(index=tickers) prices_series.name = "Current asset prices" prices_series = cast_series(prices_series, QFSeries) if was_single_ticker_provided: return prices_series[0] else: return prices_series