コード例 #1
0
    def test_futures_chain_without_adjustment(self):
        timer = SettableTimer(self.end_date)
        self.future_ticker_1.initialize_data_provider(timer,
                                                      self.data_provider)

        futures_chain = FuturesChain(self.future_ticker_1, self.data_provider,
                                     FuturesAdjustmentMethod.NTH_NEAREST)

        # AB2021M is the current specific ticker till 2021-06-14 inclusive, afterwards the AB2021U
        start_date = str_to_date("2021-06-13")
        end_date = str_to_date("2021-06-17")
        fields = PriceField.ohlcv()
        prices = futures_chain.get_price(fields, start_date, end_date,
                                         Frequency.DAILY)

        prices_m_contract = self.data_provider.get_price(
            PortaraTicker("AB2021M", SecurityType.FUTURE, 1), fields,
            start_date, str_to_date("2021-06-14"), Frequency.DAILY)
        prices_u_contract = self.data_provider.get_price(
            PortaraTicker("AB2021U", SecurityType.FUTURE, 1), fields,
            str_to_date("2021-06-15"), end_date, Frequency.DAILY)

        assert_dataframes_equal(prices,
                                concat([prices_m_contract, prices_u_contract]),
                                check_names=False)
コード例 #2
0
    def get_prices(self, ticker: Ticker):
        """
        Create a data frame with OHLC prices for the given ticker.
        """
        self.timer.set_current_time(self.end_date)

        if isinstance(ticker, FutureTicker):
            futures_chain = FuturesChain(
                ticker,
                self.data_handler,
                method=FuturesAdjustmentMethod.NTH_NEAREST)
            prices_df = futures_chain.get_price(
                [
                    PriceField.Open, PriceField.High, PriceField.Low,
                    PriceField.Close
                ],
                start_date=self.start_date,
                end_date=self.end_date,
                frequency=self.data_handler.frequency)
        else:
            prices_df = self.data_handler.get_price(
                ticker, [
                    PriceField.Open, PriceField.High, PriceField.Low,
                    PriceField.Close
                ],
                start_date=self.start_date,
                end_date=self.end_date,
                frequency=self.data_handler.frequency)
        return prices_df
コード例 #3
0
    def _get_data_for_backtest(self) -> QFDataArray:
        """
        Creates a QFDataArray containing OHLCV values for all tickers passes to Fast Alpha Models Tester.
        """
        print("\nLoading all price values of tickers:")
        self._timer.set_current_time(self._end_date)
        tickers_dict = {}
        for ticker in tqdm(self._tickers, file=sys.stdout):
            if isinstance(ticker, FutureTicker):
                fc = FuturesChain(ticker, self._data_handler)
                tickers_dict[ticker] = fc.get_price(PriceField.ohlcv(), self._start_date, self._end_date,
                                                    Frequency.DAILY)
            else:
                tickers_dict[ticker] = self._data_handler.get_price(ticker, PriceField.ohlcv(), self._start_date,
                                                                    self._end_date)

        prices_data_array = tickers_dict_to_data_array(tickers_dict, self._tickers, PriceField.ohlcv())
        return prices_data_array
コード例 #4
0
    def _compute_target_value(self,
                              signal: Signal,
                              frequency=Frequency.DAILY) -> float:
        """
        Caps the target value, so that according to historical volume data, the position will not exceed
        max_volume_percentage * mean volume within last 100 days.
        """
        ticker: Ticker = signal.ticker

        portfolio_value = self._broker.get_portfolio_value()
        target_percentage = self._compute_target_percentage(signal)
        target_value = portfolio_value * target_percentage

        end_date = self._data_handler.timer.now()
        start_date = end_date - RelativeDelta(days=100)

        if isinstance(ticker, FutureTicker):
            # Check if a futures chain instance already exists for this ticker and create it if not
            # The default adjustment method will be taken (FuturesAdjustmentMethod.NTH_NEAREST) as the volume should
            # not be adjusted
            if ticker not in self._cached_futures_chains_dict.keys():
                self._cached_futures_chains_dict[ticker] = FuturesChain(
                    ticker, self._data_handler)

            volume_series: PricesSeries = self._cached_futures_chains_dict[
                ticker].get_price(PriceField.Volume, start_date, end_date,
                                  frequency)
        else:
            volume_series: PricesSeries = self._data_handler.get_price(
                ticker, PriceField.Volume, start_date, end_date, frequency)

        mean_volume = volume_series.mean()

        specific_ticker = ticker.get_current_specific_ticker() if isinstance(
            ticker, FutureTicker) else ticker
        current_price = self._data_handler.get_last_available_price(
            specific_ticker, frequency)
        contract_size = ticker.point_value if isinstance(ticker,
                                                         FutureTicker) else 1
        divisor = current_price * contract_size
        quantity = target_value // divisor

        if abs(quantity) > mean_volume * self._max_volume_percentage:
            target_quantity = np.floor(mean_volume *
                                       self._max_volume_percentage)
            target_value = target_quantity * divisor * np.sign(quantity)
            self.logger.info(
                "InitialRiskWithVolumePositionSizer: {} - capping {}.\n"
                "Initial quantity: {}\n"
                "Reduced quantity: {}".format(self._data_handler.timer.now(),
                                              ticker.ticker, quantity,
                                              target_quantity))

        assert is_finite_number(
            target_value), "target_value has to be a finite number"
        return target_value
コード例 #5
0
    def _generate_buy_and_hold_returns(self,
                                       ticker: Ticker) -> SimpleReturnsSeries:
        """ Computes series of simple returns, which would be returned by the Buy and Hold strategy. """
        if isinstance(ticker, FutureTicker):
            try:
                ticker.initialize_data_provider(SettableTimer(self._end_date),
                                                self._data_provider)
                futures_chain = FuturesChain(
                    ticker, self._data_provider,
                    FuturesAdjustmentMethod.BACK_ADJUSTED)
                prices_series = futures_chain.get_price(
                    PriceField.Close, self._start_date, self._end_date)
            except NoValidTickerException:
                prices_series = PricesSeries()
        else:
            prices_series = self._data_provider.get_price(
                ticker, PriceField.Close, self._start_date, self._end_date)

        returns_tms = prices_series.to_simple_returns().replace(
            [-np.inf, np.inf], np.nan).fillna(0.0)
        returns_tms.name = "Buy and Hold"
        return returns_tms
コード例 #6
0
ファイル: futures_model.py プロジェクト: quarkfin/qf-lib
    def get_data(self,
                 ticker_str: str,
                 end_date: datetime,
                 aggregate_volume: bool = False):
        """
        Downloads the OHCLV Prices data frame for the given ticker. In case of a FutureTicker, the function downloads
        the Futures Chain and applies backward adjustment to the prices.

        Parameters
        ----------
        ticker_str: str
            string representing the ticker for which the data should be downloaded
        end_date: datetime
            last date for the data to be fetched
        aggregate_volume: bool
            used only in case of future tickers - if set to True, the volume data would not be the volume for the
            given contract, but the volume aggregated across all contracts (for each day the volume will be simply
            the sum of all volumes of the existing contracts of the given future asset)
        """
        end_date = end_date + RelativeDelta(
            hour=0, minute=0, second=0, microsecond=0)
        start_date = end_date - RelativeDelta(days=self.num_of_bars_needed +
                                              50)
        ticker = self.ticker_name_to_ticker[ticker_str]
        if isinstance(ticker, FutureTicker):
            try:
                data_frame = self.futures_data[ticker].get_price(
                    PriceField.ohlcv(), start_date, end_date, Frequency.DAILY)
            except KeyError:
                # Ticker was not preloaded or the FutureChain has expired
                self.futures_data[ticker] = FuturesChain(
                    ticker, self.data_provider,
                    FuturesAdjustmentMethod.BACK_ADJUSTED)

                data_frame = self.futures_data[ticker].get_price(
                    PriceField.ohlcv(), start_date, end_date, Frequency.DAILY)
            if aggregate_volume:
                data_frame[
                    PriceField.Volume] = self._compute_aggregated_volume(
                        ticker, start_date, end_date)

        else:
            data_frame = self.data_provider.get_price(ticker,
                                                      PriceField.ohlcv(),
                                                      start_date, end_date,
                                                      Frequency.DAILY)

        data_frame = data_frame.dropna(how="all")
        return data_frame
コード例 #7
0
    def calculate_exposure(self, ticker: FutureTicker,
                           current_exposure: Exposure) -> Exposure:
        num_of_bars_needed = self.slow_time_period
        current_time = self.timer.now()

        # Compute the start time
        start_time = current_time - RelativeDelta(days=num_of_bars_needed +
                                                  100)

        if self.futures_chain is None:
            # Create Futures Chain object
            self.futures_chain = FuturesChain(ticker, self.data_handler)

        # Get the data frame containing High, Low, Close prices
        data_frame = self.futures_chain.get_price(
            [PriceField.High, PriceField.Low, PriceField.Close], start_time,
            current_time)
        data_frame = data_frame.dropna(how='all').fillna(method='pad')

        close_tms = data_frame[PriceField.Close]
        close_tms = close_tms.iloc[-self.slow_time_period:]

        try:
            # Compute the ATR
            atr_df = data_frame[-num_of_bars_needed:]
            self.average_true_range = average_true_range(atr_df,
                                                         normalized=True)

            ############################
            #      Opening position    #
            ############################

            current_price = close_tms.iloc[-1]

            # Compute the fast and slow simple moving averages
            fast_ma = sum(close_tms.iloc[-self.fast_time_period:]
                          ) / self.fast_time_period
            slow_ma = sum(close_tms) / self.slow_time_period

            if fast_ma > slow_ma:
                # Long entries are only allowed if the fast moving average is above the slow moving average.
                # If today’s closing price is the highest close in the past 50 days, we buy.
                highest_price = max(close_tms[-self.fast_time_period:])
                if current_price >= highest_price:
                    if current_exposure == Exposure.OUT:
                        self.time_of_opening_position = close_tms.index[-1]
                    return Exposure.LONG
            else:
                # Short entries are only allowed if the fast moving average is below the slow moving average.
                # If today’s closing price is the lowest close in the past 50 days, we sell.
                lowest_price = min(close_tms[-self.fast_time_period:])
                if current_price <= lowest_price:
                    if current_exposure == Exposure.OUT:
                        self.time_of_opening_position = close_tms.index[-1]
                    return Exposure.SHORT

            ############################
            #     Closing position     #
            ############################

            if current_exposure == Exposure.LONG:
                # A long position is closed when it has moved three ATR units down from its highest closing price
                # since the position was opened.
                close_prices = close_tms.loc[
                    self.time_of_opening_position:].dropna()
                if current_price < max(close_prices) * (
                        1 -
                        self.risk_estimation_factor * self.average_true_range):
                    return Exposure.OUT

            elif current_exposure == Exposure.SHORT:
                # A short position is closed when it has moved three ATR units up from its lowest closing price
                # since the position was opened.
                close_prices = close_tms.loc[
                    self.time_of_opening_position:].dropna()
                if current_price > min(close_prices) * (
                        1 +
                        self.risk_estimation_factor * self.average_true_range):
                    return Exposure.OUT

        except (KeyError, ValueError):
            # No price at this day
            pass

        return current_exposure