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 __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
def _add_line_chart_element(self, series, title): chart = self._get_line_chart(series, title) position_decorator = AxesPositionDecorator(*self.full_image_axis_position) chart.add_decorator(position_decorator) self.document.add_element(ChartElement(chart, figsize=self.full_image_size, dpi=self.dpi))
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
def _add_gini_coefficient_chart(self): chart = LineChart(rotate_x_axis=False) position_decorator = AxesPositionDecorator(*self.full_image_axis_position) chart.add_decorator(position_decorator) # Get the assets history assets_history = self.backtest_result.portfolio.positions_history() assets_history = assets_history.applymap( lambda x: x.total_exposure if isinstance(x, BacktestPositionSummary) else 0) def gini(group): # Function computing the Gini coefficients for each row group = group.abs() ranks = group.rank(ascending=True) mean_value = group.mean() samples = group.size group = group * (2 * ranks - samples - 1) return group.sum() / (samples * samples * mean_value) assets_history = assets_history.stack(dropna=False).groupby(level=0).apply(gini).to_frame(name="Gini " "coefficient") assets_history_decorator = DataElementDecorator(assets_history) chart.add_decorator(assets_history_decorator) # Add title title_decorator = TitleDecorator("Concentration of assets - Gini coefficient") chart.add_decorator(title_decorator) self.document.add_element(ChartElement(chart, figsize=self.full_image_size, dpi=self.dpi))
def _add_assets_number_in_portfolio_chart(self): chart = LineChart(rotate_x_axis=False) chart.add_decorator(AxesPositionDecorator(*self.full_image_axis_position)) legend = LegendDecorator(key="legend_decorator") positions_history = self.backtest_result.portfolio.positions_history() # Find all not NaN values (not NaN values indicate that the position was open for this contract at that time) # and count their number for each row (for each of the dates) number_of_contracts = positions_history.notna().sum(axis=1) number_of_contracts_decorator = DataElementDecorator(number_of_contracts) chart.add_decorator(number_of_contracts_decorator) legend.add_entry(number_of_contracts_decorator, "Contracts") # Group tickers by name and for each name and date check if there was at least one position open with any # of the corresponding tickers. Finally sum all the assets that had a position open on a certain date. number_of_assets = positions_history.groupby(by=lambda ticker: ticker.name, axis='columns') \ .apply(lambda x: x.notna().any(axis=1)).sum(axis=1) number_of_assets_decorator = DataElementDecorator(number_of_assets) chart.add_decorator(number_of_assets_decorator) legend.add_entry(number_of_assets_decorator, "Assets") chart.add_decorator(TitleDecorator("Number of assets in the portfolio")) chart.add_decorator(legend) chart.add_decorator(AxesLabelDecorator(y_label="Number of contracts / assets")) self.document.add_element(ChartElement(chart, figsize=self.full_image_size, dpi=self.dpi))
def _add_leverage_chart(self): lev_chart = self._get_leverage_chart(self.leverage) position_decorator = AxesPositionDecorator( *self.full_image_axis_position) lev_chart.add_decorator(position_decorator) self.document.add_element( ChartElement(lev_chart, figsize=self.full_image_size, dpi=self.dpi))
def _add_concentration_of_portfolio_chart(self, top_assets_numbers: tuple = (1, 5)): chart = LineChart(rotate_x_axis=False) position_decorator = AxesPositionDecorator(*self.full_image_axis_position) chart.add_decorator(position_decorator) # Define a legend legend = LegendDecorator(key="legend_decorator") # Add y label label_decorator = AxesLabelDecorator(y_label="Mean total exposure of top assets") chart.add_decorator(label_decorator) # Add top asset contribution positions_history = self.backtest_result.portfolio.positions_history() if positions_history.empty: raise ValueError("No positions found in positions history") positions_history = positions_history.applymap( lambda x: x.total_exposure if isinstance(x, BacktestPositionSummary) else 0) # Map all the single contracts onto tickers (including future tickers) and take the maximal total exposure for # each of the groups - in case if two contracts for a single asset will be included in the open positions in # the portfolio at any point of time, only one (with higher total exposure) will be considered while generating # the top assets plot def contract_to_ticker(c: Contract): return self.backtest_result.portfolio.contract_ticker_mapper. \ contract_to_ticker(c, strictly_to_specific_ticker=False) assets_history = positions_history.rename(columns=contract_to_ticker) assets_history = assets_history.groupby(level=0, axis=1).apply(func=( lambda x: x.abs().max(axis=1).astype(float) )) for assets_number in top_assets_numbers: # For each date (row), find the top_assets largest assets and compute the mean value of their market value top_assets_mean_values = assets_history.stack(dropna=False).groupby(level=0).apply( lambda group: group.nlargest(assets_number).mean() ).resample('D').last() # Divide the computed mean values by the portfolio value, for each of the dates top_assets_percentage_value = top_assets_mean_values / self.backtest_result.portfolio.portfolio_eod_series() concentration_top_asset = DataElementDecorator(top_assets_percentage_value) chart.add_decorator(concentration_top_asset) # Add to legend legend.add_entry(concentration_top_asset, "TOP {} assets".format(assets_number)) # Add title title_decorator = TitleDecorator("Concentration of assets") chart.add_decorator(title_decorator) # Add legend chart.add_decorator(legend) self.document.add_element(ChartElement(chart, figsize=self.full_image_size, dpi=self.dpi))
def _add_cone_chart(self): cone_chart = ConeChartOOS(self.strategy_series, is_mean_return=self.is_mean_return, is_sigma=self.is_sigma) position_decorator = AxesPositionDecorator(*self.full_image_axis_position) cone_chart.add_decorator(position_decorator) chart_element = ChartElement(cone_chart, self.full_image_size, self.dpi, False) self.document.add_element(chart_element)
def _add_leverage_chart(self): lev_chart = self._get_leverage_chart(self.backtest_result.portfolio.leverage_series()) position_decorator = AxesPositionDecorator(*self.full_image_axis_position) lev_chart.add_decorator(position_decorator) # Add y label label_decorator = AxesLabelDecorator(y_label="Leverage") lev_chart.add_decorator(label_decorator) self.document.add_element(ChartElement(lev_chart, figsize=self.full_image_size, dpi=self.dpi))
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 _add_assets_number_in_portfolio_chart(self): chart = LineChart(rotate_x_axis=False) legend = LegendDecorator(key="legend_decorator") position_decorator = AxesPositionDecorator( *self.full_image_axis_position) chart.add_decorator(position_decorator) positions_history = self.backtest_result.portfolio.positions_history() # Find all not NaN values (not NaN values indicate that the position was open for this contract at that time) # and count their number for each row (for each of the dates) number_of_contracts = positions_history.notnull().sum(axis=1) number_of_contracts_decorator = DataElementDecorator( number_of_contracts) chart.add_decorator(number_of_contracts_decorator) legend.add_entry(number_of_contracts_decorator, "Contracts") # Count number of assets in the portfolio (if on two contracts from same future family exist in the same time, # e.g. during rolling day, in the portfolio, they are counted as one asset) def contract_to_ticker(c: Contract): return self.backtest_result.portfolio.contract_ticker_mapper. \ contract_to_ticker(c, strictly_to_specific_ticker=False) assets_history = positions_history.rename(columns=contract_to_ticker) assets_history = assets_history.groupby(level=0, axis=1).apply(func=( # For each asset, group all of the corresponding columns (each of which corresponds to one contract), # and check if at any given timestamp the "value" of any of the contracts was different than None - this # indicates that at this point of time a position concerning the given asset was open in the portfolio # (which in the resulting series will be denoted as 1, otherwise - 0, so that it will be possible to # sum positions of all open assets at any given point of time) lambda x: x.notna().any(axis=1).astype(int))) number_of_assets = assets_history.sum(axis=1) number_of_assets_decorator = DataElementDecorator(number_of_assets) chart.add_decorator(number_of_assets_decorator) legend.add_entry(number_of_assets_decorator, "Assets") # Add title title_decorator = TitleDecorator("Number of assets in the portfolio") chart.add_decorator(title_decorator) # Add legend chart.add_decorator(legend) # Add y label label_decorator = AxesLabelDecorator( y_label="Number of contracts / assets") chart.add_decorator(label_decorator) self.document.add_element( ChartElement(chart, figsize=self.full_image_size, dpi=self.dpi))
def _create_single_heat_map(self, title, result_df, min_v, max_v): chart = HeatMapChart(data=result_df, color_map=plt.get_cmap("coolwarm"), min_value=min_v, max_value=max_v) chart.add_decorator( AxisTickLabelsDecorator(labels=list(result_df.columns), axis=Axis.X)) chart.add_decorator( AxisTickLabelsDecorator(labels=list(reversed(result_df.index)), axis=Axis.Y)) chart.add_decorator(ValuesAnnotations()) param_names = self._get_param_names() chart.add_decorator( AxesLabelDecorator(x_label=param_names[1], y_label=param_names[0])) chart.add_decorator(TitleDecorator(title)) position_decorator = AxesPositionDecorator(*self.image_axis_position) chart.add_decorator(position_decorator) return 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 _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 _get_simulation_plot(self, scenarios_df: PricesDataFrame) -> Chart: chart = LineChart(log_scale=True) for _, scenario in scenarios_df.items(): data_element = DataElementDecorator(scenario, linewidth=0.5) chart.add_decorator(data_element) # Add a legend legend = LegendDecorator(key="legend_decorator") # Add Ensemble average ensemble_avg = scenarios_df.mean(axis=1) ensemble_avg_data_element = DataElementDecorator(ensemble_avg, color="#e1e5f4", linewidth=3) chart.add_decorator(ensemble_avg_data_element) legend.add_entry(ensemble_avg_data_element, "Ensemble average") # Add Expectation (vol adjusted) trade_returns = QFSeries(data=[trade.percentage_pnl for trade in self.trades]) std = trade_returns.std() expectation_adj_series = np.ones(len(ensemble_avg)) * (trade_returns.mean() - 0.5 * std * std) expectation_adj_series = SimpleReturnsSeries(data=expectation_adj_series, index=ensemble_avg.index) expectation_adj_series = expectation_adj_series.to_prices() data_element = DataElementDecorator(expectation_adj_series, color="#46474b", linewidth=2) chart.add_decorator(data_element) legend.add_entry(data_element, "Expectation (vol adjusted)") # Add title title_decorator = TitleDecorator("Monte Carlo Simulations (log scale)", key="title") chart.add_decorator(title_decorator) position_decorator = AxesPositionDecorator(*self.full_image_axis_position) chart.add_decorator(position_decorator) chart.add_decorator(legend) 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_concentration_of_portfolio_chart(self, top_assets_numbers: tuple = (1, 5)): chart = LineChart(rotate_x_axis=False) chart.add_decorator(AxesPositionDecorator(*self.full_image_axis_position)) chart.add_decorator(AxesLabelDecorator(y_label="Mean total exposure of top assets")) chart.add_decorator(TitleDecorator("Concentration of assets")) legend = LegendDecorator(key="legend_decorator") chart.add_decorator(legend) # Add top asset contribution positions_history = self.backtest_result.portfolio.positions_history() if positions_history.empty: raise ValueError("No positions found in positions history") positions_history = positions_history.applymap( lambda x: x.total_exposure if isinstance(x, BacktestPositionSummary) else 0) # Group all the tickers by their names and take the maximal total exposure for each of the groups - in case # if two contracts for a single asset will be included in the open positions in the portfolio at any point of # time, only one (with higher total exposure) will be considered while generating the top assets plot assets_history = positions_history.groupby(by=lambda ticker: ticker.name, axis='columns').apply( lambda x: x.abs().max(axis=1)) for assets_number in top_assets_numbers: # For each date (row), find the top_assets largest assets and compute the mean value of their market value top_assets_mean_values = assets_history.stack(dropna=False).groupby(level=0).apply( lambda group: group.nlargest(assets_number).mean() ).resample('D').last() # Divide the computed mean values by the portfolio value, for each of the dates top_assets_percentage_value = top_assets_mean_values / self.backtest_result.portfolio.portfolio_eod_series() concentration_top_asset = DataElementDecorator(top_assets_percentage_value) chart.add_decorator(concentration_top_asset) legend.add_entry(concentration_top_asset, "TOP {} assets".format(assets_number)) self.document.add_element(ChartElement(chart, figsize=self.full_image_size, dpi=self.dpi))
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 _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)
def _add_line_plots(self, tickers: Sequence[Ticker]): parameters_list = sorted( self.backtest_evaluator.params_backtest_summary_elem_dict.keys()) title_to_plot = defaultdict(lambda: LineChart()) title_to_legend = defaultdict( lambda: LegendDecorator(key="legend_decorator")) for start_time, end_time in [ (self.backtest_summary.start_date, self.out_of_sample_start_date), (self.out_of_sample_start_date, self.backtest_summary.end_date) ]: results = [] for param_tuple in parameters_list: trades_eval_result = self.backtest_evaluator.evaluate_params_for_tickers( param_tuple, tickers, start_time, end_time) results.append(trades_eval_result) sqn_avg_nr_trades = DataElementDecorator( [x.sqn_per_avg_nr_trades for x in results]) avg_nr_of_trades = DataElementDecorator( [x.avg_nr_of_trades_1Y for x in results]) annualised_return = DataElementDecorator( [x.annualised_return for x in results]) adjusted_start_time = min([x.start_date for x in results]) adjusted_end_time = max([x.end_date for x in results]) if adjusted_start_time >= adjusted_end_time: adjusted_end_time = adjusted_start_time if adjusted_start_time <= self.backtest_summary.end_date \ else end_time adjusted_start_time = start_time title = "{} - {} ".format(adjusted_start_time.strftime("%Y-%m-%d"), adjusted_end_time.strftime("%Y-%m-%d")) title_to_plot["SQN (Arithmetic return) per year"].add_decorator( sqn_avg_nr_trades) title_to_legend["SQN (Arithmetic return) per year"].add_entry( sqn_avg_nr_trades, title) title_to_plot["Avg # trades 1Y"].add_decorator(avg_nr_of_trades) title_to_legend["Avg # trades 1Y"].add_entry( sqn_avg_nr_trades, title) if len(tickers) == 1: title_to_plot["Annualised return"].add_decorator( annualised_return) title_to_legend["Annualised return"].add_entry( annualised_return, title) tickers_used = "Many tickers" if len(tickers) > 1 else ( tickers[0].name) for description, line_chart in title_to_plot.items(): self.document.add_element( HeadingElement(3, "{} - {}".format(description, tickers_used))) line_chart.add_decorator( AxesLabelDecorator(x_label=self._get_param_names()[0], y_label=title)) position_decorator = AxesPositionDecorator( *self.image_axis_position) line_chart.add_decorator(position_decorator) legend = title_to_legend[description] line_chart.add_decorator(legend) self.document.add_element( ChartElement(line_chart, figsize=self.full_image_size))
def _resize_chart(self, chart): left, bottom, width, height = self.image_axis_position position_decorator = AxesPositionDecorator(left, bottom, width, height) chart.add_decorator(position_decorator)