예제 #1
0
    def evaluate_params_for_tickers(self, parameters: tuple,
                                    tickers: Sequence[Ticker],
                                    start_time: datetime, end_date: datetime):

        # Get the backtest element for the given list of tickers
        backtest_elements_for_tickers = [
            el for el in self.params_backtest_summary_elem_dict[parameters]
            if set(el.tickers) == set(tickers)
        ]
        assert len(backtest_elements_for_tickers) == 1, "Check if the modeled_params passed to " \
                                                        "FastAlphaModelTesterConfig match those you want to test"
        backtest_elem = backtest_elements_for_tickers[0]
        returns_tms = backtest_elem.returns_tms.dropna(how="all")
        trades = backtest_elem.trades

        # Create the TradesEvaluationResult object
        ticker_evaluation = TradesEvaluationResult()
        ticker_evaluation.ticker = tickers
        ticker_evaluation.parameters = parameters
        ticker_evaluation.end_date = end_date
        # Compute the start date as the maximum value between the given start_time and the first date of returns tms in
        # case of 1 ticker backtest
        if len(tickers) == 1:
            start_date = max(
                start_time,
                returns_tms.index[0]) if not returns_tms.empty else end_date
        else:
            start_date = start_time
        ticker_evaluation.start_date = start_date

        if start_date >= end_date:
            # Do not compute further fields - return the default None values
            return ticker_evaluation

        avg_nr_of_trades = avg_nr_of_trades_per1y(
            QFSeries([
                t for t in trades
                if t.start_time >= start_date and t.end_time <= end_date
            ]), start_date, end_date)
        ticker_evaluation.avg_nr_of_trades_1Y = avg_nr_of_trades
        ticker_evaluation.sqn_per_avg_nr_trades = sqn(
            QFSeries([
                t.pnl for t in trades
                if t.start_time >= start_date and t.end_time <= end_date
            ])) * sqrt(avg_nr_of_trades)

        returns_tms = returns_tms.loc[start_date:end_date]
        if not returns_tms.empty:
            ticker_evaluation.annualised_return = cagr(returns_tms,
                                                       Frequency.DAILY)

        return ticker_evaluation
예제 #2
0
 def sqn_per_year(returns: QFSeries):
     sqn_per_year_value = sqn(returns) * sqrt(avg_nr_of_trades_per1y(returns, self.start_date, self.end_date))
     return sqn_per_year_value
예제 #3
0
    def _add_stats_table(self):
        statistics = []  # type: List[Tuple]

        def append_to_statistics(measure_description: str, function: Callable, trades_containers,
                                 percentage_style: bool = False):
            style_format = "{:.2%}" if percentage_style else "{:.2f}"
            returned_values = (function(tc) for tc in trades_containers)
            returned_values = (value if is_finite_number(value) else 0.0 for value in returned_values)
            statistics.append((measure_description, *(style_format.format(val) for val in returned_values)))

        # Prepare trades data frame, used to generate all statistics
        trades_df = QFDataFrame.from_records(
            data=[(t.start_time, t.end_time, t.percentage_pnl, t.direction) for t in self.trades],
            columns=["start time", "end time", "percentage pnl", "direction"]
        )

        # In case if the initial risk is not set all the return statistic will be computed using the percentage pnl,
        # otherwise the r_multiply = percentage pnl / initial risk is used
        unit = "%" if self.initial_risk is None else "R"
        trades_df["returns"] = trades_df["percentage pnl"] if self.initial_risk is None \
            else trades_df["percentage pnl"] / self.initial_risk

        # Filter out only long and only
        long_trades_df = trades_df[trades_df["direction"] > 0]
        short_trades_df = trades_df[trades_df["direction"] < 0]
        all_dfs = [trades_df, long_trades_df, short_trades_df]

        append_to_statistics("Number of trades", len, all_dfs)
        append_to_statistics("% of trades number", lambda df: len(df) / len(trades_df) if len(trades_df) > 0 else 0,
                             all_dfs, percentage_style=True)

        period_length_in_years = Timedelta(self.end_date - self.start_date) / Timedelta(days=1) / DAYS_PER_YEAR_AVG
        append_to_statistics("Avg number of trades per year", lambda df: len(df) / period_length_in_years, all_dfs)
        append_to_statistics("Avg number of trades per year per asset",
                             lambda df: len(df) / period_length_in_years / self.nr_of_assets_traded, all_dfs)

        def percentage_of_positive_trades(df: QFDataFrame):
            return len(df[df["returns"] > 0]) / len(df) if len(df) > 0 else 0.0
        append_to_statistics("% of positive trades", percentage_of_positive_trades, all_dfs, percentage_style=True)

        def percentage_of_negative_trades(df: QFDataFrame):
            return len(df[df["returns"] < 0]) / len(df) if len(df) > 0 else 0.0
        append_to_statistics("% of negative trades", percentage_of_negative_trades, all_dfs, percentage_style=True)

        def avg_trade_duration(df: QFDataFrame):
            trades_duration = (df["end time"] - df["start time"]) / Timedelta(days=1)
            return trades_duration.mean()
        append_to_statistics("Average trade duration [days]", avg_trade_duration, all_dfs)

        append_to_statistics("Average trade return [{}]".format(unit), lambda df: df["returns"].mean(), all_dfs,
                             percentage_style=(self.initial_risk is None))
        append_to_statistics("Std trade return [{}]".format(unit), lambda df: df["returns"].std(), all_dfs,
                             percentage_style=(self.initial_risk is None))

        def avg_positive_trade_return(df: QFDataFrame):
            positive_trades = df[df["returns"] > 0]
            return positive_trades["returns"].mean()
        append_to_statistics("Average positive return [{}]".format(unit), avg_positive_trade_return, all_dfs,
                             percentage_style=(self.initial_risk is None))

        def avg_negative_trade_return(df: QFDataFrame):
            negative_trades = df[df["returns"] < 0]
            return negative_trades["returns"].mean()
        append_to_statistics("Average negative return [{}]".format(unit), avg_negative_trade_return, all_dfs,
                             percentage_style=(self.initial_risk is None))

        append_to_statistics("Best trade return [{}]".format(unit), lambda df: df["returns"].max(), all_dfs,
                             percentage_style=(self.initial_risk is None))
        append_to_statistics("Worst trade return [{}]".format(unit), lambda df: df["returns"].min(), all_dfs,
                             percentage_style=(self.initial_risk is None))

        append_to_statistics("SQN (per trade) [{}]".format(unit), lambda df: sqn(df["returns"]), all_dfs,
                             percentage_style=(self.initial_risk is None))
        append_to_statistics("SQN (per 100 trades) [{}]".format(unit), lambda df: sqn_for100trades(df["returns"]),
                             all_dfs, percentage_style=(self.initial_risk is None))

        def sqn_per_year(returns: QFSeries):
            sqn_per_year_value = sqn(returns) * sqrt(avg_nr_of_trades_per1y(returns, self.start_date, self.end_date))
            return sqn_per_year_value
        append_to_statistics("SQN (per year) [{}]".format(unit), lambda df: sqn_per_year(df["returns"]), all_dfs,
                             percentage_style=(self.initial_risk is None))

        statistics_df = QFDataFrame.from_records(statistics, columns=["Measure", "All trades", "Long trades",
                                                                      "Short trades"])
        table = DFTable(statistics_df, css_classes=['table', 'left-align'])
        table.add_columns_classes(["Measure"], 'wide-column')
        self.document.add_element(table)
예제 #4
0
 def test_sqn(self):
     expected_value = 0.178174161
     actual_return = sqn(self.trades)
     self.assertAlmostEqual(expected_value, actual_return, places=4)
예제 #5
0
파일: test_sqn.py 프로젝트: quarkfin/qf-lib
 def test_sqn(self):
     expected_value = 0.178174161
     actual_return = sqn(
         SimpleReturnsSeries(t.percentage_pnl for t in self.trades))
     self.assertAlmostEqual(expected_value, actual_return, places=4)