def build_document(self): series_list = [self.strategy_series, self.benchmark_series] self._add_header() self.document.add_element(ParagraphElement("\n")) self._add_perf_chart(series_list) self.document.add_element(ParagraphElement("\n")) self._add_returns_statistics_charts() self.document.add_element(ParagraphElement("\n")) self._add_ret_distribution_and_similarity() self.document.add_element(ParagraphElement("\n")) self._add_rolling_table() # Next Page self.document.add_element(NewPageElement()) self.document.add_element(ParagraphElement("\n")) self._add_cone_and_quantiles() self._add_underwater_and_skewness() self._add_statistics_table(series_list)
def build_document(self): series_list = [self.strategy_series, self.benchmark_series] # First Page self._add_header() self._add_perf_chart(series_list) self._add_relative_performance_chart(self.strategy_series, self.benchmark_series) self._add_statistics_table(series_list) # Second Page self.document.add_element(NewPageElement()) self._add_header() self.document.add_element(ParagraphElement("\n")) self._add_returns_statistics_charts() self._add_ret_distribution_and_similarity() self._add_rolling_table() # Third Page self.document.add_element(NewPageElement()) self._add_header() self._add_cone_and_quantiles() self._add_underwater_and_skewness() self._add_rolling_return_chart(series_list) self.document.add_element(ParagraphElement("\n")) self._add_rolling_vol_chart(series_list) self.document.add_element(ParagraphElement("\n")) self._add_rolling_alpha_and_beta(series_list)
def _add_pnl_and_performance_contribution_tables( self, ticker_to_pnl: Dict[Ticker, PricesSeries]): # For each ticker compute the PnL for each period (each year, month etc) pnl_df = QFDataFrame.from_dict(ticker_to_pnl) agg_performance = pnl_df.groupby(pd.Grouper(key=pnl_df.index.name, freq=self._frequency.to_pandas_freq())) \ .apply(lambda s: s.iloc[-1] - s.iloc[0]) # Format the column labels, so that they point exactly to the considered time frame column_labels_format = { Frequency.YEARLY: "%Y", Frequency.MONTHLY: "%b %Y", } columns_format = column_labels_format[self._frequency] performance_df = agg_performance.rename( index=lambda timestamp: timestamp.strftime(columns_format)) # Transpose the original data frame, so that performance for each period is presented in a separate column performance_df = performance_df.transpose() performance_df.index = performance_df.index.set_names("Asset") performance_df = performance_df.reset_index() performance_df["Asset"] = performance_df["Asset"].apply( lambda t: t.name) performance_tables = self._create_performance_tables( performance_df.copy()) performance_contribution_tables = self._create_performance_contribution_tables( performance_df.copy()) # Add the text and all figures into the document self.document.add_element( HeadingElement(level=2, text="Profit and Loss")) self.document.add_element( ParagraphElement( "The following tables provide the details on the Total profit and " "loss for each asset (notional in currency units).")) self.document.add_element(ParagraphElement("\n")) for table in performance_tables: self.document.add_element( HeadingElement(level=3, text="Performance between: {} - {}".format( table.model.data.columns[1], table.model.data.columns[-1]))) self.document.add_element(table) self.document.add_element(ParagraphElement("\n")) self.document.add_element(NewPageElement()) # Add performance contribution table self.document.add_element( HeadingElement(level=2, text="Performance contribution")) for table in performance_contribution_tables: self.document.add_element( HeadingElement( level=3, text="Performance contribution between {} - {}".format( table.model.data.columns[1], table.model.data.columns[-1]))) self.document.add_element(table)
def _add_summary(self): self.document.add_element(ParagraphElement("\n")) self.document.add_element(HeadingElement(2, "Summary")) self.document.add_element(ParagraphElement("\n")) self.document.add_element(ParagraphElement("1Y strength - Overall strength - Ticker\n")) pairs_sorted_by_value = sorted(self.ticker_to_trend_dict.items(), key=lambda pair: pair[1], reverse=True) for ticker, trend_strength_values in pairs_sorted_by_value: paragraph_str = "{:12.3f} - {:12.3f} - {}".format( trend_strength_values[0], trend_strength_values[1], ticker.as_string()) self.document.add_element(ParagraphElement(paragraph_str))
def create_document(self): self.document = Document(self.backtest_summary.backtest_name) self._add_header() add_backtest_description(self.document, self.backtest_summary) selected_tickers, rejected_tickers = self._evaluate_tickers() self.document.add_element(HeadingElement(2, "Selected Tickers")) self.document.add_element(ParagraphElement("\n")) self._add_table(selected_tickers) self.document.add_element(HeadingElement(2, "Rejected Tickers")) self.document.add_element(ParagraphElement("\n")) self._add_table(rejected_tickers)
def build_document(self): self._add_header() self.document.add_element(ParagraphElement("\n\n")) series_list = [self.strategy_series, self.benchmark_series] self._add_perf_chart(series_list) self.document.add_element(ParagraphElement("\n\n")) self._add_cone_chart() self.document.add_element(ParagraphElement("\n\n")) self._add_rolling_return_chart(series_list) self.document.add_element(ParagraphElement("\n\n")) self._add_rolling_vol_chart(series_list)
def build_document(self): self._add_header() self.document.add_element(ParagraphElement("\n")) ticker_to_pnl_series = self._compute_pnl() self._add_pnl_and_performance_contribution_tables(ticker_to_pnl_series) self._add_performance_statistics(ticker_to_pnl_series)
def build_document(self): self._add_header() self.document.add_element(ParagraphElement("\n")) self._add_histogram_and_cumulative() self._add_statistics_table()
def build_document(self): self._add_header() self.document.add_element(ParagraphElement("\n")) self.document.add_element( HeadingElement(level=2, text="Open Positions in the Portfolio")) self._add_open_positions_table()
def build_document(self): series_list = [self.strategy_series, self.benchmark_series] # First Page self._add_header() self._add_perf_chart(series_list) self._add_relative_performance_chart(self.strategy_series, self.benchmark_series) self._add_statistics_table(series_list) # Next Page self.document.add_element(NewPageElement()) self._add_header() self.document.add_element(ParagraphElement("\n")) self._add_returns_statistics_charts(self.strategy_series) self._add_returns_statistics_charts(self.benchmark_series) self.document.add_element(ParagraphElement("\n")) self.document.add_element(ParagraphElement("\n")) self._add_ret_distribution_and_similarity() # Next Page self.document.add_element(NewPageElement()) self._add_header() self.document.add_element(ParagraphElement("\n")) self.document.add_element(ParagraphElement("\n")) self._add_rolling_return_chart(series_list) self.document.add_element(ParagraphElement("\n")) self.document.add_element(ParagraphElement("\n")) self._add_rolling_vol_chart(series_list)
def build_document(self): self._add_header() self.document.add_element(ParagraphElement("\n")) if self._sector_data is not None: self._add_chart(self._sector_data, self._sector_data.name) if self._factor_data is not None: self._add_chart(self._factor_data, self._factor_data.name)
def _add_page(self, ticker: Ticker): self._add_header() self.document.add_element(ParagraphElement("\n")) self.document.add_element(HeadingElement(2, ticker.as_string())) self.document.add_element(ParagraphElement("\n")) price_df = self.price_provider.get_price(ticker, PriceField.ohlcv(), self.start_date, self.end_date) self._insert_table_with_overall_measures(price_df, ticker) self.document.add_element(ParagraphElement("\n")) self._add_price_chart(price_df) self.document.add_element(ParagraphElement("\n")) self._add_trend_strength_chart(price_df) self.document.add_element(ParagraphElement("\n")) self._add_up_and_down_trend_strength(price_df) self.document.add_element(NewPageElement()) # add page break
def _add_backtest_description(self): """ Adds verbal description of the backtest to the document. The description will be placed on a single page. """ param_names = self._get_param_names() self.document.add_element( HeadingElement( 1, "Model: {}".format(self.backtest_summary.backtest_name))) self.document.add_element(ParagraphElement("\n")) self.document.add_element( HeadingElement(2, "Tickers tested in this study: ")) ticker_str = "\n".join([ ticker.name if isinstance(ticker, FutureTicker) else ticker.as_string() for ticker in self.backtest_summary.tickers ]) self.document.add_element(ParagraphElement(ticker_str)) self.document.add_element(ParagraphElement("\n")) self.document.add_element(HeadingElement(2, "Dates of the backtest")) self.document.add_element( ParagraphElement("Backtest start date: {}".format( date_to_str(self.backtest_summary.start_date)))) self.document.add_element( ParagraphElement("Backtest end date: {}".format( date_to_str(self.backtest_summary.end_date)))) self.document.add_element(ParagraphElement("\n")) self.document.add_element(HeadingElement(2, "Parameters Tested")) for param_index, param_list in enumerate( self.backtest_summary.parameters_tested): param_list_str = ", ".join(map(str, param_list)) self.document.add_element( ParagraphElement("{} = [{}]".format(param_names[param_index], param_list_str))) self.document.add_element(NewPageElement()) self.document.add_element( HeadingElement(2, "Alpha model implementation")) self.document.add_element(ParagraphElement("\n")) model_type = self.backtest_summary.alpha_model_type with open(inspect.getfile(model_type)) as f: class_implementation = f.read() # Remove the imports section class_implementation = "<pre>class {}".format(model_type.__name__) + \ class_implementation.split("class {}".format(model_type.__name__))[1] + "</pre>" self.document.add_element(CustomElement(class_implementation))
def build_document(self): self._add_header() self.document.add_element(ParagraphElement("\n")) self._add_leverage_chart() self._add_assets_number_in_portfolio_chart() self._add_concentration_of_portfolio_chart((1, 5,)) self._add_gini_coefficient_chart() self._add_number_of_transactions_chart('D', 'Number of transactions per day') self._add_number_of_transactions_chart('30D', 'Number of transactions per month') self._add_number_of_transactions_chart('365D', 'Number of transactions per year') self._add_volume_traded() self._add_avg_time_in_the_market_per_ticker() self._add_performance_statistics()
def _add_performance_statistics(self, ticker_to_pnl_series: Dict[Ticker, PricesSeries]): """ Generate performance and drawdown plots, which provide the comparison between the strategy performance and Buy and Hold performance for each of the assets. """ self.document.add_element(NewPageElement()) self.document.add_element( HeadingElement( level=2, text="Performance and Drawdowns - Strategy vs Buy and Hold")) self.document.add_element(ParagraphElement("\n")) for ticker in self.tickers: grid = self._get_new_grid() buy_and_hold_returns = self._generate_buy_and_hold_returns(ticker) strategy_exposure_series = ticker_to_pnl_series[ ticker].to_simple_returns().fillna(0.0) strategy_exposure_series = strategy_exposure_series.where( strategy_exposure_series == 0.0).fillna(1.0) strategy_returns = buy_and_hold_returns * strategy_exposure_series strategy_returns = strategy_returns.dropna() strategy_returns.name = "Strategy" if len(strategy_returns) > 0: perf_chart = self._get_perf_chart( [buy_and_hold_returns, strategy_returns], False, "Performance - {}".format(ticker.name)) underwater_chart = self._get_underwater_chart( strategy_returns.to_prices(), title="Drawdown - {}".format(ticker.name), benchmark_series=buy_and_hold_returns.to_prices(), rotate_x_axis=True) grid.add_chart(perf_chart) grid.add_chart(underwater_chart) self.document.add_element(grid) else: self._logger.warning( "No data is available for {}. No plots will be generated.". format(ticker.name))
def build_document(self): """Creates a document with charts""" self._add_header() end_date = pd.concat(self.factors_series, axis=1).index.max() start_date = end_date - RelativeDelta(years=1) all_series_one_year = [self.benchmark_series.loc[start_date:]] + \ [series.loc[start_date:] for series in self.factors_series] self._add_perf_chart_for_factor(series_list=all_series_one_year, title="Factors - 1 Year") all_series = [self.benchmark_series] + self.factors_series self._add_perf_chart_for_factor(series_list=all_series, title="Factors - Full History", force_log_scale=True) for series in self.factors_series: self.document.add_element(NewPageElement()) self._add_header() self._add_perf_chart_for_factor(series_list=[ self.benchmark_series.loc[start_date:], series.loc[start_date:] ], title="{} - 1 Year".format( series.name)) self._add_relative_performance_chart( series.loc[start_date:], self.benchmark_series.loc[start_date:], chart_title="Relative Performance", legend_subtitle="Factor - Benchmark") self._add_perf_chart_for_factor( series_list=[self.benchmark_series, series], title="{} - Full History".format(series.name), force_log_scale=True) self.document.add_element(ParagraphElement("\n")) self._add_relative_performance_chart( series, self.benchmark_series, chart_title="Relative Performance", legend_subtitle="Factor - Benchmark")
def add_backtest_description(document: Document, backtest_result: BacktestSummary, param_names: List[str]): """ Adds verbal description of the backtest to the document. The description will be placed on a single page. """ document.add_element(ParagraphElement("\n")) document.add_element( HeadingElement(1, "Model: {}".format(backtest_result.backtest_name))) document.add_element(ParagraphElement("\n")) document.add_element(HeadingElement(2, "Tickers tested in this study: ")) ticker_str = "\n".join( [ticker.as_string() for ticker in backtest_result.tickers]) document.add_element(ParagraphElement(ticker_str)) document.add_element(ParagraphElement("\n")) document.add_element(HeadingElement(2, "Dates of the backtest")) document.add_element( ParagraphElement("Backtest start date: {}".format( date_to_str(backtest_result.start_date)))) document.add_element( ParagraphElement("Backtest end date: {}".format( date_to_str(backtest_result.end_date)))) document.add_element(ParagraphElement("\n")) document.add_element(HeadingElement(2, "Parameters Tested")) for param_index, param_list in enumerate( backtest_result.parameters_tested): param_list_str = ", ".join(map(str, param_list)) document.add_element( ParagraphElement("{} = [{}]".format(param_names[param_index], param_list_str))) document.add_element(NewPageElement())
def add_models_implementation(self): """ Add the source code of the classes (in order to simplify the implementation the full contents of the file containing. If there are multiple alpha models which are different instances of the same class, the implementation will be printed only once. """ alpha_model_types = { alpha_model.__class__ for alpha_model in self.alpha_models } for model_type in alpha_model_types: self.document.add_element( HeadingElement( 2, "Implementation of {}".format(model_type.__name__))) self.document.add_element(ParagraphElement("\n")) with open(inspect.getfile(model_type)) as f: class_implementation = f.read() # Remove the imports section class_implementation = "<pre>class {}".format(model_type.__name__) + \ class_implementation.split("class {}".format(model_type.__name__))[1] + "</pre>" self.document.add_element(CustomElement(class_implementation))
def build_document(self): self._add_header() self.document.add_element(ParagraphElement("\n")) self._add_leverage_chart()