Esempio n. 1
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
Esempio n. 2
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
Esempio n. 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
Esempio n. 4
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))
Esempio n. 5
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
Esempio n. 6
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
Esempio n. 7
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))
Esempio n. 8
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))
Esempio n. 9
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
Esempio n. 10
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
Esempio n. 11
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
Esempio n. 12
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))
Esempio n. 13
0
def create_line_chart(data_list: List[Union[QFSeries, DataElementDecorator]],
                      names_list,
                      title: str = None,
                      recession_series: QFSeries = None,
                      horizontal_lines_list: List[float] = None,
                      vertical_lines_list: List[float] = None,
                      disable_dot: bool = False,
                      start_x: datetime = None,
                      end_x: datetime = None,
                      upper_y: float = None,
                      lower_y: float = None,
                      dot_decimal_points: int = 2,
                      recession_name: str = None) -> LineChart:
    """
    Creates a new line chart based on the settings specified.

    This function makes certain assumptions about the line chart, it can be customised via the parameters which should
    cover >90% of use cases. For more customisation use the ``LineChart`` class directly.

    Parameters
    ----------
    data_list
        A list of ``QFSeries`` or ``DataElementDecorator``s to plot on the chart.
    names_list
        A list of strings specifying the labels for the series, horizontal and vertical lines respectively. ``None``
        can be specified for labels to not display it for a specific series, or line.
    title
        The title of the graph, specify ``None`` if you don't want the chart to show a title.
    recession_series
        A ``QFSeries`` specifying where recessions occurred on the chart, will be highlighted using grey rectangles
        on the graph.
    horizontal_lines_list
        An optional list of values where a horizontal line should be drawn.
    vertical_lines_list
        An optional list of values where a vertical line should be drawn.
    disable_dot
        Whether a marker on the last point should be disabled.
    start_x
        The date where plotting should begin.
    end_x
        The date where plotting should end.
    upper_y
        The upper bound y-axis value at which plotting should begin.
    lower_y
        The lower bound y-axis value at which plotting should begin.
    dot_decimal_points
        How many decimal places to show after the decimal points when drawing text for "dot".
    recession_name
        A string specifying the recession label. If "None" or missing, will not be included.

    Returns
    -------
    The constructed ``LineChart``.
    """

    # If `end_x` was not specified, use a heuristic to determine it.
    if end_x is None and start_x is not None:
        end_x = LineChart.determine_end_x(start_x, data_list)

    # Create a new Line Chart.
    line_chart = LineChart(start_x=start_x,
                           end_x=end_x,
                           upper_y=upper_y,
                           lower_y=lower_y)
    line_chart.tick_fontweight = "bold"
    line_chart.tick_color = "black"

    names_index = 0  # Current legend label.
    legend_decorator = LegendDecorator(key='legend')

    # Retrieve necessary data.
    for data in data_list:
        assert isinstance(data, (pandas.Series, DataElementDecorator))
        # Add the current series with a label taken from ``names_list``.
        data_element = data
        if isinstance(data_element, pandas.Series):
            data_element = DataElementDecorator(data)
        line_id = data_element.key
        line_chart.add_decorator(data_element)

        # Retrieve the last data point.
        point_to_emphasise = \
            (_get_last_valid_value(data_element.data.index), _get_last_valid_value(data_element.data.values))

        series_label = _get_name(names_list, names_index)
        if series_label is not None:
            legend_decorator.add_entry(
                data_element, series_label +
                " [{}]".format(point_to_emphasise[0].strftime("%b %y")))

        names_index += 1
        if not disable_dot:
            # Emphasise the last data point.
            point_emphasis = PointEmphasisDecorator(
                data_element,
                point_to_emphasise,
                decimal_points=dot_decimal_points,
                key="point_emphasis_{}".format(line_id),
                use_secondary_axes=data_element.use_secondary_axes)
            line_chart.add_decorator(point_emphasis)

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

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

    # Create horizontal lines.
    if horizontal_lines_list is not None:
        for hline in horizontal_lines_list:
            line_decorator = HorizontalLineDecorator(hline,
                                                     key="hline" + str(hline))
            line_chart.add_decorator(line_decorator)
            series_label = _get_name(names_list, names_index)
            if series_label is not None:
                legend_decorator.add_entry(line_decorator, series_label)

            names_index += 1

    # Create vertical lines.
    if vertical_lines_list is not None:
        for vline in vertical_lines_list:
            line_decorator = VerticalLineDecorator(vline,
                                                   key="vline" + str(vline))
            line_chart.add_decorator(line_decorator)
            series_label = _get_name(names_list, names_index)
            if series_label is not None:
                legend_decorator.add_entry(line_decorator, series_label)
            names_index += 1

    # Add a legend.
    line_chart.add_decorator(legend_decorator)

    return line_chart