Пример #1
0
    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
Пример #2
0
    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
Пример #3
0
    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
Пример #4
0
    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