예제 #1
0
    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)
예제 #2
0
    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)
예제 #3
0
    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)
예제 #4
0
    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))
예제 #5
0
    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)
예제 #6
0
    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)
예제 #7
0
    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)
예제 #8
0
    def build_document(self):
        self._add_header()

        self.document.add_element(ParagraphElement("\n"))

        self._add_histogram_and_cumulative()
        self._add_statistics_table()
예제 #9
0
    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()
예제 #10
0
    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)
예제 #11
0
    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)
예제 #12
0
    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
예제 #13
0
    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))
예제 #14
0
    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()
예제 #15
0
    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))
예제 #16
0
    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")
예제 #17
0
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())
예제 #18
0
    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))
예제 #19
0
 def build_document(self):
     self._add_header()
     self.document.add_element(ParagraphElement("\n"))
     self._add_leverage_chart()