def test_generate_close_orders__multiple_future_tickers(self, future_ticker, order_factory, broker):
        tickers_in_portfolio = [BloombergTicker("CLG00 Comdty", SecurityType.FUTURE, 1),
                                BloombergTicker("CLG01 Comdty", SecurityType.FUTURE, 1)]

        tickers_in_portfolio_2 = [BloombergTicker("CTG00 Comdty", SecurityType.FUTURE, 1),
                                  BloombergTicker("CTG01 Comdty", SecurityType.FUTURE, 1)]

        broker.get_positions.side_effect = lambda: [BacktestPositionFactory.create_position(c)
                                                    for c in tickers_in_portfolio + tickers_in_portfolio_2]

        # Generate the FuturesRollingOrdersGenerator for two different Future Tickers
        future_ticker.get_current_specific_ticker.return_value = BloombergTicker("CLG01 Comdty", SecurityType.FUTURE, 1)
        future_ticker.belongs_to_family.side_effect = lambda t: t in tickers_in_portfolio
        future_ticker.get_expiration_dates.return_value = QFSeries(data=tickers_in_portfolio,
                                                                   index=[self.current_date - RelativeDelta(days=10),
                                                                          self.current_date + RelativeDelta(days=5)])
        future_ticker2 = MagicMock()
        future_ticker2.get_current_specific_ticker.return_value = BloombergTicker("CTG01 Comdty")
        future_ticker2.belongs_to_family.side_effect = lambda t: t in tickers_in_portfolio_2
        future_ticker2.get_expiration_dates.return_value = QFSeries(data=tickers_in_portfolio_2,
                                                                    index=[self.current_date - RelativeDelta(days=10),
                                                                           self.current_date + RelativeDelta(days=5)])

        rolling_orders_generator = FuturesRollingOrdersGenerator([future_ticker, future_ticker2], self.timer, broker,
                                                                 order_factory)
        rolling_orders_generator.logger = MagicMock()
        rolling_orders_generator.generate_close_orders()

        order_factory.target_percent_orders.assert_called_once_with(
            {BloombergTicker("CLG00 Comdty", SecurityType.FUTURE, 1): 0,
             BloombergTicker("CTG00 Comdty", SecurityType.FUTURE, 1): 0}, MarketOrder(), TimeInForce.GTC
        )
Ejemplo n.º 2
0
    def _add_number_of_transactions_chart(self, pandas_freq: str, title: str):
        transactions = self.backtest_result.transactions
        transactions_series = QFSeries(data=transactions,
                                       index=(t.time for t in transactions))

        if transactions_series.empty:
            raise ValueError("Transactions series is empty")

        # Compute the number of transactions per day
        transactions_series = transactions_series.resample(
            Frequency.DAILY.to_pandas_freq()).count()

        # Aggregate the transactions using the given frequency
        if to_offset(pandas_freq) > to_offset('D'):
            transactions_series = transactions_series.rolling(
                pandas_freq).sum()

            # Cut the non complete beginning of the outputs (e.g. in case of 30 days window, cut the first 30 days)
            start_date = transactions_series.index[0]
            transactions_series = transactions_series.loc[start_date +
                                                          Timedelta(pandas_freq
                                                                    ):]
            if transactions_series.empty:
                # The available time period is too short to compute the statistics with the provided frequency
                return

        elif to_offset(pandas_freq) < to_offset('D'):
            raise ValueError(
                "The provided pandas frequency can not be higher than the daily frequency"
            )

        self._add_line_chart_element(transactions_series, title)
Ejemplo n.º 3
0
    def __init__(self,
                 data=None,
                 index=None,
                 columns=None,
                 dtype=None,
                 copy=False):

        self.logger = qf_logger.getChild(self.__class__.__name__)

        # Data Frame containing the table data
        self.data = QFDataFrame(data, index, columns, dtype, copy)

        # Dictionary containing a mapping from column names onto ColumnStyles
        self._columns_styles = {
            column_name: self.ColumnStyle(column_name)
            for column_name in self.data.columns.tolist()
        }

        # Series containing the styles for each of the rows
        self._rows_styles = QFSeries(
            data=[self.RowStyle(loc) for loc in self.data.index],
            index=self.data.index)

        # Data Frame containing styles for all cells in the table, based upon columns_styles and rows_styles
        self._styles = QFDataFrame(data={
            column_name: [
                self.CellStyle(row_style, column_style)
                for row_style in self.rows_styles
            ]
            for column_name, column_style in self.columns_styles.items()
        },
                                   index=self.data.index,
                                   columns=self.data.columns)

        self.table_styles = self.Style()
Ejemplo n.º 4
0
    def get_factor_return_attribution(cls, fund_tms: QFSeries,
                                      fit_tms: QFSeries,
                                      regressors_df: QFDataFrame,
                                      coefficients: QFSeries,
                                      alpha: float) -> Tuple[QFSeries, float]:
        """
        Returns performance attribution for each factor in given regressors and also calculates the unexplained return.
        """
        fund_returns = fund_tms.to_simple_returns()
        regressors_returns = regressors_df.to_simple_returns()
        annualised_fund_return = cagr(fund_returns)
        annualised_fit_return = cagr(fit_tms)

        total_nav = fit_tms.to_prices(initial_price=1.0)

        def calc_factors_profit(series) -> float:
            factor_ret = regressors_returns.loc[:, series.name].values
            return coefficients.loc[series.name] * (total_nav[:-1].values *
                                                    factor_ret).sum()

        factors_profits = regressors_returns.apply(calc_factors_profit)

        alpha_profit = total_nav[:-1].sum() * alpha
        total_profit = factors_profits.sum() + alpha_profit

        regressors_return_attribution = factors_profits * annualised_fit_return / total_profit
        regressors_return_attribution = cast_series(
            regressors_return_attribution, QFSeries)

        unexplained_return = annualised_fund_return - regressors_return_attribution.sum(
        )

        return regressors_return_attribution, unexplained_return
Ejemplo n.º 5
0
def sqn(returns: QFSeries):
    """
    Calculates the SQN = mean return of trade / std(returns of trades). The returns passed to the function may wither
    be defined as percentage PnL of trades or as r_multiply = percentage PnL / risk.
    """
    result = returns.mean() / returns.std()
    return result
Ejemplo n.º 6
0
def create_qq_chart(strategy: QFSeries) -> Chart:
    colors = Chart.get_axes_colors()

    strategy = strategy.to_log_returns()
    # Normalize
    strategy = strategy - strategy.mean()
    strategy = strategy / strategy.std()
    # Sort
    strategy_values = sorted(strategy.values)

    # Create benchmark
    benchmark_values = list(range(1, len(strategy_values) + 1))
    n = len(strategy_values) + 1
    benchmark_values = map(lambda x: x / n, benchmark_values)
    benchmark_values = list(map(lambda x: norm.ppf(x), benchmark_values))

    # Figure out the limits.
    maximum = max(max(benchmark_values), max(strategy_values))

    result = LineChart(start_x=-maximum, end_x=maximum, upper_y=maximum, lower_y=-maximum)
    result.add_decorator(ScatterDecorator(
        benchmark_values, strategy_values, color=colors[0], alpha=0.6, edgecolors='black', linewidths=0.5))

    result.add_decorator(VerticalLineDecorator(0, color='black', linewidth=1))
    result.add_decorator(HorizontalLineDecorator(0, color='black', linewidth=1))

    result.add_decorator(TitleDecorator("Normal Distribution Q-Q"))
    result.add_decorator(AxesLabelDecorator("Normal Distribution Quantile", "Observed Quantile"))

    # Add diagonal line.
    result.add_decorator(DiagonalLineDecorator(color=colors[1]))

    return result
Ejemplo n.º 7
0
    def rolling_time_window(
            self, window_length: int, step: int, func: Callable[[Union["QFDataFrame", np.ndarray]], "QFSeries"]) \
            -> Union[None, "QFSeries", "QFDataFrame"]:
        """
        Runs a given function on each rolling window in the dataframe. The content of a rolling window is also
        a QFDataFrame thus the funciton which should be applied should accept a QFDataFrame as an argument.

        The function may return either a QFSeries (then the output of rolling_time_window will be QFDataFrame)
        or a scalar value (then the output of rolling_time_window will be QFSeries).

        The rolling window is moved along the time index (rows).

        Parameters
        ----------
        window_length
            number of rows which should be taken into rolling window
        step
            number of rows by which rolling window should be moved
        func
            function to apply on each rolling window. If it returns a QFSeries then the output of rolling_time_window()
            will be a QFDataFrame; if it returns a scalar value, the return value of rolling_time_window() will
            be a QFSeries

        Returns
        -------
        None (if the result of running the rolling window was empty)
        or QFSeries (if the function applied returned scalar value for each window)
        or QFDataFrame (if the function applied returned QFSeries for each window)
        """
        results_dict = dict()  # type: Dict[datetime, pd.Series]
        end_idx = self.num_of_rows

        while True:
            start_idx = end_idx - window_length
            if start_idx < 0:
                break

            patch = self.iloc[start_idx:end_idx, :]
            end_date = self.index[end_idx - 1]
            results_dict[end_date] = func(patch)

            end_idx -= step

        if not results_dict:
            return None

        first_element = next(iter(results_dict.values()))  # type: "QFSeries"

        if isinstance(first_element, pd.Series):
            result = QFDataFrame.from_dict(results_dict, orient='index')
            result = cast_dataframe(result, QFDataFrame)
        else:
            from qf_lib.containers.series.qf_series import QFSeries
            dates_and_values = [(date, value)
                                for date, value in results_dict.items()]
            dates, values = zip(*dates_and_values)
            result = QFSeries(index=dates, data=values)
            result = result.sort_index()

        return result
Ejemplo n.º 8
0
def main():
    dates_a = pd.date_range('2015-01-01', periods=10, freq='D')
    a = QFSeries(data=[1, 2, 3, 4, 5, 4, 3, 2, 1, 4],
                 index=dates_a,
                 name='Series A')

    dates_b = pd.date_range('2015-01-08', periods=10, freq='D')
    b = QFSeries(data=[3, 2, 3, 4, 5, 4, 3, 2, 1, 2],
                 index=dates_b,
                 name='Series B')

    dates_c = pd.date_range('2015-01-05', periods=10, freq='D')
    c = QFSeries(data=[4, 2, 3, 4, 5, None, 3, 2, 1, 2],
                 index=dates_c,
                 name='Series C')

    abc = pd.concat([a, b, c], axis=1, join='outer')
    print(abc)

    line_chart = LineChart()
    line_chart.add_decorator(DataElementDecorator(abc.iloc[:, 0]))
    line_chart.add_decorator(DataElementDecorator(abc.iloc[:, 1]))
    line_chart.add_decorator(DataElementDecorator(abc.iloc[:, 2]))
    line_chart.plot()

    plt.show(block=True)
Ejemplo n.º 9
0
    def __init__(self, benchmark_tms: QFSeries, strategy_tms: QFSeries):
        super().__init__()
        self.assert_is_qfseries(benchmark_tms)
        self.assert_is_qfseries(strategy_tms)

        self.benchmark_tms = benchmark_tms.to_simple_returns()
        self.strategy_tms = strategy_tms.to_simple_returns()
Ejemplo n.º 10
0
    def setup(self, window_size=None, step=None):
        """
        Returns the series of models (each model is placed under the date corresponding to the end of its time window).

        Parameters
        ----------
        window_size: int, optional
            number of samples contained in each window. If it's not provided, than it will be calculated automatically
        step: int, optional
            number of samples by which window shall be moved each time it is moved. If the value isn't provided,
            than it will be calculated automatically
        """
        if window_size is None:
            window_size = RollingWindowsEstimator.estimate_rolling_window_size(
                self.input_data.analysed_tms)
        if step is None:
            step = RollingWindowsEstimator.estimate_rolling_window_step(
                self.input_data.analysed_tms)

        assert step > 0

        self.window_size_ = window_size
        self.step_ = step

        end_of_window_idx = len(self.input_data.analysed_tms) - 1
        beginning_of_window_idx = end_of_window_idx - window_size

        ref_dates = []
        models = []

        while beginning_of_window_idx >= 0:
            data_model, ref_date = self._get_model_for_window(
                beginning_of_window_idx, end_of_window_idx)
            models.append(data_model)
            ref_dates.append(ref_date)

            end_of_window_idx -= step
            beginning_of_window_idx -= step

        models_series_ = QFSeries(data=models, index=ref_dates)

        self.coefficients_df = models_series_.apply(
            lambda model: model.coefficients)
        self.t_stats_df = models_series_.apply(lambda model: model.t_values)
        self.p_values_df = models_series_.apply(lambda model: model.p_values)
        self.r_squared_tms = models_series_.apply(
            lambda model: model.r_squared)
        self.risk_contribs_df = models_series_.apply(
            lambda model: model.risk_contribution)

        self.factors_performance_attributions_df = models_series_.apply(
            lambda model: model.factors_performance_attribution_ret)
        self.unexplained_performance_attributions_tms = models_series_.apply(
            lambda model: model.unexplained_performance_attribution_ret)

        # select correlations of different series with analysed timeseries
        self.correlations_df = models_series_.apply(
            lambda model: model.correlation_matrix.iloc[-1, :-1])
Ejemplo n.º 11
0
    def calculate_aggregated_cone_oos_only(
            self, oos_series: QFSeries, is_mean_return: float, is_sigma: float,
            number_of_std: float) -> QFDataFrame:
        """
        This functions does not need the IS history, only the IS statistics.

        Parameters
        ----------
        oos_series
            series that is plotted on the cone - corresponds to the oos returns
        is_mean_return
            mean daily log return of the strategy In Sample
        is_sigma
            std of daily log returns of the strategy In Sample
        number_of_std
            corresponds to the randomness of the stochastic process. reflects number of standard deviations
            to get expected values for. For example 1.0 means 1 standard deviation above the expected value.

        Returns
        -------
        QFDataFrame: contains values corresponding to Strategy, Mean and Std. Values are indexed by number of days
            from which given cone was evaluated
        """

        log_returns_tms = oos_series.to_log_returns()
        nr_of_data_points = oos_series.size

        strategy_values = np.empty(nr_of_data_points)
        expected_values = np.empty(nr_of_data_points)

        for i in range(nr_of_data_points):
            cone_start_idx = i + 1

            # calculate total return of the strategy
            oos_log_returns = log_returns_tms[cone_start_idx:]
            total_strategy_return = exp(
                oos_log_returns.sum())  # 1 + percentage return

            # calculate expectation
            number_of_steps = len(oos_log_returns)
            starting_price = 1  # we take 1 as a base value
            total_expected_return = self.get_expected_value(
                is_mean_return, is_sigma, starting_price, number_of_steps,
                number_of_std)

            # writing to the array starting from the last array element and then moving towards the first one
            strategy_values[-i - 1] = total_strategy_return
            expected_values[-i - 1] = total_expected_return

        index = Int64Index(range(0, nr_of_data_points))

        strategy_values_tms = PricesSeries(index=index, data=strategy_values)
        expected_tms = QFSeries(index=index, data=expected_values)

        return QFDataFrame({
            'Strategy': strategy_values_tms,
            'Expectation': expected_tms,
        })
Ejemplo n.º 12
0
    def __init__(self, benchmark_tms: QFSeries, strategy_tms: QFSeries, tail_plot=False, custom_title=False):
        super().__init__()
        self.assert_is_qfseries(benchmark_tms)
        self.assert_is_qfseries(strategy_tms)

        self.benchmark_tms = benchmark_tms.to_simple_returns()
        self.strategy_tms = strategy_tms.to_simple_returns()
        self.tail_plot = tail_plot
        self.custom_title = custom_title
Ejemplo n.º 13
0
    def test_concat_series(self):
        index = [1, 2, 3]
        series_1 = QFSeries(data=["A", "B", "C"], index=index)
        series_2 = QFSeries(data=["D", "E", "F"], index=index)

        df = pd.concat([series_1, series_2], axis=1)
        self.assertEqual(type(df), QFDataFrame)

        series = pd.concat([series_1, series_2], axis=0)
        self.assertEqual(type(series), QFSeries)
Ejemplo n.º 14
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
Ejemplo n.º 15
0
    def setUp(self):
        dates = DatetimeIndex(date_range(start='2014-01-01', freq='d', periods=10))
        returns = np.arange(0, 1, 0.1)
        self.test_series = QFSeries(index=dates, data=returns)

        reversed_returns = returns[::-1]
        test_series_reversed = QFSeries(index=dates, data=reversed_returns)

        self.test_data_frame = concat([self.test_series, test_series_reversed], axis=1, join='inner')

        self.xl_importer = ExcelImporter()
Ejemplo n.º 16
0
def _get_simple_quantile_chart(simple_returns):
    if len(simple_returns) > 0:
        simple_returns_weekly = get_aggregate_returns(simple_returns, Frequency.WEEKLY, multi_index=True)
        simple_returns_monthly = get_aggregate_returns(simple_returns, Frequency.MONTHLY, multi_index=True)

        chart = BoxplotChart([simple_returns, simple_returns_weekly, simple_returns_monthly], linewidth=1)
    else:
        chart = BoxplotChart([QFSeries(), QFSeries(), QFSeries()], linewidth=1)

    tick_decorator = AxisTickLabelsDecorator(labels=["daily", "weekly", "monthly"], axis=Axis.X)
    return chart, tick_decorator
Ejemplo n.º 17
0
    def evaluate_params_for_tickers(self, parameters: tuple,
                                    tickers: Sequence[Ticker],
                                    start_time: datetime, end_date: datetime):

        # Get the backtest element for the given list of tickers
        backtest_elements_for_tickers = [
            el for el in self.params_backtest_summary_elem_dict[parameters]
            if set(el.tickers) == set(tickers)
        ]
        assert len(backtest_elements_for_tickers) == 1, "Check if the modeled_params passed to " \
                                                        "FastAlphaModelTesterConfig match those you want to test"
        backtest_elem = backtest_elements_for_tickers[0]
        returns_tms = backtest_elem.returns_tms.dropna(how="all")
        trades = backtest_elem.trades

        # Create the TradesEvaluationResult object
        ticker_evaluation = TradesEvaluationResult()
        ticker_evaluation.ticker = tickers
        ticker_evaluation.parameters = parameters
        ticker_evaluation.end_date = end_date
        # Compute the start date as the maximum value between the given start_time and the first date of returns tms in
        # case of 1 ticker backtest
        if len(tickers) == 1:
            start_date = max(
                start_time,
                returns_tms.index[0]) if not returns_tms.empty else end_date
        else:
            start_date = start_time
        ticker_evaluation.start_date = start_date

        if start_date >= end_date:
            # Do not compute further fields - return the default None values
            return ticker_evaluation

        avg_nr_of_trades = avg_nr_of_trades_per1y(
            QFSeries([
                t for t in trades
                if t.start_time >= start_date and t.end_time <= end_date
            ]), start_date, end_date)
        ticker_evaluation.avg_nr_of_trades_1Y = avg_nr_of_trades
        ticker_evaluation.sqn_per_avg_nr_trades = sqn(
            QFSeries([
                t.pnl for t in trades
                if t.start_time >= start_date and t.end_time <= end_date
            ])) * sqrt(avg_nr_of_trades)

        returns_tms = returns_tms.loc[start_date:end_date]
        if not returns_tms.empty:
            ticker_evaluation.annualised_return = cagr(returns_tms,
                                                       Frequency.DAILY)

        return ticker_evaluation
Ejemplo n.º 18
0
    def test_compute_container_hash__series(self):
        list_of_data = list(range(200))
        qfseries_1 = QFSeries(data=list_of_data)
        qfseries_2 = QFSeries(data=list_of_data)
        returns_series = ReturnsSeries(data=list_of_data)
        prices_series = PricesSeries(data=list_of_data)

        self.assertEqual(compute_container_hash(qfseries_1),
                         compute_container_hash(qfseries_2))
        self.assertEqual(compute_container_hash(qfseries_1),
                         compute_container_hash(returns_series))
        self.assertEqual(compute_container_hash(qfseries_1),
                         compute_container_hash(prices_series))
Ejemplo n.º 19
0
    def test_get_distance_to_equal_risk_contrib(self):
        factors_covariance = self.factors_df.cov()
        weights = QFSeries([0.5, 0.5], index=self.factors_df.columns)
        actual_result = RiskContributionAnalysis.get_distance_to_equal_risk_contrib(
            factors_covariance, weights)
        expected_result = 0.342309791791
        self.assertAlmostEqual(actual_result, expected_result, places=10)

        weights = QFSeries([0.25, 0.75], index=self.factors_df.columns)
        actual_result = RiskContributionAnalysis.get_distance_to_equal_risk_contrib(
            factors_covariance, weights)
        expected_result = 0.72012126510882146
        self.assertAlmostEqual(actual_result, expected_result, places=10)
Ejemplo n.º 20
0
    def test_get_risk_contribution_optimised(self):
        weights = QFSeries([0.5, 0.5], index=self.factors_df.columns)
        actual_result = RiskContributionAnalysis.get_risk_contribution_optimised(
            assets_rets=self.factors_df, weights_of_assets=weights)
        expected_result = QFSeries([0.328845104104390, 0.671154895895610],
                                   index=self.factors_df.columns)
        assert_series_equal(expected_result, actual_result)

        weights = QFSeries([0.25, 0.75], index=self.factors_df.columns)
        actual_result = RiskContributionAnalysis.get_risk_contribution_optimised(
            assets_rets=self.factors_df, weights_of_assets=weights)
        expected_result = QFSeries([0.139939367445589, 0.860060632554411],
                                   index=self.factors_df.columns)
        assert_series_equal(expected_result, actual_result)
Ejemplo n.º 21
0
    def _generate_exposure_values(self, config: FastAlphaModelTesterConfig,
                                  data_handler: FastDataHandler,
                                  tickers: Sequence[Ticker]):
        """
        For the given Alpha model and its parameters, generates the dataframe containing all exposure values, that
        will be returned by the model through signals.
        """

        model = config.generate_model(data_handler)

        current_exposures_values = QFSeries(
            index=pd.Index(tickers, name=TICKERS))
        current_exposures_values[:] = 0.0

        backtest_dates = pd.date_range(self._start_date,
                                       self._end_date,
                                       freq="B")

        exposure_values_df = QFDataFrame(index=backtest_dates,
                                         columns=pd.Index(tickers,
                                                          name=TICKERS))

        for ticker in tickers:
            if isinstance(ticker, FutureTicker):
                # Even if the tickers were already initialize, during pickling process, the data handler and timer
                # information is lost
                ticker.initialize_data_provider(self._timer, data_handler)

        for i, curr_datetime in enumerate(backtest_dates):
            new_exposures = QFSeries(index=tickers)
            self._timer.set_current_time(curr_datetime)

            for j, ticker, curr_exp_value in zip(count(), tickers,
                                                 current_exposures_values):
                curr_exp = Exposure(curr_exp_value) if is_finite_number(
                    curr_exp_value) else None
                try:
                    new_exp = model.calculate_exposure(ticker, curr_exp)
                except NoValidTickerException:
                    new_exp = None
                new_exposures.iloc[
                    j] = new_exp.value if new_exp is not None else None

            # assuming that we always follow the new_exposures from strategy, disregarding confidence levels
            # and expected moves, looking only at the suggested exposure
            current_exposures_values = new_exposures
            exposure_values_df.iloc[i, :] = current_exposures_values.iloc[:]

        exposure_values_df = exposure_values_df.dropna(axis=1, how="all")
        return exposure_values_df
Ejemplo n.º 22
0
    def setUpClass(cls):
        cls.initial_cash = 1000000  # 1M
        cls.contract = Contract('AAPL US Equity', security_type='STK', exchange='NYSE')
        cls.contract_size = 75
        cls.fut_contract = Contract('CTZ9 Comdty', security_type='FUT', exchange='CME', contract_size=cls.contract_size)

        tickers = [DummyTicker(cls.contract.symbol), DummyTicker(cls.fut_contract.symbol)]
        cls.prices_series = QFSeries(data=[120, 250], index=tickers)
        cls.prices_up = QFSeries(data=[130, 270], index=tickers)
        cls.prices_down = QFSeries(data=[100, 210], index=tickers)

        cls.start_time = str_to_date('2017-01-01')
        cls.random_time = str_to_date('2017-02-02')
        cls.end_time = str_to_date('2018-02-03')
        cls.trades_generator = TradesGenerator()
Ejemplo n.º 23
0
    def setUpClass(cls):
        cls.initial_cash = 1000000  # 1M
        cls.ticker = DummyTicker('AAPL US Equity', SecurityType.STOCK)
        cls.point_value = 75
        cls.fut_ticker = DummyTicker('CTZ9 Comdty', SecurityType.FUTURE, cls.point_value)

        tickers = [cls.ticker, cls.fut_ticker]
        cls.prices_series = QFSeries(data=[120, 250], index=tickers)
        cls.prices_up = QFSeries(data=[130, 270], index=tickers)
        cls.prices_down = QFSeries(data=[100, 210], index=tickers)

        cls.start_time = str_to_date('2017-01-01')
        cls.random_time = str_to_date('2017-02-02')
        cls.end_time = str_to_date('2018-02-03')
        cls.trades_generator = TradesGenerator()
Ejemplo n.º 24
0
    def test_concat_series(self):
        index = [1, 2, 3]
        series_1 = QFSeries(data=[17., 15., 16.], index=index)
        series_2 = QFSeries(data=[18., 19., 20.], index=index)

        df = pd.concat([series_1, series_2], axis=1)
        self.assertEqual(type(df), QFDataFrame)
        self.assertEqual({s.dtypes
                          for s in [series_1, series_2]}, set(df.dtypes))

        series = pd.concat([series_1, series_2], axis=0)
        self.assertEqual(type(series), QFSeries)
        self.assertEqual("float64", series.dtypes)
        self.assertEqual({s.dtypes
                          for s in [series_1, series_2]}, {series.dtypes})
Ejemplo n.º 25
0
 def calculate_relative_rank_logits(self, strategies_names: List):
     """
     Computes relative ranks for the strategies named in the strategies_names list and afterwards
     calculates the logits. High logit values imply a consistency between IS and OOS performances,
     which indicates a low lever of backtest overfitting.
     """
     self.create_is_oos_rankings()
     num_of_strategies = len(self.multiple_returns_timeseries.columns)
     relative_ranks = QFSeries(data=[
         oos_ranking["rank"].loc[best_is_strategy] / (num_of_strategies + 1)
         for oos_ranking, best_is_strategy in zip(self.oos_ranking,
                                                  strategies_names)
     ])
     logits = np.log(relative_ranks.divide(1.0 - relative_ranks))
     return logits
Ejemplo n.º 26
0
    def _get_exposure(self, regressors_tickers: List, regression_len: int):
        df = QFDataFrame()
        for portfolio_date, positions in self.positions_history.iterrows():
            positions = positions.dropna()
            positions_tickers = positions.index.tolist()
            exposure = QFSeries([x.total_exposure for x in positions])
            portfolio_net_liquidation = self.portfolio_nav_history.asof(
                portfolio_date)
            positions_allocation = exposure / portfolio_net_liquidation
            from_date = portfolio_date - RelativeDelta(months=regression_len)
            coefficients, current_regressors_tickers = self._get_coefficients_and_current_regressors_tickers(
                regressors_tickers, positions_tickers, positions_allocation,
                from_date, portfolio_date)

            df = df.append(
                QFDataFrame(
                    {
                        col: val
                        for val, col in zip(coefficients,
                                            current_regressors_tickers)
                    },
                    index=[portfolio_date]))

        # remove missing regressors
        df = df.dropna(axis=1, how='all')
        return df
Ejemplo n.º 27
0
    def test_infer_interval(self):
        expected_interval = pd.Timedelta("1 day")
        expected_frequency = 1
        actual_interval, actual_frequency = self.test_log_returns_tms.infer_interval()
        self.assertEqual(expected_interval, actual_interval)
        self.assertEqual(expected_frequency, actual_frequency)

        expected_interval = pd.Timedelta("1 day")
        expected_frequency = 2 / 3
        dates = pd.date_range('2016-04-01', periods=4, freq='b')
        test_series = QFSeries(data=[0, 0, 0, 0], index=dates)

        actual_interval, actual_frequency = test_series.infer_interval()

        self.assertEqual(expected_interval, actual_interval)
        self.assertEqual(expected_frequency, actual_frequency)
Ejemplo n.º 28
0
def ta_series(func: Callable, *args, **kwargs) -> QFSeries:
    """
    Function created to allow using TA-Lib functions with QFSeries.

    Parameters
    ----------
    func
        talib function: for example talib.MA
    args
        time series arguments to the function. They are all passed as QFSeries.
        for example: 'close' or 'high, low, close' where each argument is a QFSeries.
    kwargs
        additional arguments to the function. for example: 'timeperiod=10' or 'timeperiod=timeperiod, matype=i'.
        All additional arguments have to be passed as keyword arguments.

    Returns
    -------
    QFSeries
        Output from the talib function encapsulated in a QFSeries
    """

    series_list = list(map(lambda series: series.values, args))

    result = func(*series_list, **kwargs)
    result = QFSeries(index=args[0].index, data=result)
    return result
Ejemplo n.º 29
0
    def _periods_from_int_series(
            cls, series: QFSeries) -> Sequence[Tuple[datetime, datetime]]:
        """
        Converts a time series with multiple 1/0 values into a condensed list of date ranges specifying where
        the rectangles should begin and end.

        For example:
            1920-03-31    0.0
            1920-06-30    1.0
            1920-09-30    1.0
            1920-12-31    0.0

        For this series, the area from 1920-06-30 to 1920-09-30 will be highlighted.
        """
        result = []  # List[Tuple[start_date, end_date]]

        start_date = None
        for index, value in series.iteritems():
            if value < 1.0 and start_date is not None:
                result.append((start_date, index))
                start_date = None
            if value >= 1.0 and start_date is None:
                start_date = index

        return result
Ejemplo n.º 30
0
 def _setup_r_square_of_each_predictor(self):
     regressors_df = self.input_data.regressors_df
     corr_matrix = regressors_df.corr()
     corr_matrix = cast_dataframe(corr_matrix, output_type=QFDataFrame)
     vif = np.diagonal(inv(corr_matrix))
     r_squared_values = 1 - (1 / vif)
     self.r_squared_of_each_predictor = QFSeries(data=r_squared_values, index=regressors_df.columns.copy())