示例#1
0
    def __init__(self, orientation: Orientation, stacked: bool = True, index_translator: IndexTranslator = None,
                 thickness: float = 0.8, start_x: Any = None, end_x: Any = None,
                 upper_y: float = None, lower_y: float = None, **plot_settings):
        Chart.__init__(self, start_x, end_x, upper_y, lower_y)

        self.index_translator = index_translator
        self._orientation = orientation
        self._stacked = stacked
        self._thickness = thickness
        self._plot_settings = plot_settings
示例#2
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
示例#3
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
示例#4
0
    def __init__(self,
                 prices: QFSeries,
                 count: int,
                 colors: List[str] = None,
                 key: str = None):
        """
        Construct a new TopDrawdownDecorator.

        The top ``count`` amount of drawdowns will be highlighted. If ``colors`` is ``None`` then a default list of
        colours will be used, you can override it by specifying a list of strings containing color names or hex codes.

        Parameters
        ----------
        prices
            A series from which drawdowns will be calculated.
        count
            The amount of longest drawdowns to highlight.
        colors
            A list of colours to use to highlight the drawdowns.
        """
        super().__init__(key)
        if colors is None:
            self._color = Chart.get_axes_colors()[3]
        else:
            self._color = cycle(colors)
        self._current_color = 0

        self._series = prices
        self._count = count
示例#5
0
    def __init__(
            self, x_data: Sequence, y_data: Sequence, size: int=40, color=None, key: str = None, **plot_settings: Any):
        """
        Creates a scatter plot based on the data specified.

        Parameters
        ----------
        x_data
            values of x coordinate
        y_data
            values of y coordinate
        size
            size in points^2; scalar or an array of the same length as x_data and y_data
        color
            *c* can be a single color format string, or a sequence of color specifications of length x_data and y_data,
            or a sequence of x_data and y_data numbers to be mapped to colors using the *cmap* and *norm* specified via
            kwargs (see below). Note that color should not be a single numeric RGB or RGBA sequence because that is
            indistinguishable from an array of values to be colormapped.  color can be a 2-D array in which the rows are
            RGB or RGBA, however, including the case of a single row to specify the same color for all points.
        plot_settings
            other settings like for example: alpha, linewidths, verts, edgecolors
        
        """
        ChartDecorator.__init__(self, key)
        SimpleLegendItem.__init__(self)
        self.x_data = x_data
        self.y_data = y_data
        self.size = size
        if color is None:
            self.color = Chart.get_axes_colors()[0]
        else:
            self.color = color
        self.plot_settings = plot_settings
示例#6
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
示例#7
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
示例#8
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
示例#9
0
    def apply_data_element_decorators(
            self, data_element_decorators: List[DataElementDecorator]) -> Any:
        default_colors = Chart.get_axes_colors()
        default_color_iter = cycle(default_colors)

        # Holds the positions of the bars that have been plotted most recently. It is used to stack
        # bars on top of each other and tracks where to place the bars so that they are on top of each other.
        last_data_element_positions = (None, None)  # (Positive, Negative)

        for data_element in data_element_decorators:
            # copy the general plot settings and add DataElementDecorator-specific plot settings to the copy
            # (overwrite general plot settings if necessary)
            plot_settings = dict(self._plot_settings)
            plot_settings.update(data_element.plot_settings)

            # set color for the bars if it's not specified
            if "color" not in plot_settings:
                plot_settings["color"] = next(default_color_iter)

            data = self._trim_data(data_element.data)

            # Pick the axes to plot on.
            axes = self.axes
            if data_element.use_secondary_axes:
                self.setup_secondary_axes_if_necessary()
                axes = self.secondary_axes

            bars = self._plot_data(axes, data, last_data_element_positions,
                                   plot_settings)
            data_element.legend_artist = bars

            last_data_element_positions = self._calculate_last_data_positions(
                data, last_data_element_positions)
示例#10
0
    def plot(self, figsize: Tuple[float, float] = None):
        self._setup_axes_if_necessary(figsize)

        cone = AnalyticalCone(self.data)
        cone_data_frame = cone.calculate_aggregated_cone(self.nr_of_data_points, self.is_end_date, 0)

        strategy_tms = cone_data_frame['Strategy']
        mean_tms = cone_data_frame['Expectation']

        ax = self.axes
        ax.plot(strategy_tms)
        ax.plot(mean_tms)

        cone_colors = cycle(Chart.get_axes_colors()[2:4])

        # fill areas for every standard deviation
        for cone_std in self.cone_stds:
            upper_df = cone.calculate_aggregated_cone(self.nr_of_data_points, self.is_end_date, cone_std)
            lower_df = cone.calculate_aggregated_cone(self.nr_of_data_points, self.is_end_date, -cone_std)

            upper_bound = upper_df['Expectation']
            lower_bound = lower_df['Expectation']
            ax.fill_between(
                cone_data_frame.index, lower_bound, upper_bound, color=next(cone_colors), alpha=self.cone_opacity)

        ax.set_xlabel('Days in the past')
        ax.set_ylabel('Current valuation')
        ax.set_title('Performance vs. Expectation')
        ax.set_xlim(0, self.nr_of_data_points)
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
示例#12
0
    def __init__(self,
                 orientation: Orientation,
                 stacked: bool = True,
                 index_translator: IndexTranslator = None,
                 thickness: float = 0.8,
                 start_x: datetime.datetime = None,
                 end_x: datetime.datetime = None,
                 upper_y: float = None,
                 lower_y: float = None,
                 **plot_settings):
        """
        Creates a new bar chart with the specified ``orientation``.

        Parameters
        ----------
        orientation
            The orientation of the bar chart, either Horizontal or Vertical.
        stacked
            default: True; if True then bars corresponding to different DataElementDecorators will be stacked.
            Otherwise bars will be plotted next to each other.
        index_translator:
            the mapper of index coordinates (e.g. you may use labels as index in a pandas series and this translator
            will ensure that it is plotted correctly)
        thickness
            how thick should each bar be (expressed in numeric data coordinates system)
        start_x
            The date where the x-axis should begin.
        end_x
            The date where the x-axis should end.
        upper_y
            The upper bound of the y-axis.
        lower_y
            The lower bound of the y-axis.
        plot_settings
            Keyword arguments to pass to the ``plot`` function.
        """
        Chart.__init__(self, start_x, end_x, upper_y, lower_y)

        self.index_translator = index_translator
        self._orientation = orientation
        self._stacked = stacked
        self._thickness = thickness
        self._plot_settings = plot_settings
示例#13
0
    def plot(self, figsize: Tuple[float, float] = None):
        self._setup_axes_if_necessary(figsize)

        plot_kwargs = self.plot_settings

        # Plot the boxes.
        colors = Chart.get_axes_colors()
        sns.boxplot(ax=self.axes, data=self._data, palette=colors, **plot_kwargs)

        self._apply_decorators()
        self._adjust_style()
示例#14
0
    def decorate(self, chart: "Chart") -> None:
        prices_tms = self.series
        cone = AnalyticalCone(prices_tms)
        ax = chart.axes

        colors = Chart.get_axes_colors()
        mean_tms = cone.calculate_simple_cone(self._live_start_date, 0)
        ax.plot(mean_tms, color=colors[1])

        for cone_std in self._cone_stds:
            upper_bound_tms = cone.calculate_simple_cone(self._live_start_date, cone_std)
            lower_bound_tms = cone.calculate_simple_cone(self._live_start_date, -cone_std)
            ax.fill_between(upper_bound_tms.index, upper_bound_tms, lower_bound_tms, alpha=self._colors_alpha)
示例#15
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
示例#16
0
    def _plot_tail_data(self, regression_line, beta, alpha, r_squared, max_ret):
        colors = Chart.get_axes_colors()

        self.axes.plot(regression_line.index.values, regression_line.values, axes=self.axes, color=colors[2])

        self.axes.set_xlim([-max_ret, max_ret])
        self.axes.set_ylim([-max_ret, max_ret])

        props = dict(boxstyle='square', facecolor=colors[2], alpha=0.5)
        textstr = 'tail $\\beta={0:.2f}$\ntail $\\alpha={1:.2%}$$\%$\ntail $R^2={2:.2}$'.format(beta, alpha, r_squared)
        font_size = mpl.rcParams['legend.fontsize']

        self.axes.text(
            0.80, 0.35, textstr, transform=self.axes.transAxes, bbox=props, verticalalignment='top', fontsize=font_size)
示例#17
0
    def __init__(self,
                 prices: QFSeries,
                 count: int,
                 colors: List[str] = None,
                 key: str = None):
        super().__init__(key)
        if colors is None:
            self._color = Chart.get_axes_colors()[3]
        else:
            self._color = cycle(colors)
        self._current_color = 0

        self._series = prices
        self._count = count
示例#18
0
    def apply_data_element_decorators(
            self, data_element_decorators: List["DataElementDecorator"]):
        colors = cycle(Chart.get_axes_colors())

        for data_element in data_element_decorators:
            plot_settings = data_element.plot_settings.copy()
            plot_settings.setdefault("color", next(colors))

            series = data_element.data
            trimmed_series = self._trim_data(series)
            drawdown_series = drawdown_tms(trimmed_series)
            drawdown_series *= -1

            axes = self._ax
            axes.yaxis.set_major_formatter(PercentageFormatter())
            axes.fill_between(drawdown_series.index, 0, drawdown_series.values)
            axes.set_ylim(top=0)
示例#19
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
示例#20
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
示例#21
0
    def decorate(self, chart) -> None:
        cone = AnalyticalConeBase()
        ax = chart.axes

        colors = Chart.get_axes_colors()
        mean_tms = cone.calculate_simple_cone_for_process(
            self._mean, self._std, 0, self._steps, self._starting_value)
        ax.plot(mean_tms, color=colors[1])

        for cone_std in self._cone_stds:
            upper_bound_tms = cone.calculate_simple_cone_for_process(
                self._mean, self._std, cone_std, self._steps,
                self._starting_value)
            lower_bound_tms = cone.calculate_simple_cone_for_process(
                self._mean, self._std, -cone_std, self._steps,
                self._starting_value)
            ax.fill_between(upper_bound_tms.index,
                            upper_bound_tms,
                            lower_bound_tms,
                            alpha=self._colors_alpha)
示例#22
0
    def apply_data_element_decorators(
            self, data_element_decorators: List["DataElementDecorator"]):
        colors = cycle(Chart.get_axes_colors())

        for data_element in data_element_decorators:
            plot_settings = data_element.plot_settings.copy()
            plot_settings.setdefault("color", next(colors))

            series = data_element.data
            trimmed_series = self._trim_data(series)

            axes = self._ax
            if data_element.use_secondary_axes:
                mpl.rcParams[
                    'axes.spines.right'] = True  # Ensure that the right axes spine is shown.
                self.setup_secondary_axes_if_necessary()
                axes = self._secondary_axes

            handle = axes.plot(trimmed_series, **plot_settings)[0]
            data_element.legend_artist = handle
示例#23
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
示例#24
0
    def plot(self, figsize: Tuple[float, float] = None):
        self._setup_axes_if_necessary(figsize)

        cone = AnalyticalConeOOS()
        cone_data_frame = cone.calculate_aggregated_cone_oos_only(
            self.oos_series, self.is_mean_return, self.is_sigma, 0)

        strategy_tms = cone_data_frame['Strategy']
        mean_tms = cone_data_frame['Expectation']

        ax = self.axes
        ax.plot(strategy_tms)
        ax.plot(mean_tms)

        cone_colors = cycle(Chart.get_axes_colors()[2:4])

        # fill areas for every standard deviation
        for cone_std in self.cone_stds:
            upper_df = cone.calculate_aggregated_cone_oos_only(
                self.oos_series, self.is_mean_return, self.is_sigma, cone_std)
            lower_df = cone.calculate_aggregated_cone_oos_only(
                self.oos_series, self.is_mean_return, self.is_sigma, -cone_std)

            upper_bound = upper_df['Expectation']
            lower_bound = lower_df['Expectation']
            ax.fill_between(cone_data_frame.index,
                            lower_bound,
                            upper_bound,
                            color=next(cone_colors),
                            alpha=self.cone_opacity)

        ax.set_xlabel('Days in the past')
        ax.set_ylabel('Current valuation')
        ax.set_title('Performance vs. Expectation')
        ax.set_xlim(0, self.oos_series.size)

        self._insert_valuation_text_box(cone, strategy_tms)
        self._apply_decorators()
示例#25
0
    def _plot_data(self, datapoints_tms, regression_line, beta, alpha, r_squared, max_ret):
        colors = Chart.get_axes_colors()

        self.axes.scatter(x=datapoints_tms.iloc[:, 0], y=datapoints_tms.iloc[:, 1],
                          c=colors[0], alpha=0.6, edgecolors='black', linewidths=0.5)

        self.axes.axhline(0, color='black', axes=self.axes, linewidth=1)
        self.axes.axvline(0, color='black', axes=self.axes, linewidth=1)

        self.axes.plot(regression_line.index.values, regression_line.values, axes=self.axes, color=colors[1])

        self.axes.set_xlim([-max_ret, max_ret])
        self.axes.set_ylim([-max_ret, max_ret])

        props = dict(boxstyle='square', facecolor='white', alpha=0.5)
        textstr = '$\\beta={0:.2f}$\n$\\alpha={1:.2%}$$\%$\n$R^2={2:.2}$'.format(beta, alpha, r_squared)
        font_size = mpl.rcParams['legend.fontsize']

        self.axes.text(
            0.05, 0.95, textstr, transform=self.axes.transAxes, bbox=props, verticalalignment='top', fontsize=font_size)

        self.axes.xaxis.set_major_formatter(PercentageFormatter())
        self.axes.yaxis.set_major_formatter(PercentageFormatter())
示例#26
0
def main():
    # GENERATE DATA
    regressors_and_fund_df = QFDataFrame(data=[[1, 3, 5], [2, 3, 1], [3, 1, 2],
                                               [4, 2, 3], [5, 3, 4]],
                                         index=pd.bdate_range(
                                             start='2015-01-01', periods=5),
                                         columns=['a', 'b', 'c'])

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

    colors = cycle(Chart.get_axes_colors())
    chart = LineChart(start_x=str_to_date('2014-12-31'),
                      end_x=str_to_date('2015-01-08'))
    legend = LegendDecorator()

    for name, 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, name)

    chart.add_decorator(legend)
    chart.plot()

    plt.show(block=True)
def create_returns_similarity(strategy: QFSeries,
                              benchmark: QFSeries,
                              mean_normalization: bool = True,
                              std_normalization: bool = True,
                              frequency: Frequency = None) -> KDEChart:
    """
    Creates a new returns similarity chart. The frequency is determined by the specified returns series.

    Parameters
    ----------
    strategy: QFSeries
        The strategy series to plot.
    benchmark: QFSeries
        The benchmark series to plot.
    mean_normalization: bool
        Whether to perform mean normalization on the series data.
    std_normalization: bool
        Whether to perform variance normalization on the series data.
    frequency: Frequency
        Returns can be aggregated in to specific frequency before plotting the chart
    Returns
    -------
    KDEChart
        A newly created KDEChart instance.
    """
    chart = KDEChart()
    colors = Chart.get_axes_colors()

    if frequency is not None:
        aggregate_strategy = get_aggregate_returns(
            strategy.to_simple_returns(), frequency)
        aggregate_benchmark = get_aggregate_returns(
            benchmark.to_simple_returns(), frequency)
    else:
        aggregate_strategy = strategy.to_simple_returns()
        aggregate_benchmark = benchmark.to_simple_returns()

    scaled_strategy = preprocessing.scale(aggregate_strategy,
                                          with_mean=mean_normalization,
                                          with_std=std_normalization)
    strategy_data_element = DataElementDecorator(scaled_strategy,
                                                 bw="scott",
                                                 shade=True,
                                                 label=strategy.name,
                                                 color=colors[0])
    chart.add_decorator(strategy_data_element)

    scaled_benchmark = preprocessing.scale(aggregate_benchmark,
                                           with_mean=mean_normalization,
                                           with_std=std_normalization)
    benchmark_data_element = DataElementDecorator(scaled_benchmark,
                                                  bw="scott",
                                                  shade=True,
                                                  label=benchmark.name,
                                                  color=colors[1])
    chart.add_decorator(benchmark_data_element)

    # Add a title.
    title = _get_title(mean_normalization, std_normalization, frequency)
    title_decorator = TitleDecorator(title, key="title")
    chart.add_decorator(title_decorator)
    chart.add_decorator(AxesLabelDecorator("Returns", "Similarity"))
    return chart
示例#28
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
示例#29
0
 def _add_axes_position_decorator(self, chart: Chart):
     left, bottom, width, height = self.full_image_axis_position
     position_decorator = AxesPositionDecorator(left, bottom, width, height)
     chart.add_decorator(position_decorator)
示例#30
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