Example #1
0
    def _add_up_and_down_trend_strength(self, prices_df: QFDataFrame):
        def _down_trend_fun(df):
            return down_trend_strength(df, self.use_next_open_instead_of_close)

        def _up_trend_fun(df):
            return up_trend_strength(df, self.use_next_open_instead_of_close)

        up_trend_strength_tms = prices_df.rolling_time_window(window_length=self.window_len, step=1,
                                                              func=_down_trend_fun)
        down_trend_strength_tms = prices_df.rolling_time_window(window_length=self.window_len, step=1,
                                                                func=_up_trend_fun)
        chart = LineChart()
        up_trend_elem = DataElementDecorator(up_trend_strength_tms)
        down_trend_elem = DataElementDecorator(down_trend_strength_tms)
        chart.add_decorator(up_trend_elem)
        chart.add_decorator(down_trend_elem)
        legend = LegendDecorator(legend_placement=Location.BEST, key='legend')
        legend.add_entry(up_trend_elem, 'Up trend strength')
        legend.add_entry(down_trend_elem, 'Down trend strength')
        chart.add_decorator(legend)
        title = "Strength of the up and down trend - rolling {} days".format(self.window_len)
        title_decorator = TitleDecorator(title, key="title")
        chart.add_decorator(title_decorator)
        self._add_axes_position_decorator(chart)
        self.document.add_element(ChartElement(chart, figsize=self.image_size, dpi=self.dpi))
    def _add_gini_coefficient_chart(self):
        chart = LineChart(rotate_x_axis=False)

        position_decorator = AxesPositionDecorator(*self.full_image_axis_position)
        chart.add_decorator(position_decorator)

        # Get the assets history
        assets_history = self.backtest_result.portfolio.positions_history()
        assets_history = assets_history.applymap(
            lambda x: x.total_exposure if isinstance(x, BacktestPositionSummary) else 0)

        def gini(group):
            # Function computing the Gini coefficients for each row
            group = group.abs()
            ranks = group.rank(ascending=True)
            mean_value = group.mean()
            samples = group.size
            group = group * (2 * ranks - samples - 1)
            return group.sum() / (samples * samples * mean_value)

        assets_history = assets_history.stack(dropna=False).groupby(level=0).apply(gini).to_frame(name="Gini "
                                                                                                       "coefficient")

        assets_history_decorator = DataElementDecorator(assets_history)
        chart.add_decorator(assets_history_decorator)

        # Add title
        title_decorator = TitleDecorator("Concentration of assets - Gini coefficient")
        chart.add_decorator(title_decorator)

        self.document.add_element(ChartElement(chart, figsize=self.full_image_size, dpi=self.dpi))
Example #3
0
def create_gross_leverage_chart(gross_lev: QFSeries) -> LineChart:
    """
    Creates a line chart showing gross leverage based on the specified gross leverage values.

    Parameters
    ----------
    gross_lev: QFSeries
        Gross leverage as returned by the extract_rets_pos_txn_from_zipline function.

    Returns
    -------
    LineChart
        Created line chart
    """
    result = LineChart()

    result.add_decorator(
        DataElementDecorator(gross_lev, linewidth=0.5, color="g"))

    result.add_decorator(
        HorizontalLineDecorator(gross_lev.mean(),
                                color="g",
                                linestyle="--",
                                linewidth=3))

    result.add_decorator(TitleDecorator("Gross leverage"))
    result.add_decorator(AxesLabelDecorator(y_label="Gross leverage"))
    return result
Example #4
0
    def _add_assets_number_in_portfolio_chart(self):
        chart = LineChart(rotate_x_axis=False)
        chart.add_decorator(AxesPositionDecorator(*self.full_image_axis_position))
        legend = LegendDecorator(key="legend_decorator")

        positions_history = self.backtest_result.portfolio.positions_history()

        # Find all not NaN values (not NaN values indicate that the position was open for this contract at that time)
        # and count their number for each row (for each of the dates)
        number_of_contracts = positions_history.notna().sum(axis=1)
        number_of_contracts_decorator = DataElementDecorator(number_of_contracts)
        chart.add_decorator(number_of_contracts_decorator)
        legend.add_entry(number_of_contracts_decorator, "Contracts")

        # Group tickers by name and for each name and date check if there was at least one position open with any
        # of the corresponding tickers. Finally sum all the assets that had a position open on a certain date.
        number_of_assets = positions_history.groupby(by=lambda ticker: ticker.name, axis='columns') \
            .apply(lambda x: x.notna().any(axis=1)).sum(axis=1)
        number_of_assets_decorator = DataElementDecorator(number_of_assets)
        chart.add_decorator(number_of_assets_decorator)
        legend.add_entry(number_of_assets_decorator, "Assets")

        chart.add_decorator(TitleDecorator("Number of assets in the portfolio"))
        chart.add_decorator(legend)
        chart.add_decorator(AxesLabelDecorator(y_label="Number of contracts / assets"))

        self.document.add_element(ChartElement(chart, figsize=self.full_image_size, dpi=self.dpi))
Example #5
0
    def cooks_distance_chart(self) -> LineChart:
        cooks_dist = self.model.cooks_distance_tms
        chart = LineChart()

        colors = cycle(Chart.get_axes_colors())
        color = next(colors)

        marker_props = {'alpha': 0.7}
        stemline_props = {'linestyle': '-.', 'linewidth': 0.2}
        baseline_props = {'visible': False}
        marker_props['markeredgecolor'] = color
        marker_props['markerfacecolor'] = color
        stemline_props['color'] = color

        data_elem = StemDecorator(cooks_dist,
                                  marker_props=marker_props,
                                  stemline_props=stemline_props,
                                  baseline_props=baseline_props)

        chart.add_decorator(data_elem)
        chart.add_decorator(TitleDecorator("Cook's Distance"))
        chart.add_decorator(
            AxesLabelDecorator(y_label="max change of coefficients"))

        return chart
Example #6
0
    def __get_perf_chart(self, series_list, is_large_chart):
        strategy = series_list[0].to_prices(
            1)  # the main strategy should be the first series
        log_scale = True if strategy[
            -1] > 10 else False  # use log scale for returns above 1 000 %

        if is_large_chart:
            chart = LineChart(start_x=strategy.index[0],
                              end_x=strategy.index[-1],
                              log_scale=log_scale)
            position_decorator = AxesPositionDecorator(
                *self.full_image_axis_position)
            chart.add_decorator(position_decorator)
        else:
            chart = LineChart(log_scale=log_scale, rotate_x_axis=True)

        line_decorator = HorizontalLineDecorator(1, key="h_line", linewidth=1)
        chart.add_decorator(line_decorator)
        legend = LegendDecorator()
        for series in series_list:
            strategy_tms = series.to_prices(1)
            series_elem = DataElementDecorator(strategy_tms)
            chart.add_decorator(series_elem)
            legend.add_entry(series_elem, strategy_tms.name)

        chart.add_decorator(legend)
        title_decorator = TitleDecorator("Strategy Performance", key="title")
        chart.add_decorator(title_decorator)

        return chart
Example #7
0
    def risk_contribution_chart(self) -> BarChart:
        colors_palette = Chart.get_axes_colors()

        tickers = self.model.input_data.regressors_df.columns.values
        names = [self._get_security_name(ticker) for ticker in tickers]
        risk_contributions = QFSeries(data=self.model.risk_contribution.values,
                                      index=pd.Index(names))

        index_translator = self._get_index_translator(labels=names)
        bar_chart = BarChart(orientation=Orientation.Horizontal,
                             index_translator=index_translator,
                             thickness=self._bars_width,
                             align='center')
        bar_chart.add_decorator(
            DataElementDecorator(risk_contributions, color=colors_palette[1]))
        bar_chart.add_decorator(TitleDecorator("Risk contribution"))
        bar_chart.add_decorator(
            AxesLabelDecorator(x_label="risk contribution [%]"))
        bar_chart.add_decorator(
            AxesFormatterDecorator(x_major=PercentageFormatter()))
        labels = ('{:.2f}'.format(value * 100) for value in risk_contributions)
        self._add_labels_for_bars(bar_chart,
                                  risk_contributions,
                                  labels,
                                  margin=0.001)

        return bar_chart
Example #8
0
    def _get_distribution_plot(self, data_series: SimpleReturnsSeries, title: str, bins: Union[int, str] = 50,
                               crop: bool = False):
        colors = Chart.get_axes_colors()

        if crop:
            start_x = np.quantile(data_series, 0.01)
            end_x = np.quantile(data_series, 0.99)
            chart = HistogramChart(data_series, bins=bins, start_x=start_x, end_x=end_x)
        else:
            chart = HistogramChart(data_series, bins=bins)

        # Only show whole numbers on the y-axis.
        y_axis_locator = MaxNLocator(integer=True)
        axes_locator_decorator = AxesLocatorDecorator(y_major=y_axis_locator, key="axes_locator")
        chart.add_decorator(axes_locator_decorator)

        # Add an average line.
        avg_line = VerticalLineDecorator(data_series.mean(), color=colors[1],
                                         key="average_line_decorator", linestyle="--", alpha=0.8)
        chart.add_decorator(avg_line)

        # Add a legend.
        legend = LegendDecorator(key="legend_decorator")
        legend.add_entry(avg_line, "Mean")
        chart.add_decorator(legend)

        # Add a title.
        title_decorator = TitleDecorator(title, key="title")
        chart.add_decorator(title_decorator)
        chart.add_decorator(AxesLabelDecorator(title, "Occurrences"))

        position_decorator = AxesPositionDecorator(*self.full_image_axis_position)
        chart.add_decorator(position_decorator)

        return chart
Example #9
0
    def historical_performance_chart(self) -> LineChart:
        frequency = self.model.input_data.frequency
        analysed_tms = self.model.input_data.analysed_tms
        fitted_tms = self.model.fitted_tms

        cumulative_fund_rets = analysed_tms.to_prices(initial_price=1.0,
                                                      frequency=frequency) - 1
        cumulative_fit_rets = fitted_tms.to_prices(initial_price=1.0,
                                                   frequency=frequency) - 1

        hist_performance_chart = LineChart()
        fund_cummulative_rets_data_elem = DataElementDecorator(
            cumulative_fund_rets)
        fit_cummulative_rets_data_elem = DataElementDecorator(
            cumulative_fit_rets)

        legend_decorator = LegendDecorator(
            legend_placement=Location.LOWER_RIGHT)
        legend_decorator.add_entry(fund_cummulative_rets_data_elem,
                                   self._get_security_name(analysed_tms.name))
        legend_decorator.add_entry(fit_cummulative_rets_data_elem, 'Fit')

        hist_performance_chart.add_decorator(fund_cummulative_rets_data_elem)
        hist_performance_chart.add_decorator(fit_cummulative_rets_data_elem)

        hist_performance_chart.add_decorator(
            TitleDecorator("Historical Performance"))
        hist_performance_chart.add_decorator(
            AxesLabelDecorator(y_label="Cumulative return"))
        hist_performance_chart.add_decorator(legend_decorator)
        hist_performance_chart.add_decorator(
            AxesFormatterDecorator(y_major=PercentageFormatter()))

        return hist_performance_chart
Example #10
0
    def _create_chart(self, df: QFDataFrame, title: str):
        chart = LineChart()
        # Place legend on bottom right corner of plot
        legend = LegendDecoratorCustomPosition(
            legend_placement=AxisLocation.LOWER_LEFT)
        cmap = get_cmap("tab10", len(df.columns))

        # iterate columns
        for column, label, color_index in zip(df.columns, df.columns.values,
                                              range(0, cmap.N)):
            data = df.loc[:, column]
            data_value_decorator = DataElementDecorator(
                data, color=cmap(color_index))
            chart.add_decorator(data_value_decorator)
            legend.add_entry(data_value_decorator, label)

        chart.add_decorator(
            AxesFormatterDecorator(
                x_major=DateFormatter(fmt=str(DateFormat.YEAR_DOT_MONTH)),
                y_major=StrMethodFormatter("{x:.2f}"),
            ))

        chart.add_decorator(AxesPositionDecorator(*self.axis_position))
        chart.add_decorator(TitleDecorator(title))
        chart.add_decorator(legend)
        return chart
Example #11
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
Example #12
0
    def _get_histogram_chart(self):
        colors = Chart.get_axes_colors()
        chart = HistogramChart(self.returns_of_trades * 100)  # expressed in %
        # Format the x-axis so that its labels are shown as a percentage.
        x_axis_formatter = FormatStrFormatter("%0.0f%%")
        axes_formatter_decorator = AxesFormatterDecorator(x_major=x_axis_formatter, key="axes_formatter")
        chart.add_decorator(axes_formatter_decorator)
        # Only show whole numbers on the y-axis.
        y_axis_locator = MaxNLocator(integer=True)
        axes_locator_decorator = AxesLocatorDecorator(y_major=y_axis_locator, key="axes_locator")
        chart.add_decorator(axes_locator_decorator)

        # Add an average line.
        avg_line = VerticalLineDecorator(self.returns_of_trades.values.mean(), color=colors[1],
                                         key="average_line_decorator", linestyle="--", alpha=0.8)
        chart.add_decorator(avg_line)

        # Add a legend.
        legend = LegendDecorator(key="legend_decorator")
        legend.add_entry(avg_line, "Mean")
        chart.add_decorator(legend)

        # Add a title.
        title = TitleDecorator("Distribution of Trades", key="title_decorator")
        chart.add_decorator(title)
        chart.add_decorator(AxesLabelDecorator("Return", "Occurrences"))
        return chart
def create_returns_distribution(returns: QFSeries, frequency: Frequency = Frequency.MONTHLY, title: str = None) -> \
        HistogramChart:
    """
    Creates a new returns distribution histogram with the specified frequency.

    Parameters
    ----------
    returns: QFSeries
        The returns series to use in the histogram.
    frequency: Frequency
        frequency of the returns after aggregation
    title
        title of the chart
    Returns
    -------
    HistogramChart
        A new ``HistogramChart`` instance.
    """
    colors = Chart.get_axes_colors()
    aggregate_returns = get_aggregate_returns(returns,
                                              frequency,
                                              multi_index=True).multiply(100)

    chart = HistogramChart(aggregate_returns)

    # Format the x-axis so that its labels are shown as a percentage.
    x_axis_formatter = FormatStrFormatter("%.0f%%")
    axes_formatter_decorator = AxesFormatterDecorator(x_major=x_axis_formatter,
                                                      key="axes_formatter")
    chart.add_decorator(axes_formatter_decorator)
    # Only show whole numbers on the y-axis.
    y_axis_locator = MaxNLocator(integer=True)
    axes_locator_decorator = AxesLocatorDecorator(y_major=y_axis_locator,
                                                  key="axes_locator")
    chart.add_decorator(axes_locator_decorator)

    # Add an average line.
    avg_line = VerticalLineDecorator(aggregate_returns.values.mean(),
                                     color=colors[1],
                                     key="average_line_decorator",
                                     linestyle="--",
                                     alpha=0.8)
    chart.add_decorator(avg_line)

    # Add a legend.
    legend = LegendDecorator(key="legend_decorator")
    legend.add_entry(avg_line, "Mean")
    chart.add_decorator(legend)

    # Add a title.
    if title is None:
        title = "Distribution of " + str(frequency).capitalize() + " Returns"
    title = TitleDecorator(title, key="title_decorator")
    chart.add_decorator(title)
    chart.add_decorator(AxesLabelDecorator("Returns", "Occurrences"))

    return chart
    def _add_concentration_of_portfolio_chart(self, top_assets_numbers: tuple = (1, 5)):
        chart = LineChart(rotate_x_axis=False)

        position_decorator = AxesPositionDecorator(*self.full_image_axis_position)
        chart.add_decorator(position_decorator)

        # Define a legend
        legend = LegendDecorator(key="legend_decorator")

        # Add y label
        label_decorator = AxesLabelDecorator(y_label="Mean total exposure of top assets")
        chart.add_decorator(label_decorator)

        # Add top asset contribution
        positions_history = self.backtest_result.portfolio.positions_history()
        if positions_history.empty:
            raise ValueError("No positions found in positions history")

        positions_history = positions_history.applymap(
            lambda x: x.total_exposure if isinstance(x, BacktestPositionSummary) else 0)

        # Map all the single contracts onto tickers (including future tickers) and take the maximal total exposure for
        # each of the groups - in case if two contracts for a single asset will be included in the open positions in
        # the portfolio at any point of time, only one (with higher total exposure) will be considered while generating
        # the top assets plot
        def contract_to_ticker(c: Contract):
            return self.backtest_result.portfolio.contract_ticker_mapper. \
                contract_to_ticker(c, strictly_to_specific_ticker=False)

        assets_history = positions_history.rename(columns=contract_to_ticker)
        assets_history = assets_history.groupby(level=0, axis=1).apply(func=(
            lambda x: x.abs().max(axis=1).astype(float)
        ))

        for assets_number in top_assets_numbers:
            # For each date (row), find the top_assets largest assets and compute the mean value of their market value
            top_assets_mean_values = assets_history.stack(dropna=False).groupby(level=0).apply(
                lambda group: group.nlargest(assets_number).mean()
            ).resample('D').last()
            # Divide the computed mean values by the portfolio value, for each of the dates
            top_assets_percentage_value = top_assets_mean_values / self.backtest_result.portfolio.portfolio_eod_series()

            concentration_top_asset = DataElementDecorator(top_assets_percentage_value)
            chart.add_decorator(concentration_top_asset)

            # Add to legend
            legend.add_entry(concentration_top_asset, "TOP {} assets".format(assets_number))

        # Add title
        title_decorator = TitleDecorator("Concentration of assets")
        chart.add_decorator(title_decorator)

        # Add legend
        chart.add_decorator(legend)

        self.document.add_element(ChartElement(chart, figsize=self.full_image_size, dpi=self.dpi))
Example #15
0
 def _crete_single_line_chart(self, measure_name, parameters, values, tickers):
     result_series = QFSeries(data=values, index=parameters)
     line_chart = LineChart()
     data_element = DataElementDecorator(result_series)
     line_chart.add_decorator(data_element)
     line_chart.add_decorator(TitleDecorator(self._get_chart_title(tickers, measure_name)))
     param_names = self._get_param_names()
     line_chart.add_decorator(AxesLabelDecorator(x_label=param_names[0], y_label=measure_name))
     self._resize_chart(line_chart)
     return line_chart
Example #16
0
    def _get_leverage_chart(self,
                            leverage: QFSeries,
                            rotate_x_axis: bool = False):
        chart = LineChart(rotate_x_axis=rotate_x_axis)

        series_elem = DataElementDecorator(leverage)
        chart.add_decorator(series_elem)

        title_decorator = TitleDecorator("Leverage over time", key="title")
        chart.add_decorator(title_decorator)
        return chart
Example #17
0
    def _add_rolling_alpha_and_beta(self, timeseries_list):
        freq = timeseries_list[0].get_frequency()
        timeseries_list = [
            tms.dropna().to_simple_returns() for tms in timeseries_list
        ]
        df = pd.concat(timeseries_list, axis=1).fillna(0)

        rolling_window_len = int(freq.value / 2)  # 6M rolling
        step = round(freq.value / 6)  # 2M shift

        legend = LegendDecorator()
        chart = LineChart(start_x=df.index[0], end_x=df.index[-1])
        line_decorator = HorizontalLineDecorator(0, key="h_line", linewidth=1)
        chart.add_decorator(line_decorator)

        def alpha_function(df_in_window):
            strategy_returns = df_in_window.iloc[:, 0]
            benchmark_returns = df_in_window.iloc[:, 1]
            beta, alpha, _, _, _ = stats.linregress(benchmark_returns,
                                                    strategy_returns)
            return beta, alpha

        rolling = df.rolling_time_window(rolling_window_len, step,
                                         alpha_function)
        rolling = pd.DataFrame([[b, a] for b, a in rolling.values],
                               columns=["beta", "alpha"],
                               index=rolling.index)

        rolling_element = DataElementDecorator(rolling["beta"])
        chart.add_decorator(rolling_element)
        legend.add_entry(rolling_element, "beta")

        rolling_element = DataElementDecorator(rolling["alpha"],
                                               use_secondary_axes=True)
        chart.add_decorator(rolling_element)
        legend.add_entry(rolling_element, "alpha")

        chart.add_decorator(legend)
        chart.add_decorator(
            AxesFormatterDecorator(use_secondary_axes=True,
                                   y_major=PercentageFormatter(".1f")))

        # modify axes position to make secondary scale visible
        axes_position = list(self.full_image_axis_position)
        axes_position[2] = axes_position[2] - 0.07
        position_decorator = AxesPositionDecorator(*axes_position)
        chart.add_decorator(position_decorator)

        title_str = "Rolling alpha and beta [{} {} samples]".format(
            rolling_window_len, freq)
        title_decorator = TitleDecorator(title_str, key="title")
        chart.add_decorator(title_decorator)
        self.document.add_element(
            ChartElement(chart, figsize=self.full_image_size, dpi=self.dpi))
Example #18
0
    def _add_assets_number_in_portfolio_chart(self):
        chart = LineChart(rotate_x_axis=False)
        legend = LegendDecorator(key="legend_decorator")

        position_decorator = AxesPositionDecorator(
            *self.full_image_axis_position)
        chart.add_decorator(position_decorator)

        positions_history = self.backtest_result.portfolio.positions_history()

        # Find all not NaN values (not NaN values indicate that the position was open for this contract at that time)
        # and count their number for each row (for each of the dates)
        number_of_contracts = positions_history.notnull().sum(axis=1)
        number_of_contracts_decorator = DataElementDecorator(
            number_of_contracts)

        chart.add_decorator(number_of_contracts_decorator)
        legend.add_entry(number_of_contracts_decorator, "Contracts")

        # Count number of assets in the portfolio (if on two contracts from same future family exist in the same time,
        # e.g. during rolling day, in the portfolio, they are counted as one asset)
        def contract_to_ticker(c: Contract):
            return self.backtest_result.portfolio.contract_ticker_mapper. \
                contract_to_ticker(c, strictly_to_specific_ticker=False)

        assets_history = positions_history.rename(columns=contract_to_ticker)
        assets_history = assets_history.groupby(level=0, axis=1).apply(func=(
            # For each asset, group all of the corresponding columns (each of which corresponds to one contract),
            # and check if at any given timestamp the "value" of any of the contracts was different than None - this
            # indicates that at this point of time a position concerning the given asset was open in the portfolio
            # (which in the resulting series will be denoted as 1, otherwise - 0, so that it will be possible to
            # sum positions of all open assets at any given point of time)
            lambda x: x.notna().any(axis=1).astype(int)))

        number_of_assets = assets_history.sum(axis=1)
        number_of_assets_decorator = DataElementDecorator(number_of_assets)
        chart.add_decorator(number_of_assets_decorator)
        legend.add_entry(number_of_assets_decorator, "Assets")

        # Add title
        title_decorator = TitleDecorator("Number of assets in the portfolio")
        chart.add_decorator(title_decorator)

        # Add legend
        chart.add_decorator(legend)

        # Add y label
        label_decorator = AxesLabelDecorator(
            y_label="Number of contracts / assets")
        chart.add_decorator(label_decorator)

        self.document.add_element(
            ChartElement(chart, figsize=self.full_image_size, dpi=self.dpi))
Example #19
0
    def _get_perf_chart(self):
        strategy_tms = self.returns_of_trades.to_prices(1)
        chart = LineChart()
        line_decorator = HorizontalLineDecorator(1, key="h_line", linewidth=1)
        chart.add_decorator(line_decorator)

        series_elem = DataElementDecorator(strategy_tms)
        chart.add_decorator(series_elem)

        title_decorator = TitleDecorator("Alpha Model Performance", key="title")
        chart.add_decorator(title_decorator)
        return chart
Example #20
0
    def _create_mse_debug_chart(self, alphas, chosen_solution, mean_square_errors, min_se_solution):
        mse_chart = LineChart()
        mean_square_errors_paths = QFDataFrame(data=mean_square_errors, index=pd.Index(alphas))
        mse_chart.add_decorator(TitleDecorator("Cross-validated avg. MSE of Elastic Net fit"))
        for _, path in mean_square_errors_paths.iteritems():
            mse_chart.add_decorator(DataElementDecorator(path))
        mse_chart.add_decorator(VerticalLineDecorator(x=min_se_solution, linestyle='-.'))
        mse_chart.add_decorator(VerticalLineDecorator(x=chosen_solution, linestyle='-'))
        mse_chart.plot()
        mse_chart.axes.invert_xaxis()

        return mse_chart
Example #21
0
    def _create_coeffs_debug_chart(self, alphas, chosen_solution, coeffs_path, min_se_solution):
        coeffs_chart = LineChart()
        coefficients_paths = QFDataFrame(data=coeffs_path, index=pd.Index(alphas))
        for _, path in coefficients_paths.iteritems():
            coeffs_chart.add_decorator(DataElementDecorator(path))
        coeffs_chart.add_decorator(TitleDecorator("Elastic Net (using Cross Validation)"))
        coeffs_chart.add_decorator(VerticalLineDecorator(x=min_se_solution, linestyle='-.'))
        coeffs_chart.add_decorator(VerticalLineDecorator(x=chosen_solution, linestyle='-'))
        coeffs_chart.plot()
        coeffs_chart.axes.invert_xaxis()

        return coeffs_chart
Example #22
0
    def _get_line_chart(self,
                        series: QFSeries,
                        title: str,
                        rotate_x_axis: bool = False):
        chart = LineChart(rotate_x_axis=rotate_x_axis)

        series_elem = DataElementDecorator(series)
        chart.add_decorator(series_elem)

        title_decorator = TitleDecorator(title, key="title")
        chart.add_decorator(title_decorator)
        return chart
Example #23
0
def create_return_quantiles(returns: QFSeries, live_start_date: datetime = None, x_axis_labels_rotation: int = 20) \
        -> BoxplotChart:
    """
    Creates a new return quantiles boxplot chart based on the returns specified.

    A swarm plot is also rendered on the chart if the ``live_start_date`` is specified.

    Parameters
    ----------
    returns
        The returns series to plot on the chart.
    live_start_date
        The live start date that will determine whether a swarm plot should be rendered.
    x_axis_labels_rotation

    Returns
    -------
    A new ``BoxplotChart`` instance.
    """

    simple_returns = returns.to_simple_returns()

    # case when we can plot IS together with OOS
    if live_start_date is not None:
        oos_returns = simple_returns.loc[simple_returns.index >= live_start_date]
        if len(oos_returns) > 0:
            in_sample_returns = simple_returns.loc[simple_returns.index < live_start_date]
            in_sample_weekly = get_aggregate_returns(in_sample_returns, Frequency.WEEKLY, multi_index=True)
            in_sample_monthly = get_aggregate_returns(in_sample_returns, Frequency.MONTHLY, multi_index=True)

            oos_weekly = get_aggregate_returns(oos_returns, Frequency.WEEKLY, multi_index=True)
            oos_monthly = get_aggregate_returns(oos_returns, Frequency.MONTHLY, multi_index=True)

            chart = BoxplotChart([in_sample_returns, oos_returns, in_sample_weekly,
                                  oos_weekly, in_sample_monthly, oos_monthly], linewidth=1)

            x_labels = ["daily IS", "daily OOS", "weekly IS", "weekly OOS", "monthly IS", "monthly OOS"]
            tick_decorator = AxisTickLabelsDecorator(labels=x_labels, axis=Axis.X, rotation=x_axis_labels_rotation)
        else:
            chart, tick_decorator = _get_simple_quantile_chart(simple_returns)

    else:  # case where there is only one set of data
        chart, tick_decorator = _get_simple_quantile_chart(simple_returns)

    # fixed_format_decorator = AxesFormatterDecorator(x_major=fixed_formatter)
    chart.add_decorator(tick_decorator)

    # Set title.
    title = TitleDecorator("Return Quantiles")
    chart.add_decorator(title)
    chart.add_decorator(AxesLabelDecorator(y_label="Returns"))
    return chart
def create_returns_bar_chart(
        returns: QFSeries,
        frequency: Frequency = Frequency.YEARLY) -> BarChart:
    """
    Constructs a new returns bar chart based on the returns specified. By default a new annual returns bar chart will
    be created.
    """
    colors = Chart.get_axes_colors()
    # Calculate data.
    aggregate_returns = get_aggregate_returns(returns,
                                              frequency,
                                              multi_index=True)
    data_series = QFSeries(aggregate_returns.sort_index(ascending=True))

    chart = BarChart(Orientation.Horizontal, align="center")
    chart.add_decorator(DataElementDecorator(data_series))
    chart.add_decorator(BarValuesDecorator(data_series))

    # Format the x-axis so that its labels are shown as a percentage.
    chart.add_decorator(AxesFormatterDecorator(x_major=PercentageFormatter()))

    # Format Y axis to make sure we have a tick for each year or 2 years
    if len(data_series) > 10:
        y_labels = data_series[data_series.index % 2 == 1].index
    else:
        y_labels = data_series.index
    chart.add_decorator(
        AxisTickLabelsDecorator(labels=y_labels,
                                axis=Axis.Y,
                                tick_values=y_labels))

    # Add an average line.
    avg_line = VerticalLineDecorator(aggregate_returns.values.mean(),
                                     color=colors[1],
                                     key="avg_line",
                                     linestyle="--",
                                     alpha=0.8)
    chart.add_decorator(avg_line)

    # Add a legend.
    legend = LegendDecorator(key="legend_decorator")
    legend.add_entry(avg_line, "Mean")
    chart.add_decorator(legend)

    # Add a title.
    title = TitleDecorator(str(frequency).capitalize() + " Returns",
                           key="title_decorator")
    chart.add_decorator(title)
    chart.add_decorator(AxesLabelDecorator("Returns", "Year"))

    return chart
Example #25
0
 def _create_single_heat_map(self, measure_name, result_df, tickers, min_v, max_v, third_param):
     chart = HeatMapChart(data=result_df, color_map=plt.get_cmap("coolwarm"), min_value=min_v, max_value=max_v)
     chart.add_decorator(AxisTickLabelsDecorator(labels=list(result_df.columns), axis=Axis.X))
     chart.add_decorator(AxisTickLabelsDecorator(labels=list(reversed(result_df.index)), axis=Axis.Y))
     chart.add_decorator(ValuesAnnotations())
     param_names = self._get_param_names()
     chart.add_decorator(AxesLabelDecorator(x_label=param_names[1], y_label=param_names[0]))
     if third_param is None:
         title = self._get_chart_title(tickers, measure_name)
     else:
         title = "{}, {} = {:0.2f}".format(self._get_chart_title(tickers, measure_name), param_names[2], third_param)
     chart.add_decorator(TitleDecorator(title))
     self._resize_chart(chart)
     return chart
Example #26
0
def create_holdings_chart(positions: QFDataFrame) -> LineChart:
    """
    Creates a line chart showing holdings per day based on the specified positions.

    Parameters
    ----------
    positions: QFDataFrame
        Positions as returned by the extract_rets_pos_txn_from_zipline function.

    Returns
    -------
    LineChart
        Created line chart
    """
    # Based on:
    # https://github.com/quantopian/pyfolio/blob/5d63df4ca6e0ead83f4bebf9860732d37f532026/pyfolio/plotting.py#L323
    result = LineChart()

    # Perform some calculations.
    positions = positions.copy().drop("cash", axis="columns")
    holdings = positions.apply(lambda x: np.sum(x != 0), axis="columns")
    holdings_by_month = holdings.resample("1M").mean()

    holdings_decorator = DataElementDecorator(holdings,
                                              color="steelblue",
                                              linewidth=1.5)
    result.add_decorator(holdings_decorator)
    holdings_by_month_decorator = DataElementDecorator(holdings_by_month,
                                                       color="orangered",
                                                       alpha=0.5,
                                                       linewidth=2)
    result.add_decorator(holdings_by_month_decorator)

    hline_decorator = HorizontalLineDecorator(holdings.values.mean(),
                                              linestyle="--")
    result.add_decorator(hline_decorator)

    legend = LegendDecorator()
    legend.add_entry(holdings_decorator, "Daily Holdings")
    legend.add_entry(holdings_by_month_decorator,
                     "Average Daily Holdings, by month")
    legend.add_entry(hline_decorator, "Average Daily Holdings, net")
    result.add_decorator(legend)

    result.add_decorator(TitleDecorator("Holdings per Day"))
    result.add_decorator(
        AxesLabelDecorator(y_label="Amount of holdings per Day"))

    return result
Example #27
0
 def _add_price_chart(self, prices_df: QFDataFrame):
     close_tms = prices_df[PriceField.Close]
     price_tms = close_tms.to_prices(1)
     chart = LineChart(start_x=price_tms.index[0], end_x=price_tms.index[-1])
     price_elem = DataElementDecorator(price_tms)
     chart.add_decorator(price_elem)
     line_decorator = HorizontalLineDecorator(1, key="h_line", linewidth=1)
     chart.add_decorator(line_decorator)
     legend = LegendDecorator()
     legend.add_entry(price_elem, "Close Price")
     chart.add_decorator(legend)
     title_decorator = TitleDecorator("Price of the instrument", key="title")
     chart.add_decorator(title_decorator)
     self._add_axes_position_decorator(chart)
     self.document.add_element(ChartElement(chart, figsize=self.image_size, dpi=self.dpi))
Example #28
0
    def _add_trend_strength_chart(self, prices_df: QFDataFrame):

        def _fun(df):
            return trend_strength(df, self.use_next_open_instead_of_close)

        trend_strength_tms = prices_df.rolling_time_window(window_length=self.window_len, step=1, func=_fun)

        chart = LineChart()
        trend_elem = DataElementDecorator(trend_strength_tms, color='black')
        chart.add_decorator(trend_elem)
        legend = LegendDecorator(legend_placement=Location.BEST, key='legend')
        legend.add_entry(trend_elem, 'Trend strength')
        chart.add_decorator(legend)
        title_decorator = TitleDecorator("Strength of the trend - rolling {} days".format(self.window_len), key="title")
        chart.add_decorator(title_decorator)
        self._add_axes_position_decorator(chart)
        self.document.add_element(ChartElement(chart, figsize=self.image_size, dpi=self.dpi))
Example #29
0
    def correlation_matrix_chart(self) -> HeatMapChart:
        data = self.model.correlation_matrix
        names = [
            self._get_security_name(ticker)
            for ticker in self.model.correlation_matrix.columns.values
        ]
        heatmap_chart = HeatMapChart(data, min_value=-1, max_value=1)

        heatmap_chart.add_decorator(
            AxisTickLabelsDecorator(axis=Axis.X, labels=names))
        heatmap_chart.add_decorator(
            AxisTickLabelsDecorator(axis=Axis.Y, labels=reversed(names)))
        heatmap_chart.add_decorator(ValuesAnnotations())
        heatmap_chart.add_decorator(ColorBar())
        heatmap_chart.add_decorator(TitleDecorator("Correlation matrix"))

        return heatmap_chart
Example #30
0
    def beta_and_alpha_chart(self,
                             benchmark_coefficients: Sequence[float] = None
                             ) -> BarChart:
        colors_palette = Chart.get_axes_colors()

        coeff_names = [
            self._get_security_name(ticker)
            for ticker in self.model.coefficients.index.values
        ]
        coeff_values = self.model.coefficients.values

        bars_colors = [colors_palette[0]] * len(self.model.coefficients)
        title = 'Coefficients of regressors'

        if self.model.input_data.is_fit_intercept:
            coeff_names = np.insert(coeff_names, 0, "intercept")
            coeff_values = np.insert(coeff_values, 0, self.model.intercept)
            bars_colors = ['gold'] + bars_colors

            if benchmark_coefficients is not None:
                raise ValueError(
                    "Benchmark coefficients aren't used when model contains a bias value (constant)"
                )
        elif benchmark_coefficients is not None:
            coeff_values -= benchmark_coefficients
            title = 'Relative coefficients of regressors'

        index_translator = self._get_index_translator(coeff_names)
        coefficients = QFSeries(index=pd.Index(coeff_names), data=coeff_values)

        bar_chart = BarChart(orientation=Orientation.Horizontal,
                             index_translator=index_translator,
                             thickness=self._bars_width,
                             align='center')

        bar_chart.add_decorator(
            DataElementDecorator(coefficients, color=bars_colors))
        bar_chart.add_decorator(TitleDecorator(title))
        bar_chart.add_decorator(AxesLabelDecorator(x_label="sensitivity"))

        labels = ['{:.2f}'.format(value) for value in coeff_values]
        self._add_labels_for_bars(bar_chart, coefficients, labels)

        return bar_chart