def _compute_market_impact(self, date: datetime, tickers: Sequence[Ticker], fill_volumes: Sequence[int]) \
            -> Sequence[float]:
        """
        Market Impact is positive for buys and negative for sells.
        MI = +/- price_impact * volatility * sqrt (fill volume / average daily volume)
        """
        start_date = date - RelativeDelta(days=60)
        end_date = date - RelativeDelta(days=1)

        # Download close price and volume values
        data_array = self._data_provider.get_price(
            tickers, [PriceField.Close, PriceField.Volume], start_date,
            end_date, Frequency.DAILY)

        close_prices = cast_data_array_to_proper_type(
            data_array.loc[:, tickers, PriceField.Close])
        volumes = cast_data_array_to_proper_type(
            data_array.loc[:, tickers, PriceField.Volume])
        close_prices_volatility = close_prices.apply(
            self._compute_volatility).values

        average_volumes = volumes.apply(self._compute_average_volume).values

        abs_fill_volumes = np.abs(fill_volumes)
        volatility_volume_ratio = np.divide(abs_fill_volumes, average_volumes)
        sqrt_volatility_volume_ratio = np.sqrt(
            volatility_volume_ratio) * np.sign(fill_volumes)
        return self.price_impact * close_prices_volatility * sqrt_volatility_volume_ratio
Esempio n. 2
0
 def _get_open_prices(self,
                      prices_data_array: QFDataArray) -> PricesDataFrame:
     """ Returns PricesDataFrame consisting of only Open prices. """
     open_prices_df = cast_data_array_to_proper_type(
         prices_data_array.loc[:, :, PriceField.Open],
         use_prices_types=True).dropna(how="all")
     return open_prices_df
Esempio n. 3
0
    def generate_trades_for_ticker(self, prices_array: QFDataArray, exposures_tms: pd.Series, ticker: Ticker) \
            -> List[Trade]:

        open_prices_tms = cast_data_array_to_proper_type(
            prices_array.loc[:, ticker, PriceField.Open],
            use_prices_types=True)
        # historical data cropped to the time frame of the backtest (from start date till end date)
        historical_data = pd.concat((exposures_tms, open_prices_tms),
                                    axis=1).loc[self._start_date:]

        prev_exposure = 0.0
        trades_list = []

        trade_start_date = None
        trade_exposure = None
        trade_start_price = None

        for curr_date, row in historical_data.iterrows():
            curr_exposure, curr_price = row.values

            # skipping the nan exposures (the first one is sure to be nan)
            if np.isnan(curr_exposure) or np.isnan(curr_price):
                continue

            out_of_the_market = trade_exposure is None
            if out_of_the_market:
                assert prev_exposure == 0.0

                if curr_exposure != 0.0:
                    trade_start_date = curr_date
                    trade_exposure = curr_exposure
                    trade_start_price = curr_price
            else:
                assert prev_exposure != 0.0

                exposure_change = int(curr_exposure - prev_exposure)
                should_close_position = exposure_change != 0.0

                if should_close_position:
                    trades_list.append(
                        Trade(start_time=trade_start_date,
                              end_time=curr_date,
                              contract=self._tickers_to_contracts[ticker],
                              pnl=(curr_price / trade_start_price - 1) *
                              trade_exposure,
                              commission=0.0,
                              direction=int(trade_exposure)))
                    trade_start_date = None
                    trade_exposure = None
                    trade_start_price = None

                    going_into_opposite_direction = curr_exposure != 0.0
                    if going_into_opposite_direction:
                        trade_start_date = curr_date
                        trade_exposure = curr_exposure
                        trade_start_price = curr_price

            prev_exposure = curr_exposure

        return trades_list
Esempio n. 4
0
    def get_current_bar(self, tickers: Union[Ticker, Sequence[Ticker]], frequency: Frequency = None) \
            -> Union[QFSeries, QFDataFrame]:
        """
        Gets the current bar(s) for given Ticker(s). If the bar is not available yet, None is returned.

        If the request for single Ticker was made, then the result is a QFSeries indexed with PriceFields (OHLCV).
        If the request for multiple Tickers was made, then the result has Tickers as an index and PriceFields
        as columns.

        In case of N minutes frequency, the current bar can be returned in the time between (inclusive) N minutes
        after MarketOpenEvent and the MarketCloseEvent).

        E.g. for 1 minute frequency, at 13:00 (if the market opens before 13:00), the 12:59 - 13:00 bar will be
        returned. In case of 15 minutes frequency, when the market opened less then 15 minutes ago, Nones will be
        returned. If current time ("now") contains non-zero seconds or microseconds, Nones will be returned.

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

        Returns
        -------
        QFSeries, QFDataFrame
            current bar

        """
        if not tickers:
            return QFSeries()

        frequency = frequency or self.fixed_data_provider_frequency or Frequency.MIN_1

        tickers, was_single_ticker_provided = convert_to_list(tickers, Ticker)

        current_datetime = self.timer.now()

        start_date = current_datetime - frequency.time_delta()
        prices_data_array = self.get_price(tickers=tickers,
                                           fields=PriceField.ohlcv(),
                                           start_date=start_date,
                                           end_date=current_datetime,
                                           frequency=frequency)
        try:
            last_available_bars = cast_data_array_to_proper_type(
                prices_data_array.loc[start_date])
        except KeyError:
            return QFDataFrame(index=tickers, columns=PriceField.ohlcv())

        if was_single_ticker_provided:
            last_available_bars = last_available_bars.iloc[0, :]

        return last_available_bars
Esempio n. 5
0
    def _get_current_bars(self, tickers: Sequence[Ticker]) -> QFDataFrame:
        """
        Gets the current bars for given Tickers. If the bars are not available yet, NaNs are returned.
        The result is a QFDataFrame with Tickers as an index and PriceFields as columns.

        In case of daily trading, the current bar is returned only at the Market Close Event time, as the get_price
        function will not return data for the current date until the market closes.

        In case of intraday trading (for N minutes frequency) the current bar can be returned in the time between
        (inclusive) N minutes after MarketOpenEvent and the MarketCloseEvent. Important: If current time ("now")
        contains non-zero seconds or microseconds, NaNs will be returned.

        """
        if not tickers:
            return QFDataFrame()

        assert self._frequency >= Frequency.DAILY, "Lower than daily frequency is not supported by the simulated " \
                                                   "executor"
        current_datetime = self._timer.now()

        market_close_time = current_datetime + MarketCloseEvent.trigger_time(
        ) == current_datetime

        if self._frequency == Frequency.DAILY:
            # In case of daily trading, the current bar can be returned only at the Market Close
            if not market_close_time:
                return QFDataFrame(index=tickers, columns=PriceField.ohlcv())
            else:
                current_datetime = date_to_datetime(current_datetime.date())
                start_date = current_datetime - self._frequency.time_delta()
                current_bar_start = current_datetime
        else:
            # In case of intraday trading the current full bar is always indexed by the left side of the time range
            start_date = current_datetime - self._frequency.time_delta()
            current_bar_start = start_date

        prices_data_array = self._data_handler.get_price(
            tickers=tickers,
            fields=PriceField.ohlcv(),
            start_date=start_date,
            end_date=current_datetime,
            frequency=self._frequency)
        try:
            current_bars = cast_data_array_to_proper_type(
                prices_data_array.loc[current_bar_start])
        except KeyError:
            current_bars = QFDataFrame(index=tickers,
                                       columns=PriceField.ohlcv())
        return current_bars
Esempio n. 6
0
    def _initialize_futures_chain(self, fields: Union[PriceField, Sequence[PriceField]], start_date: datetime,
                                  end_date: datetime, frequency: Frequency):
        """
        Provides data related to the future chain, within a given time range, and updates the Futures Chain with the
        newly acquired data. It gets the values of price fields and expiration dates for each specific future contract.

        It is the first function, that needs to be called, before generating the chain, because it is responsible for
        downloading all the necessary data, used later on by other functions.

        Parameters
        ----------
        fields
            price fields, which should be retrieved
        start_date
        end_date
        frequency
            represent the time range and frequency of the downloaded prices data for the future contracts

        """
        # Check if single field was provided
        _, got_single_field = convert_to_list(fields, PriceField)

        # Get the expiration dates related to the future contracts belonging to the futures chain
        future_tickers_exp_dates_series = self._future_ticker.get_expiration_dates()

        # Consider only these future contracts, which may be used to build the futures chain - do not include contracts,
        # which expired before the start_date
        future_tickers_exp_dates_series = future_tickers_exp_dates_series[
            future_tickers_exp_dates_series.index >= start_date
        ]
        # Exclude contracts which will not be used while building the current futures chain. All of the newer contracts,
        # which will be used for later futures chains building will be downloaded later anyway, as
        # _initialize_futures_chain() is called after each expiration of a contract.
        current_contract_index = pd.Index(future_tickers_exp_dates_series).get_loc(
            self._future_ticker.get_current_specific_ticker()
        )
        last_ticker_position = min(future_tickers_exp_dates_series.size, current_contract_index + 1)
        future_tickers_exp_dates_series = future_tickers_exp_dates_series.iloc[0:last_ticker_position]

        # Download the historical prices
        future_tickers_list = list(future_tickers_exp_dates_series.values)
        futures_data = self._data_provider.get_price(future_tickers_list, fields, start_date, end_date, frequency)

        # Store the start_date used for the purpose of FuturesChain initialization
        self._first_cached_date = start_date

        for exp_date, future_ticker in future_tickers_exp_dates_series.items():

            # Create a data frame and cast it into PricesDataFrame or PricesSeries
            if got_single_field:
                data = futures_data.loc[:, future_ticker]
            else:
                data = futures_data.loc[:, future_ticker, :]
                data = cast_data_array_to_proper_type(data, use_prices_types=True)

            # Check if data is empty (some contract may have no price within the given time range) - if so do not
            # add it to the FuturesChain
            if not data.empty:
                # Create the future object and add it to the Futures Chain data structure
                future = FutureContract(ticker=future_ticker,
                                        exp_date=exp_date,
                                        data=data
                                        )

                self.loc[exp_date] = future

        self.sort_index(inplace=True)
Esempio n. 7
0
    def get_current_bar(self, tickers: Union[Ticker, Sequence[Ticker]], frequency: Frequency = None) \
            -> Union[QFSeries, QFDataFrame]:
        """
        Gets the current bar(s) for given Ticker(s). If the bar is not available yet (e.g. before the market close),
        None is returned.

        If the request for single Ticker was made, then the result is a QFSeries indexed with PriceFields (OHLCV).
        If the request for multiple Tickers was made, then the result has Tickers as an index and PriceFields
        as columns.

        Normally on working days the method will return non-empty bars in the time between (inclusive)
        MarketCloseEvent and midnight (exclusive).

        On non-working days or on working days in the time between midnight (inclusive) and MarketClose (exclusive),
        e.g. 12:00, the returned bars will contain Nones as values.

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

        Returns
        -------
        QFSeries, QFDataFrame
            current bar
        """
        if not tickers:
            return QFSeries()

        frequency = frequency or self.fixed_data_provider_frequency or Frequency.DAILY

        tickers, was_single_ticker_provided = convert_to_list(tickers, Ticker)

        current_datetime = self.timer.now()

        if self.time_helper.datetime_of_latest_market_event(
                MarketCloseEvent) < current_datetime:
            last_available_bars = QFDataFrame(index=tickers,
                                              columns=PriceField.ohlcv())
        else:
            current_date = self._zero_out_time_component(current_datetime)
            start_date = current_date - RelativeDelta(days=7)

            prices_data_array = self.get_price(
                tickers=tickers,
                fields=PriceField.ohlcv(),
                start_date=start_date,
                end_date=current_date,
                frequency=frequency)  # type: QFDataArray
            try:
                last_available_bars = cast_data_array_to_proper_type(
                    prices_data_array.loc[current_date])
            except KeyError:
                return QFDataFrame(index=tickers, columns=PriceField.ohlcv())

        if was_single_ticker_provided:
            last_available_bars = last_available_bars.iloc[0, :]

        return last_available_bars