Пример #1
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
Пример #2
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
Пример #3
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
Пример #4
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
Пример #6
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))
Пример #7
0
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
Пример #8
0
    def _add_returns_distribution(self):
        if self.initial_risk is not None:
            returns = SimpleReturnsSeries(data=[t.percentage_pnl / self.initial_risk for t in self.trades])
            title = "Distribution of R multiples, Initial risk = {:.2%}".format(self.initial_risk)
            returns_histogram = self._get_distribution_plot(returns, title)
        else:
            returns = SimpleReturnsSeries(data=[t.percentage_pnl for t in self.trades])
            title = "Distribution of returns [%]"
            returns_histogram = self._get_distribution_plot(returns, title)

            # Format the x-axis so that its labels are shown as a percentage in case of percentage returns
            axes_formatter_decorator = AxesFormatterDecorator(x_major=PercentageFormatter(), key="axes_formatter")
            returns_histogram.add_decorator(axes_formatter_decorator)

        self.document.add_element(ChartElement(returns_histogram, figsize=self.full_image_size, dpi=self.dpi))
Пример #9
0
    def performance_attribution_chart(self) -> BarChart:
        colors_palette = Chart.get_axes_colors()

        unexplained_ret = self.model.unexplained_performance_attribution_ret
        factors_ret = self.model.factors_performance_attribution_ret
        fund_ret = self.model.fund_tms_analysis.cagr

        unexplained_name = "Unexplained"
        factors_names = [
            self._get_security_name(ticker)
            for ticker in self.model.coefficients.index.values
        ]

        fund_name = self._get_security_name(
            self.model.input_data.analysed_tms.name)

        all_values = [unexplained_ret] + list(factors_ret) + [fund_ret]
        all_names = [unexplained_name] + list(factors_names) + [fund_name]
        all_returns = SimpleReturnsSeries(data=all_values,
                                          index=pd.Index(all_names))

        colors = [
            colors_palette[0]
        ] + [colors_palette[1]] * len(factors_names) + [colors_palette[2]]

        index_translator = self._get_index_translator(labels=all_names)
        bar_chart = BarChart(orientation=Orientation.Horizontal,
                             index_translator=index_translator,
                             thickness=self._bars_width,
                             align='center')
        bar_chart.add_decorator(DataElementDecorator(all_returns,
                                                     color=colors))
        bar_chart.add_decorator(
            TitleDecorator("Attribution of Fund Annualised Return"))
        bar_chart.add_decorator(
            AxesLabelDecorator(x_label="annualised return [%]"))
        bar_chart.add_decorator(
            AxesFormatterDecorator(x_major=PercentageFormatter()))

        labels = ('{:.2f}'.format(value * 100) for value in all_returns)
        self._add_labels_for_bars(bar_chart, all_returns, labels)

        return bar_chart
Пример #10
0
    def _create_line_chart(self, rolling_values, title):
        line_chart = LineChart()
        legend = LegendDecorator()

        for column_name, values_tms in rolling_values.iteritems():
            coeff_tms_data_elem = DataElementDecorator(values_tms)
            line_chart.add_decorator(coeff_tms_data_elem)
            legend.add_entry(coeff_tms_data_elem, column_name)

        full_title_str = "".join([
            title,
            ' {:d} samples rolling'.format(self.rolling_model.window_size_)
        ])
        line_chart.add_decorator(TitleDecorator(full_title_str))
        line_chart.add_decorator(
            AxesFormatterDecorator(x_major=DateFormatter(
                fmt=str(DateFormat.YEAR_DOT_MONTH))))
        line_chart.add_decorator(legend)

        return line_chart
Пример #11
0
    def _get_rolling_ret_and_vol_chart(self, timeseries):
        freq = timeseries.get_frequency()

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

        tms = timeseries.to_prices(1)
        chart = LineChart(start_x=tms.index[0], end_x=tms.index[-1])
        line_decorator = HorizontalLineDecorator(0, key="h_line", linewidth=1)
        chart.add_decorator(line_decorator)

        legend = LegendDecorator()

        def tot_return(window):
            return PricesSeries(window).total_cumulative_return()

        def volatility(window):
            return get_volatility(PricesSeries(window), freq)

        functions = [tot_return, volatility]
        names = ['Rolling Return', 'Rolling Volatility']
        for func, name in zip(functions, names):
            rolling = tms.rolling_window(rolling_window_len, func, step=step)
            rolling_element = DataElementDecorator(rolling)
            chart.add_decorator(rolling_element)
            legend.add_entry(rolling_element, name)

        chart.add_decorator(legend)
        chart.add_decorator(
            AxesFormatterDecorator(y_major=PercentageFormatter(".0f")))

        position_decorator = AxesPositionDecorator(
            *self.full_image_axis_position)
        chart.add_decorator(position_decorator)
        title_str = "Rolling Stats [{} {} samples]".format(
            rolling_window_len, freq)

        title_decorator = TitleDecorator(title_str, key="title")
        chart.add_decorator(title_decorator)
        return chart
Пример #12
0
    def _add_rolling_chart(self):
        days_rolling = int(252 / 2)  # 6M rolling
        step = round(days_rolling / 5)

        strategy = self.strategy_series.to_prices(1)
        chart = LineChart(start_x=strategy.index[0], end_x=strategy.index[-1])
        line_decorator = HorizontalLineDecorator(0, key="h_line", linewidth=1)
        chart.add_decorator(line_decorator)

        legend = LegendDecorator()

        def tot_return(window):
            return PricesSeries(window).total_cumulative_return()

        def volatility(window):
            return get_volatility(PricesSeries(window), Frequency.DAILY)

        functions = [tot_return, volatility]
        names = ['Rolling Return', 'Rolling Volatility']
        for func, name in zip(functions, names):
            rolling = strategy.rolling_window(days_rolling, func, step=step)
            rolling_element = DataElementDecorator(rolling)
            chart.add_decorator(rolling_element)
            legend.add_entry(rolling_element, name)

        chart.add_decorator(legend)

        chart.add_decorator(
            AxesFormatterDecorator(y_major=PercentageFormatter(".0f")))

        left, bottom, width, height = self.full_image_axis_position
        position_decorator = AxesPositionDecorator(left, bottom, width, height)
        chart.add_decorator(position_decorator)

        title_decorator = TitleDecorator(
            "Rolling Statistics [6 Months]".format(days_rolling), key="title")
        chart.add_decorator(title_decorator)

        self.document.add_element(
            ChartElement(chart, figsize=self.full_image_size, dpi=self.dpi))
Пример #13
0
    def _add_simulation_results(self):
        """
        Generate a data frame consisting of a certain number of "scenarios" (each scenario denotes one single equity
        curve).
        """
        self.document.add_element(NewPageElement())
        self.document.add_element(HeadingElement(level=1, text="Monte Carlo simulations\n"))
        self.document.add_element(HeadingElement(level=2, text="Average number of trades per year: {}\n".format(
            int(self._average_number_of_trades_per_year()))))
        if self.initial_risk is not None:
            self.document.add_element(HeadingElement(level=2, text="Initial risk: {:.2%}".format(self.initial_risk)))

        scenarios_df, total_returns = self._get_scenarios()

        # Plot all the possible paths on a chart
        all_paths_chart = self._get_simulation_plot(scenarios_df)
        self.document.add_element(ChartElement(all_paths_chart, figsize=self.full_image_size, dpi=self.dpi))

        # Plot the distribution plot
        distribution_plot = self._get_distribution_plot(
            total_returns, title="Monte Carlo Simulations Distribution (one year % return)", bins=200, crop=True)
        # Format the x-axis so that its labels are shown as a percentage in case of percentage returns

        axes_formatter_decorator = AxesFormatterDecorator(x_major=PercentageFormatter(), key="axes_formatter")
        distribution_plot.add_decorator(axes_formatter_decorator)

        self.document.add_element(ChartElement(distribution_plot, figsize=self.full_image_size, dpi=self.dpi))

        simulations_summary_table = self._get_monte_carlos_simulator_outputs(scenarios_df, total_returns)
        self.document.add_element(simulations_summary_table)

        # Extract the results of each of the scenarios and summarize the data in the tables
        dist_summary_tables = self._get_distribution_summary_table(total_returns)
        self.document.add_element(dist_summary_tables)

        # Add the "Chances of dropping below" and "Simulations summary" tables
        ruin_chances_table = self._get_chances_of_dropping_below_table(scenarios_df)
        self.document.add_element(ruin_chances_table)
Пример #14
0
    def _get_rolling_chart(self, timeseries_list, rolling_function,
                           function_name):
        freq = timeseries_list[0].get_frequency()
        timeseries_list = [
            tms.dropna().to_prices(1) for tms in timeseries_list
        ]
        df = pd.concat(timeseries_list, axis=1).fillna(method='ffill')

        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)

        for _, tms in df.iteritems():
            rolling = tms.rolling_window(rolling_window_len,
                                         rolling_function,
                                         step=step)
            rolling_element = DataElementDecorator(rolling)
            chart.add_decorator(rolling_element)
            legend.add_entry(rolling_element, tms.name)

        chart.add_decorator(legend)
        chart.add_decorator(
            AxesFormatterDecorator(y_major=PercentageFormatter(".0f")))

        position_decorator = AxesPositionDecorator(
            *self.full_image_axis_position)
        chart.add_decorator(position_decorator)
        title_str = "{} - Rolling Stats [{} {} samples]".format(
            function_name, rolling_window_len, freq)

        title_decorator = TitleDecorator(title_str, key="title")
        chart.add_decorator(title_decorator)
        return chart
Пример #15
0
    def regressors_and_explained_variable_chart(self) -> LineChart:
        regressors_df = self.model.input_data.regressors_df
        fund_tms = self.model.input_data.analysed_tms

        chart = LineChart()
        legend = LegendDecorator()

        # add data to the chart and the legend
        marker_props_template = {'alpha': 0.5}
        stemline_props_template = {'linestyle': '-.', 'linewidth': 0.2}
        baseline_props = {'visible': False}

        regressors_and_fund_df = pd.concat([regressors_df, fund_tms], axis=1)
        colors = cycle(Chart.get_axes_colors())

        for ticker, series in regressors_and_fund_df.iteritems():
            marker_props = marker_props_template.copy()
            stemline_props = stemline_props_template.copy()

            color = next(colors)
            marker_props['markeredgecolor'] = color
            marker_props['markerfacecolor'] = color
            stemline_props['color'] = color
            data_elem = StemDecorator(series,
                                      marker_props=marker_props,
                                      stemline_props=stemline_props,
                                      baseline_props=baseline_props)
            chart.add_decorator(data_elem)
            legend.add_entry(data_elem, self._get_security_name(ticker))

        # add decorators to the chart
        chart.add_decorator(TitleDecorator("Returns"))
        chart.add_decorator(AxesLabelDecorator(y_label="return [%]"))
        chart.add_decorator(legend)
        chart.add_decorator(
            AxesFormatterDecorator(y_major=PercentageFormatter()))

        return chart
Пример #16
0
    def _get_rolling_chart(self, timeseries_list, rolling_function,
                           function_name):
        days_rolling = int(BUSINESS_DAYS_PER_YEAR / 2)  # 6M rolling
        step = round(days_rolling / 5)

        legend = LegendDecorator()
        chart = None

        for i, tms in enumerate(timeseries_list):
            if i == 0:
                chart = LineChart(start_x=tms.index[0], end_x=tms.index[-1])
                line_decorator = HorizontalLineDecorator(0,
                                                         key="h_line",
                                                         linewidth=1)
                chart.add_decorator(line_decorator)

            tms = tms.to_prices(1)
            rolling = tms.rolling_window(days_rolling,
                                         rolling_function,
                                         step=step)
            rolling_element = DataElementDecorator(rolling)
            chart.add_decorator(rolling_element)
            legend.add_entry(rolling_element, tms.name)

        chart.add_decorator(legend)
        chart.add_decorator(
            AxesFormatterDecorator(y_major=PercentageFormatter(".0f")))

        position_decorator = AxesPositionDecorator(
            *self.full_image_axis_position)
        chart.add_decorator(position_decorator)
        title_str = "{} - Rolling Stats [{} days]".format(
            function_name, days_rolling)

        title_decorator = TitleDecorator(title_str, key="title")
        chart.add_decorator(title_decorator)
        return chart
Пример #17
0
    def _add_relative_performance_chart(
            self,
            strategy_tms: QFSeries,
            benchmark_tms: QFSeries,
            chart_title: str = "Relative Performance",
            legend_subtitle: str = "Strategy - Benchmark"):
        diff = strategy_tms.to_simple_returns().subtract(
            benchmark_tms.to_simple_returns(), fill_value=0)
        diff = diff.to_prices(1) - 1

        chart = LineChart(start_x=diff.index[0],
                          end_x=diff.index[-1],
                          log_scale=False)
        position_decorator = AxesPositionDecorator(
            *self.full_image_axis_position)
        chart.add_decorator(position_decorator)

        line_decorator = HorizontalLineDecorator(0, key="h_line", linewidth=1)
        chart.add_decorator(line_decorator)
        legend = LegendDecorator()

        series_elem = DataElementDecorator(diff)
        chart.add_decorator(series_elem)
        legend.add_entry(series_elem, legend_subtitle)

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

        chart.add_decorator(
            AxesFormatterDecorator(y_major=PercentageFormatter(".0f")))

        fill_decorator = FillBetweenDecorator(diff)
        chart.add_decorator(fill_decorator)
        self.document.add_element(
            ChartElement(chart, figsize=self.full_image_size, dpi=self.dpi))
Пример #18
0
def create_bar_chart(series_list: List[QFSeries],
                     names_list,
                     title: str,
                     lines: List[QFSeries],
                     recession_series: QFSeries = None,
                     start_x: datetime = None,
                     end_x: datetime = None,
                     quarterly: bool = False,
                     date_label_format: Tuple[str, str] = ("%Y", "%y Q{}"),
                     recession_name: str = None) -> BarChart:
    """
    Creates a new bar chart based on the settings specified.

    This function makes some assumptions about the type of bar chart to create, but it should cover >90% of cases.

    Parameters
    ----------
    series_list
    names_list
    title
    lines
        One or more series representing the lines to draw on the bar chart.
    recession_series
        A series that will be used to highlight recession periods using gray boxes.
    start_x
        The first date to plot from the specified series.
    end_x
        The last date to plot from the specified series.
    quarterly
        Whether the bar chart should be formatted for quarterly frequency series.
    date_label_format
        The format for the date labels in the x-axis. It can contain a format parameter which will be replaced with
        the quarter. The first format is for labels that are not shown every quarter, whereas the second format is
        used for labels that are shown on every quarter.
    recession_name
        Example "US Recession"

    Returns
    -------
    BarChart
    """
    assert len(names_list) > len(lines) + 1, \
        "Not all labels have been specified. Specify one in the list for each series and line."

    bar_chart = BarChart(orientation=Orientation.Vertical,
                         start_x=start_x,
                         end_x=end_x,
                         thickness=60 if quarterly else 20,
                         align="center")
    bar_chart.tick_fontweight = "bold"
    bar_chart.tick_color = "black"

    series_start = series_list[0].index.min()
    series_end = series_list[0].index.max()
    data_elements = []
    for series in series_list:
        # Find the smallest series start and largest series end among all series.
        if series.index.min() < series_start:
            series_start = series.index.min()
        if series.index.max() > series_end:
            series_end = series.index.max()
        # Add the series to the bar chart.
        data_element = DataElementDecorator(series)
        data_elements.append(data_element)
        bar_chart.add_decorator(data_element)

    # Get the list of colors from the current stylesheet.
    style_colors = Chart.get_axes_colors()
    line_decorators = []
    for i in range(0, len(lines)):
        # Grab colors from the end so that they do not clash with the bars.
        color = style_colors[(len(style_colors) - i % len(style_colors)) - 1]
        # Add a series line decorator for each line.
        line_decorator = SeriesLineDecorator(lines[i][start_x:end_x],
                                             key="series_line_" + str(i),
                                             linewidth=4,
                                             color=color)
        line_decorators.append(line_decorator)

        bar_chart.add_decorator(line_decorator)

    # Create a title.
    if title is not None:
        title_decorator = TitleDecorator(title, key="title")
        bar_chart.add_decorator(title_decorator)

    # Create a legend.
    legend_decorator = _create_legend(bar_chart, data_elements,
                                      line_decorators, names_list, quarterly)

    # Create spans (rectangles) to highlight the recession periods.
    if recession_series is not None:
        span_decorator = SpanDecorator.from_int_list(recession_series,
                                                     key="span")
        bar_chart.add_decorator(span_decorator)
        if recession_name is not None:
            legend_decorator.add_entry(span_decorator, recession_name)

    if quarterly:
        # Format the ticks.
        # Determine (roughly) how many years passed between ``start`` and ``end``.
        display_start = series_start if start_x is None else start_x
        display_end = series_end if end_x is None else end_x
        years = (display_end - display_start).days // 365
        # Determine how often to show the ticks.
        # N.B. The show_every value depends on the locator defined below.
        if years < 2:
            show_every = 1  # Every quarter.
            date_format = date_label_format[1]
        elif years > 10:
            show_every = 5  # Every 5 years.
            date_format = date_label_format[0]
        else:
            show_every = 4  # Every year (4 quarters).
            date_format = date_label_format[0]
        func = lambda x, pos: _quarterly_formatter(x, pos, show_every,
                                                   date_format)
        axes_formatter = AxesFormatterDecorator(x_major=FuncFormatter(func),
                                                key="formatter")
        bar_chart.add_decorator(axes_formatter)

        # Set the tick locator.
        if years > 10:
            x_major = YearLocator()
        else:
            x_major = MonthLocator(range(1, 13), bymonthday=30, interval=3)
        axes_locator = AxesLocatorDecorator(x_major=x_major, key="locator")
        bar_chart.add_decorator(axes_locator)

    return bar_chart
Пример #19
0
    def historical_out_of_sample_performance_chart(self) -> LineChart:
        analysed_tms = self.model.input_data.analysed_tms
        frequency = self.model.input_data.frequency
        fund_cumulative_rets = analysed_tms.to_prices(
            initial_price=1.0, frequency=frequency) - 1  # type: PricesSeries
        fit_cumulative_rets = self.model.fitted_tms.to_prices(
            initial_price=1.0, frequency=frequency) - 1  # type: PricesSeries

        live_start_date = self.model.oos_start_date

        in_sample_fund_tms = fund_cumulative_rets.loc[:live_start_date]
        in_sample_fit_tms = fit_cumulative_rets.loc[:live_start_date]

        out_of_sample_fund_tms = fund_cumulative_rets.loc[live_start_date:]
        out_of_sample_fit_tms = fit_cumulative_rets.loc[live_start_date:]

        colors = Chart.get_axes_colors()

        in_sample_fund_data_elem = DataElementDecorator(in_sample_fund_tms,
                                                        color=colors[0])
        out_of_sample_fund_data_elem = DataElementDecorator(
            out_of_sample_fund_tms, color=colors[0])

        in_sample_fit_data_elem = DataElementDecorator(in_sample_fit_tms,
                                                       color=colors[1])
        out_of_sample_fit_data_elem = DataElementDecorator(
            out_of_sample_fit_tms, color=colors[1])

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

        is_vs_oos_performance_chart = LineChart()
        is_vs_oos_performance_chart.add_decorator(in_sample_fund_data_elem)
        is_vs_oos_performance_chart.add_decorator(out_of_sample_fund_data_elem)
        is_vs_oos_performance_chart.add_decorator(in_sample_fit_data_elem)
        is_vs_oos_performance_chart.add_decorator(out_of_sample_fit_data_elem)

        is_vs_oos_performance_chart.add_decorator(
            AxesFormatterDecorator(y_major=PercentageFormatter()))
        is_vs_oos_performance_chart.add_decorator(
            AxesLabelDecorator(y_label="Cumulative return [%]"))
        is_vs_oos_performance_chart.add_decorator(legend_decorator)

        is_vs_oos_performance_chart.add_decorator(
            TextDecorator("In Sample  ",
                          x=DataCoordinate(live_start_date),
                          y=AxesCoordinate(0.99),
                          verticalalignment='top',
                          horizontalalignment='right'))

        is_vs_oos_performance_chart.add_decorator(
            TextDecorator("  Out Of Sample",
                          x=DataCoordinate(live_start_date),
                          y=AxesCoordinate(0.99),
                          verticalalignment='top',
                          horizontalalignment='left'))
        last_date = fund_cumulative_rets.index[-1]
        is_vs_oos_performance_chart.add_decorator(
            VerticalSpanDecorator(x_min=live_start_date, x_max=last_date))

        return is_vs_oos_performance_chart