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
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
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
def _get_histogram_chart(self): colors = Chart.get_axes_colors() chart = HistogramChart(self.returns_of_trades * 100) # expressed in % # Format the x-axis so that its labels are shown as a percentage. x_axis_formatter = FormatStrFormatter("%0.0f%%") axes_formatter_decorator = AxesFormatterDecorator(x_major=x_axis_formatter, key="axes_formatter") chart.add_decorator(axes_formatter_decorator) # Only show whole numbers on the y-axis. y_axis_locator = MaxNLocator(integer=True) axes_locator_decorator = AxesLocatorDecorator(y_major=y_axis_locator, key="axes_locator") chart.add_decorator(axes_locator_decorator) # Add an average line. avg_line = VerticalLineDecorator(self.returns_of_trades.values.mean(), color=colors[1], key="average_line_decorator", linestyle="--", alpha=0.8) chart.add_decorator(avg_line) # Add a legend. legend = LegendDecorator(key="legend_decorator") legend.add_entry(avg_line, "Mean") chart.add_decorator(legend) # Add a title. title = TitleDecorator("Distribution of Trades", key="title_decorator") chart.add_decorator(title) chart.add_decorator(AxesLabelDecorator("Return", "Occurrences")) return chart
def create_returns_distribution(returns: QFSeries, frequency: Frequency = Frequency.MONTHLY, title: str = None) -> \ HistogramChart: """ Creates a new returns distribution histogram with the specified frequency. Parameters ---------- returns: QFSeries The returns series to use in the histogram. frequency: Frequency frequency of the returns after aggregation title title of the chart Returns ------- HistogramChart A new ``HistogramChart`` instance. """ colors = Chart.get_axes_colors() aggregate_returns = get_aggregate_returns(returns, frequency, multi_index=True).multiply(100) chart = HistogramChart(aggregate_returns) # Format the x-axis so that its labels are shown as a percentage. x_axis_formatter = FormatStrFormatter("%.0f%%") axes_formatter_decorator = AxesFormatterDecorator(x_major=x_axis_formatter, key="axes_formatter") chart.add_decorator(axes_formatter_decorator) # Only show whole numbers on the y-axis. y_axis_locator = MaxNLocator(integer=True) axes_locator_decorator = AxesLocatorDecorator(y_major=y_axis_locator, key="axes_locator") chart.add_decorator(axes_locator_decorator) # Add an average line. avg_line = VerticalLineDecorator(aggregate_returns.values.mean(), color=colors[1], key="average_line_decorator", linestyle="--", alpha=0.8) chart.add_decorator(avg_line) # Add a legend. legend = LegendDecorator(key="legend_decorator") legend.add_entry(avg_line, "Mean") chart.add_decorator(legend) # Add a title. if title is None: title = "Distribution of " + str(frequency).capitalize() + " Returns" title = TitleDecorator(title, key="title_decorator") chart.add_decorator(title) chart.add_decorator(AxesLabelDecorator("Returns", "Occurrences")) return chart
def _add_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))
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
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))
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
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
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
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))
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)
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
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
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
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))
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
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