コード例 #1
0
    def get_factor_return_attribution(cls, fund_tms: QFSeries,
                                      fit_tms: QFSeries,
                                      regressors_df: QFDataFrame,
                                      coefficients: QFSeries,
                                      alpha: float) -> Tuple[QFSeries, float]:
        """
        Returns performance attribution for each factor in given regressors and also calculates the unexplained return.
        """
        fund_returns = fund_tms.to_simple_returns()
        regressors_returns = regressors_df.to_simple_returns()
        annualised_fund_return = cagr(fund_returns)
        annualised_fit_return = cagr(fit_tms)

        total_nav = fit_tms.to_prices(initial_price=1.0)

        def calc_factors_profit(series) -> float:
            factor_ret = regressors_returns.loc[:, series.name].values
            return coefficients.loc[series.name] * (total_nav[:-1].values *
                                                    factor_ret).sum()

        factors_profits = regressors_returns.apply(calc_factors_profit)

        alpha_profit = total_nav[:-1].sum() * alpha
        total_profit = factors_profits.sum() + alpha_profit

        regressors_return_attribution = factors_profits * annualised_fit_return / total_profit
        regressors_return_attribution = cast_series(
            regressors_return_attribution, QFSeries)

        unexplained_return = annualised_fund_return - regressors_return_attribution.sum(
        )

        return regressors_return_attribution, unexplained_return
コード例 #2
0
def sharpe_ratio(qf_series: QFSeries,
                 frequency: Frequency,
                 risk_free: float = 0) -> float:
    """
    Calculates the Sharpe Ratio for a given timeseries of returns and given frequency.

    Parameters
    ----------
    qf_series: QFSeries
        financial series
    frequency: Frequency
        frequency of the series
    risk_free: float
        risk free rate

    Returns
    -------
    float
        Sharpe Ratio for given series and frequency
    """
    annual_simple_return = cagr(qf_series, frequency)
    annual_log_return = np.log(annual_simple_return + 1)
    annual_vol = get_volatility(qf_series, frequency, annualise=True)

    return (annual_log_return - risk_free) / annual_vol
コード例 #3
0
ファイル: sorino_ratio.py プロジェクト: quarkfin/qf-lib
def sorino_ratio(qf_series: QFSeries,
                 frequency: Frequency,
                 risk_free: float = 0) -> float:
    """
    Calculates the Sorino ratio for a given timeseries of returns.
    sorino_ratio = (CAGR - risk free) / annualised downside volatility

    Parameters
    ----------
    qf_series: QFSeries
        financial series
    frequency: Frequency
        frequency of the qf_series
    risk_free: float
        risk free rate

    Returns
    -------
    float
    """

    annualised_growth_rate = cagr(qf_series, frequency)
    negative_returns = qf_series[qf_series < 0]
    annualised_downside_vol = get_volatility(negative_returns,
                                             frequency,
                                             annualise=True)

    ratio = (annualised_growth_rate - risk_free) / annualised_downside_vol
    return ratio
コード例 #4
0
 def _get_best_strategies_returns(self) -> List[float]:
     """ Returns the annual returns of the best IS strategies """
     annual_returns = []
     for oos_set, best_strategy_name in zip(self._oos_set,
                                            self.best_is_strategies_names):
         best_strategy_tms = oos_set.loc[:, best_strategy_name]
         annual_simple_return = cagr(best_strategy_tms, Frequency.DAILY)
         annual_returns.append(annual_simple_return)
     return annual_returns
コード例 #5
0
ファイル: evaluation_utils.py プロジェクト: quarkfin/qf-lib
    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
コード例 #6
0
def trade_based_cagr(trades: QFDataFrame, start_date: datetime,
                     end_date: datetime):
    """
    Calculates average number of trades per year for a given data-frame of trades.
    """
    returns = trades[TradeField.Return]
    dates = trades[TradeField.EndDate]

    # insert start date and the beginning and end date at the end.
    # we insert nex start + 1day to returns and set the frequency for to_prices to daily so that the
    # prices series will start exactly from the start_date
    returns = pd.concat([pd.Series([0]), returns, pd.Series([0])])
    dates = pd.concat([
        pd.Series([start_date]), dates + timedelta(days=1),
        pd.Series([end_date])
    ])

    returns_tms = SimpleReturnsSeries(index=dates, data=returns.values)
    prices_tms = returns_tms.to_prices(frequency=Frequency.DAILY)
    return cagr(prices_tms)
コード例 #7
0
def calmar_ratio(qf_series: QFSeries, frequency: Frequency) -> float:
    """
    Calculates the Calmar ratio for a given timeseries of returns.
    calmar_ratio = CAGR / max drawdown

    Parameters
    ----------
    qf_series
        financial series
    frequency
        frequency of qf_series

    Returns
    -------
    calmar_ratio
    """

    annualised_growth_rate = cagr(qf_series, frequency)
    max_dd = max_drawdown(qf_series)
    ratio = annualised_growth_rate / max_dd
    return ratio
コード例 #8
0
 def _calculate_return(self):
     self.total_return = self.returns_tms.total_cumulative_return()
     self.cagr = cagr(self.returns_tms, self.frequency)
コード例 #9
0
ファイル: test_returns.py プロジェクト: mborraty/qf-lib
 def test_compound_annual_growth_rate_monthly(self):
     actual_return = cagr(self.test_dd_prices_tms)
     expected_return = pow(1.5, 12.0/12.0)-1
     self.assertAlmostEqual(expected_return, actual_return, delta=0.001)
コード例 #10
0
ファイル: test_returns.py プロジェクト: mborraty/qf-lib
 def test_compound_annual_growth_rate(self):
     expected_return = 535.67015428006502590536838042708
     actual_return = cagr(self.test_simple_returns_tms)
     self.assertAlmostEqual(expected_return, actual_return)