Exemplo n.º 1
0
    def _data_array_to_dataframe(self, prices_data_array: QFDataArray,
                                 frequency: Frequency):
        """
        Converts a QFDataArray into a DataFrame by removing the "Price Field" axis.

        Every index (e.g. 15:00) denotes the close price of the time range beginning at this time (15:00 - 15:01)
        The only exception is the time range 1 minute before market open (e.g. 9:29 - 9:30 if market opens 9:30). The
        price for this time range, denotes the OPEN price of 9:30 - 9:31.
        """
        original_dates = list(prices_data_array.dates.to_index())
        dates = prices_data_array.resample(dates='1D').first().dates.to_index()
        market_open_datetimes = [
            price_datetime + MarketOpenEvent.trigger_time()
            for price_datetime in dates if price_datetime +
            MarketOpenEvent.trigger_time() in original_dates
        ]
        shifted_open_datetimes = [
            price_datetime - frequency.time_delta()
            for price_datetime in market_open_datetimes
        ]

        new_dates = list(set(original_dates + shifted_open_datetimes))
        new_dates = sorted(new_dates)
        prices_df = PricesDataFrame(index=new_dates,
                                    columns=prices_data_array.tickers)

        prices_df.loc[shifted_open_datetimes, :] = \
            prices_data_array.loc[market_open_datetimes, :, PriceField.Open].values
        prices_df.loc[original_dates, :] = prices_data_array.loc[
            original_dates, :, PriceField.Close].values

        return prices_df
Exemplo n.º 2
0
    def test_get_last_price_single_ticker(self):
        # just test if getting single ticker value works, when a single ticker (not wrapped in a list) is passed
        self.timer.set_current_time(
            str_to_date("2018-01-31") + MarketOpenEvent.trigger_time() +
            RelativeDelta(hours=1))
        single_price = self.data_handler.get_last_available_price(
            self.spx_index_ticker)
        self.assertTrue(isinstance(single_price, float))

        # at market open
        self.timer.set_current_time(
            str_to_date("2018-01-31") + MarketOpenEvent.trigger_time())
        at_market_open = self.data_handler.get_last_available_price(
            [self.spx_index_ticker])

        self.assertEqual(self.spx_index_ticker, at_market_open.index[0])
        self.assertEqual(single_price, at_market_open[0])

        # during the trading session
        self.timer.set_current_time(
            str_to_date("2018-01-31") + MarketOpenEvent.trigger_time() +
            RelativeDelta(hours=1))
        during_the_day_last_prices = self.data_handler.get_last_available_price(
            [self.spx_index_ticker])

        self.assertEqual(self.spx_index_ticker,
                         during_the_day_last_prices.index[0])
        self.assertEqual(single_price, during_the_day_last_prices[0])

        # after the trading session
        self.timer.set_current_time(
            str_to_date("2018-01-31") + MarketCloseEvent.trigger_time() +
            RelativeDelta(hours=1))
        after_close_last_prices = self.data_handler.get_last_available_price(
            [self.spx_index_ticker])

        self.assertEqual(self.spx_index_ticker,
                         after_close_last_prices.index[0])
        self.assertNotEqual(during_the_day_last_prices[0],
                            after_close_last_prices[0])

        # before the trading session
        self.timer.set_current_time(
            str_to_date("2018-01-31") + MarketOpenEvent.trigger_time() -
            RelativeDelta(hours=1))
        before_trading_session_prices = self.data_handler.get_last_available_price(
            [self.spx_index_ticker])

        self.assertEqual(self.spx_index_ticker,
                         before_trading_session_prices.index[0])
        self.assertNotEqual(during_the_day_last_prices[0],
                            before_trading_session_prices[0])
        self.assertNotEqual(after_close_last_prices[0],
                            before_trading_session_prices[0])
Exemplo n.º 3
0
    def test_get_open_price_when_end_date_is_today_before_market_close__multiple_tickers(
            self):
        self.timer.set_current_time(
            str_to_date("2018-01-31") + MarketOpenEvent.trigger_time() +
            RelativeDelta(hours=1))
        current_date = datetime(self.timer.now().year,
                                self.timer.now().month,
                                self.timer.now().day)

        tickers = [self.spx_index_ticker, self.microsoft_ticker]
        open_prices_tms = self.data_handler.get_price(tickers, PriceField.Open,
                                                      self.start_date,
                                                      self.timer.now())

        self.assertEqual(self.start_date,
                         open_prices_tms.index[0].to_pydatetime())
        self.assertEqual(current_date,
                         open_prices_tms.index[-1].to_pydatetime())

        prices_data_array = self.data_handler.get_price(
            tickers, [PriceField.Open, PriceField.Close], self.start_date,
            self.timer.now())
        last_bar_df = prices_data_array.loc[current_date, :, :].to_pandas()

        self.assertTrue(last_bar_df[PriceField.Close].isna().all())
        self.assertTrue(last_bar_df[PriceField.Open].notna().all())
Exemplo n.º 4
0
    def _get_prices_df(self, ticker: Ticker, start_date: datetime, end_date: datetime) -> PricesDataFrame:
        """ Returns non-adjusted open and close prices, indexed with the Market Open and Market Close time."""
        if isinstance(ticker, FutureTicker):
            ticker.initialize_data_provider(SettableTimer(end_date), self._data_provider)
            tickers_chain = ticker.get_expiration_dates()

            if start_date >= tickers_chain.index[-1] or end_date <= tickers_chain.index[0]:
                # If the futures chain starts after the _end_date or ends before the _start_date - no data available
                return PricesDataFrame()

            # Get all tickers from the chain that were valid between the start_date and expiration date of the
            # currently valid ticker
            end_date = tickers_chain[tickers_chain == ticker.get_current_specific_ticker()].index[0]
            tickers_chain = tickers_chain.loc[start_date:end_date]
            tickers = tickers_chain.values.tolist()

            open_prices = self._data_provider.get_price(tickers, PriceField.Open, start_date, end_date)
            close_prices = self._data_provider.get_price(tickers, PriceField.Close, start_date, end_date)
        else:
            open_prices = self._data_provider.get_price([ticker], PriceField.Open, start_date, end_date)
            close_prices = self._data_provider.get_price([ticker], PriceField.Close, start_date, end_date)

        open_prices.index = [dt + MarketOpenEvent.trigger_time() for dt in open_prices.index]
        close_prices.index = [dt + MarketCloseEvent.trigger_time() for dt in close_prices.index]
        prices = concat([open_prices, close_prices]).sort_index()
        return prices
Exemplo n.º 5
0
    def test_no_orders_executed_on_market_open(self):
        # Move before the market open event
        self._set_bar_for_today(open_price=105.0,
                                high_price=110.0,
                                low_price=100.0,
                                close_price=105.0,
                                volume=100000000.0)
        self.timer.set_current_time(self.timer.now() +
                                    MarketOpenEvent.trigger_time() -
                                    RelativeDelta(
                                        minutes=self.number_of_minutes))
        self.exec_handler.assign_order_ids([
            self.stop_loss_order_1, self.stop_loss_order_2,
            self.stop_loss_order_3
        ])
        # Trigger the order execution event (the function also forwards time into the future)
        self._trigger_single_time_event()
        self.exec_handler.on_market_open(...)

        self.portfolio.transact_transaction.assert_not_called()
        self.monitor.record_transaction.assert_not_called()

        actual_orders = self.exec_handler.get_open_orders()
        expected_orders = [
            self.stop_loss_order_1, self.stop_loss_order_2,
            self.stop_loss_order_3
        ]
        assert_lists_equal(expected_orders, actual_orders)
Exemplo n.º 6
0
    def _data_array_to_dataframe(self, prices_data_array: QFDataArray):
        """
        Converts a QFDataArray into a DataFrame by removing the "Price Field" axis.

        In order to remove it open and close prices get different time component in their corresponding datetimes
        (open prices will get the time of `MarketOpenEvent` and close prices will get the time of `MarketCloseEvent`).
        """
        original_dates = prices_data_array.dates.to_index()

        market_open_datetimes = [
            price_datetime + MarketOpenEvent.trigger_time()
            for price_datetime in original_dates
        ]
        market_close_datetimes = [
            price_datetime + MarketCloseEvent.trigger_time()
            for price_datetime in original_dates
        ]

        new_dates = set(market_open_datetimes + market_close_datetimes)

        prices_df = PricesDataFrame(index=new_dates,
                                    columns=prices_data_array.tickers)
        prices_df.loc[
            market_open_datetimes, :] = prices_data_array.loc[:, :, PriceField.
                                                              Open].values
        prices_df.loc[
            market_close_datetimes, :] = prices_data_array.loc[:, :,
                                                               PriceField.
                                                               Close].values

        prices_df.sort_index(inplace=True)
        return prices_df
Exemplo n.º 7
0
    def test_get_open_price_when_end_date_is_today_before_market_close__single_ticker(
            self):
        self.timer.set_current_time(
            str_to_date("2018-01-31") + MarketOpenEvent.trigger_time() +
            RelativeDelta(hours=1))
        current_date = datetime(self.timer.now().year,
                                self.timer.now().month,
                                self.timer.now().day)
        open_prices_tms = self.data_handler.get_price(self.spx_index_ticker,
                                                      PriceField.Open,
                                                      self.start_date,
                                                      self.timer.now())

        self.assertEqual(self.start_date,
                         open_prices_tms.index[0].to_pydatetime())
        self.assertEqual(current_date,
                         open_prices_tms.index[-1].to_pydatetime())

        prices_df = self.data_handler.get_price(
            self.spx_index_ticker, [PriceField.Open, PriceField.Close],
            self.start_date, self.timer.now())
        self.assertEqual(self.start_date, prices_df.index[0].to_pydatetime())
        self.assertEqual(current_date, prices_df.index[-1].to_pydatetime())

        last_bar = prices_df.iloc[-1]
        self.assertTrue(isnan(last_bar.loc[PriceField.Close]))
        self.assertIsNotNone(last_bar.loc[PriceField.Open])
Exemplo n.º 8
0
    def test_historical_price_many_tickers_one_field(self):
        self.timer.set_current_time(
            str_to_date("2018-01-04") + MarketOpenEvent.trigger_time() +
            RelativeDelta(hours=1))
        result_df = self.data_handler.historical_price([self.microsoft_ticker],
                                                       PriceField.Open,
                                                       nr_of_bars=5)

        self.assertEqual(PricesDataFrame, type(result_df))

        expected_dates_idx = pd.DatetimeIndex([
            '2017-12-27', '2017-12-28', '2017-12-29', '2018-01-02',
            '2018-01-03'
        ],
                                              name=DATES)
        assert_same_index(expected_dates_idx,
                          result_df.index,
                          check_index_type=True,
                          check_names=True)

        expected_tickers_idx = pd.Index([self.microsoft_ticker], name=TICKERS)
        assert_same_index(expected_tickers_idx,
                          result_df.columns,
                          check_index_type=True,
                          check_names=True)
    def _make_mock_data_array(self, tickers, fields):
        all_dates_market_open = pd.date_range(
            start=self.data_start_date + MarketOpenEvent.trigger_time(),
            end=self.data_end_date + MarketOpenEvent.trigger_time(),
            freq="B")
        all_dates_market_close = pd.date_range(
            start=self.data_start_date + MarketCloseEvent.trigger_time() -
            Frequency.MIN_1.time_delta(),
            end=self.data_end_date + MarketCloseEvent.trigger_time() -
            Frequency.MIN_1.time_delta(),
            freq="B")

        num_of_dates = len(all_dates_market_open)
        num_of_tickers = len(tickers)
        num_of_fields = len(fields)

        start_value = 100.0
        values = np.arange(
            start_value,
            num_of_dates * num_of_tickers * num_of_fields + start_value)
        reshaped_values = np.reshape(
            values, (num_of_dates, num_of_tickers, num_of_fields))

        mocked_result_market_open = QFDataArray.create(all_dates_market_open,
                                                       tickers,
                                                       fields,
                                                       data=reshaped_values)

        mocked_result_market_close = QFDataArray.create(all_dates_market_close,
                                                        tickers,
                                                        fields,
                                                        data=reshaped_values)
        mocked_result_market_close.loc[:, :, PriceField.Low] -= 5.0
        mocked_result_market_close.loc[:, :, PriceField.High] += 5.0

        all_dates = all_dates_market_open.union(all_dates_market_close)

        mocked_result = QFDataArray.create(all_dates, tickers, fields)
        mocked_result.loc[
            all_dates_market_open, :, :] = mocked_result_market_open.loc[:, :, :]
        mocked_result.loc[
            all_dates_market_close, :, :] = mocked_result_market_close.loc[:, :, :]

        self._add_test_cases(mocked_result, tickers)
        return mocked_result
Exemplo n.º 10
0
    def test_get_last_price_with_multiple_tickers_when_current_data_is_unavailable(
            self):
        self.timer.set_current_time(
            str_to_date("2018-01-01") + MarketOpenEvent.trigger_time() +
            RelativeDelta(hours=1))
        last_prices = self.data_handler.get_last_available_price(
            [self.spx_index_ticker, self.google_ticker])

        self.assertEqual(self.spx_index_ticker, last_prices.index[0])
        self.assertEqual(self.google_ticker, last_prices.index[1])
Exemplo n.º 11
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
Exemplo n.º 12
0
    def test_get_history_when_end_date_is_today_before_market_close(self):
        self.timer.set_current_time(
            str_to_date("2018-01-31") + MarketOpenEvent.trigger_time() +
            RelativeDelta(hours=1))
        prices_tms = self.data_handler.get_history(self.spx_index_ticker,
                                                   self.get_history_field,
                                                   self.start_date,
                                                   self.end_date)

        self.assertEqual(self.start_date, prices_tms.index[0].to_pydatetime())
        self.assertEqual(self.end_date_trimmed,
                         prices_tms.index[-1].to_pydatetime())
Exemplo n.º 13
0
    def test_get_history_with_multiple_tickers(self):
        self.timer.set_current_time(
            str_to_date("2018-01-31") + MarketOpenEvent.trigger_time() +
            RelativeDelta(hours=1))
        resilt_df = self.data_handler.get_history(
            [self.microsoft_ticker, self.google_ticker],
            self.get_history_field, self.start_date, self.end_date_trimmed)

        self.assertEqual(self.microsoft_ticker, resilt_df.columns[0])
        self.assertEqual(self.google_ticker, resilt_df.columns[1])
        self.assertEqual(self.start_date, resilt_df.index[0].to_pydatetime())
        self.assertEqual(self.end_date_trimmed,
                         resilt_df.index[-1].to_pydatetime())
        self.assertEqual(resilt_df.shape, (20, 2))
Exemplo n.º 14
0
    def _filter_transactions(self, ticker: Ticker, transactions: List[Transaction], start_date: datetime,
                             end_date: datetime) -> QFSeries:
        """ Filters out transactions, which do not correspond to the given ticker and returns a QFSeries of remaining
        transactions. Only transactions between start_date market open and end_date market close are considered. """
        transactions = [t for t in transactions if start_date + MarketOpenEvent.trigger_time()
                        <= t.time <= end_date + MarketCloseEvent.trigger_time()]

        if isinstance(ticker, FutureTicker):
            transactions_for_tickers = [t for t in transactions if ticker.belongs_to_family(t.ticker)]
        else:
            transactions_for_tickers = [t for t in transactions if ticker == t.ticker]

        transactions_records = [(t, t.time) for t in transactions_for_tickers]
        transactions_series = QFDataFrame.from_records(transactions_records, columns=["Transaction", "Index"]) \
            .set_index("Index").iloc[:, 0]
        return transactions_series
Exemplo n.º 15
0
    def _aggregate_intraday_data(self, data_array, start_date: datetime,
                                 end_date: datetime, tickers: Sequence[Ticker],
                                 fields, frequency: Frequency):
        """
        Function, which aggregates the intraday data array for various dates and returns a new data array with data
        sampled with the given frequency.
        """

        # If the data is of intraday data type, which spans over multiple days, the base parameter of resample()
        # function should be adjusted differently for the first day.
        #
        # Therefore, the data array is divided into two separate arrays data_array_1, data_array_2 - first containing
        # only the first day, and the second one - containing all other dates.

        end_of_day = start_date + RelativeDelta(hour=23, minute=59, second=59)
        _end_date = end_of_day if (end_of_day < end_date) else end_date

        # Get both parts of the data array
        data_array_1 = data_array.loc[start_date:_end_date, :, :]
        data_array_2 = data_array.loc[end_of_day:end_date, :, :]

        if len(data_array_1) > 0:
            base_data_array_1 = pd.to_datetime(
                data_array_1[DATES].values[0]).minute
            data_array_1 = data_array_1.resample(
                dates=frequency.to_pandas_freq(),
                base=base_data_array_1,
                label='left',
                skipna=True).apply(
                    lambda x: self._aggregate_data_array(x, tickers, fields))

        if len(data_array_2) > 0:
            base_data_array_2 = MarketOpenEvent.trigger_time().minute
            data_array_2 = data_array_2.resample(
                dates=frequency.to_pandas_freq(),
                base=base_data_array_2,
                label='left',
                skipna=True).apply(
                    lambda x: self._aggregate_data_array(x, tickers, fields))

        data_array = QFDataArray.concat([data_array_1, data_array_2],
                                        dim=DATES)

        return data_array
Exemplo n.º 16
0
    def test_historical_price_many_tickers_many_fields(self):
        self.timer.set_current_time(
            str_to_date("2018-01-31") + MarketOpenEvent.trigger_time() +
            RelativeDelta(hours=1))
        result_array = self.data_handler.historical_price(
            [self.microsoft_ticker], [PriceField.Open, PriceField.Close],
            nr_of_bars=5)

        self.assertEqual(QFDataArray, type(result_array))
        self.assertEqual((5, 1, 2), result_array.shape)

        expected_dates_str = [
            "2018-01-24", "2018-01-25", "2018-01-26", "2018-01-29",
            "2018-01-30"
        ]
        expected_dates = [
            str_to_date(date_str) for date_str in expected_dates_str
        ]
        assert_same_index(pd.DatetimeIndex(expected_dates, name=DATES),
                          result_array.dates.to_index(),
                          check_index_type=True,
                          check_names=True)
Exemplo n.º 17
0
    def get_last_available_price(
            self,
            tickers: Union[Ticker, Sequence[Ticker]],
            frequency: Frequency = None) -> Union[float, QFSeries]:
        """
        Gets the latest available price for given assets, even if the full bar is not yet available.

        The frequency parameter is always casted into 1 minute frequency, to represent the most recent price.

        It returns the CLOSE price of the last available bar. If "now" is after the market OPEN, and before the market
        CLOSE, the last available price is equal to the current price (CLOSE price of the bar, which right bound is
        equal to "now"). If the market did not open yet, the last available CLOSE price will be returned.
        Non-zero seconds or microseconds values are omitted (e.g. 13:40:01 is always treated as 13:40:00).

        Parameters
        -----------
        tickers: Ticker, Sequence[Ticker]
            tickers of the securities which prices should be downloaded
        frequency: Frequency
            frequency of the data

        Returns
        -------
        float, QFSeries
            last_prices series where:
            - last_prices.name contains a date of current prices,
            - last_prices.index contains tickers
            - last_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()

        # If the current_datetime represents the time after Market Close and before Market Open, shift it to the
        # Market Close of the day before
        if current_datetime + MarketOpenEvent.trigger_time(
        ) > current_datetime:
            current_datetime = current_datetime - RelativeDelta(days=1)
            current_datetime = current_datetime + MarketCloseEvent.trigger_time(
            )
        elif current_datetime + MarketCloseEvent.trigger_time(
        ) < current_datetime:
            current_datetime = current_datetime + MarketCloseEvent.trigger_time(
            )

        # If the current_datetime represents Saturday or Sunday, shift it to last Friday
        if current_datetime.weekday() in (5, 6):
            current_datetime = current_datetime - RelativeDelta(weekday=4,
                                                                weeks=1)

        # The time range denotes the current_datetime +- time delta related to the given frequency. The current price is
        # represented as the close price of (time_range_start, current_datetime) range, labeled using the time_range_
        # start value in most of the cases.
        #
        # The only exception is the price at the market open - in this case we do not have the bar directly
        # leading up to market open time. Thus, the open price from the time range (current_datetime, time_range_end)
        # is used to denote the price.

        time_range_start = current_datetime - frequency.time_delta()
        time_range_end = current_datetime + frequency.time_delta()

        # The start date is used to download older data, in case if there is no price available currently and we are
        # interested in the last available one. Therefore, at first we look one hour in the past. If this amount of data
        # would not be sufficient, we would look up to a few days in the past.

        download_start_date = current_datetime - Frequency.MIN_60.time_delta()

        def download_prices(start_time, end_time, multiple_days=False):
            # Function which downloads prices for the given tickers. In case if the time range spans over multiple days
            # and thus contains at least one Market Open Event, combine the Open price for the first bar after the
            # market open with the Close prices for all other bars from this day.
            if multiple_days:
                price_fields = [PriceField.Open, PriceField.Close]
                prices = self.data_provider.get_price(tickers, price_fields,
                                                      start_time, end_time,
                                                      frequency)
                return self._data_array_to_dataframe(prices, frequency)
            else:
                return self.data_provider.get_price(tickers, PriceField.Close,
                                                    start_time, end_time,
                                                    frequency)

        # If the data contains the Market Open Price, merge the prices
        if download_start_date <= MarketOpenEvent.trigger_time(
        ) + time_range_end <= time_range_end:
            contains_market_open = True
        elif download_start_date <= MarketOpenEvent.trigger_time(
        ) + download_start_date <= time_range_end:
            contains_market_open = True
        elif (time_range_end - download_start_date) > timedelta(days=1):
            contains_market_open = True
        else:
            contains_market_open = False

        prices_data_array = download_prices(download_start_date,
                                            time_range_end,
                                            contains_market_open)

        # Access the price bar starting at time_range_start and ending at current_datetime
        try:
            prices_series = prices_data_array.asof(time_range_start)
            prices_series.name = "Last available asset prices"

            if prices_series.isnull().values.any():
                # If any of the values is null, download more data, using a longer period of time
                raise IndexError

        except IndexError:
            # Download data using a longer period of time. In case of Monday or Tuesday, we download data from last 4
            # days in order to handle situations, were there was no price on Monday or Friday (and during the weekend).
            # In all other cases, we download data from the last 2 days.
            number_of_days_to_go_back = 2 if download_start_date.weekday(
            ) not in (0, 1) else 4
            prices_data_array = download_prices(
                download_start_date -
                RelativeDelta(days=number_of_days_to_go_back),
                time_range_end,
                multiple_days=True)

            prices_series = prices_data_array.asof(time_range_start)
            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
Exemplo n.º 18
0
 def test_get_last_price_with_empty_tickers_list(self):
     self.timer.set_current_time(
         str_to_date("2018-01-31") + MarketOpenEvent.trigger_time() +
         RelativeDelta(hours=1))
     last_prices = self.data_handler.get_last_available_price([])
     assert_series_equal(QFSeries(), last_prices)
Exemplo n.º 19
0
    def get_price(self, tickers: Union[Ticker, Sequence[Ticker]], fields: Union[PriceField, Sequence[PriceField]],
                  start_date: datetime, end_date: datetime = None, frequency: Frequency = None) -> \
            Union[PricesSeries, PricesDataFrame, QFDataArray]:
        """
        Runs DataProvider.get_price(...) but before makes sure that the query doesn't concern data from
        the future.

        In contrast to the DataHandler.get_history(...), it will return a valid Open price in the time between the
        Market Open and Market Close.

        Parameters
        ----------
        tickers: Ticker, Sequence[Ticker]
            tickers for securities which should be retrieved
        fields: PriceField, Sequence[PriceField]
            fields of securities which should be retrieved
        start_date: datetime
            date representing the beginning of historical period from which data should be retrieved
        end_date: datetime
            date representing the end of historical period from which data should be retrieved;
            if no end_date was provided, by default the current date will be used
        frequency: Frequency
            frequency of the data

        Returns
        -------
        None, PricesSeries, PricesDataFrame, QFDataArray
        """
        frequency = frequency or self.default_frequency
        assert frequency is not None, "Frequency cannot be equal to None"

        current_datetime = self.timer.now()
        end_date = current_datetime if end_date is None else end_date

        # end_date_without_look_ahead points to the latest market close in order to not return prices from the future
        # However, when the end_date falls between the market open and market close, the open price could also be
        # returned by the get_price function, therefore it is necessary to adjust the end_date_without_look_ahead
        end_date_without_look_ahead = self._get_end_date_without_look_ahead(
            end_date)

        open_prices_included = PriceField.Open == fields if isinstance(fields, PriceField) else \
            PriceField.Open in fields
        today_market_open = current_datetime + MarketOpenEvent.trigger_time()
        today_market_close = current_datetime + MarketCloseEvent.trigger_time()
        consider_additional_open_price = (
            frequency == Frequency.DAILY and open_prices_included
            and today_market_open <= end_date < today_market_close)

        if consider_additional_open_price:
            end_date_without_look_ahead = datetime(today_market_open.year,
                                                   today_market_open.month,
                                                   today_market_open.day)

        prices_data = self.data_provider.get_price(
            tickers, fields, start_date, end_date_without_look_ahead,
            frequency)

        # In case if the additional open price should be added, clean up the prices container to remove all data from
        # the future
        single_price_field = fields is not None and isinstance(
            fields, PriceField)
        if consider_additional_open_price and not single_price_field:
            single_ticker = tickers is not None and isinstance(tickers, Ticker)
            single_date = start_date.date() == end_date.date()
            prices_data = self._remove_data_from_the_future(
                prices_data, single_date, single_ticker,
                end_date_without_look_ahead)

        return prices_data
Exemplo n.º 20
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