Exemplo n.º 1
0
 def test_alpha(self, test_risk_free):
     res_a = empyrical.alpha(ret['a'], benchmark_rets['a'], risk_free=test_risk_free)
     res_b = empyrical.alpha(ret['b'], benchmark_rets['b'], risk_free=test_risk_free)
     res_c = empyrical.alpha(ret['c'], benchmark_rets['c'], risk_free=test_risk_free)
     assert isclose(ret['a'].vbt.returns.alpha(benchmark_rets['a'], risk_free=test_risk_free), res_a)
     pd.testing.assert_series_equal(
         ret.vbt.returns.alpha(benchmark_rets, risk_free=test_risk_free),
         pd.Series([res_a, res_b, res_c], index=ret.columns).rename('alpha')
     )
Exemplo n.º 2
0
def perf_stats(returns,
               factor_returns=None,
               positions=None,
               transactions=None,
               turnover_denom='AGB'):
    """
    Calculates various performance metrics of a strategy, for use in
    plotting.show_perf_stats.

    Parameters
    ----------
    returns : pd.Series
        Daily returns of the strategy, noncumulative.
         - See full explanation in tears.create_full_tear_sheet.
    factor_returns : pd.Series, optional
        Daily noncumulative returns of the benchmark factor to which betas are
        computed. Usually a benchmark such as market returns.
         - This is in the same style as returns.
         - If None, do not compute alpha, beta, and information ratio.
    positions : pd.DataFrame
        Daily net position values.
         - See full explanation in tears.create_full_tear_sheet.
    transactions : pd.DataFrame
        Prices and amounts of executed trades. One row per trade.
        - See full explanation in tears.create_full_tear_sheet.
    turnover_denom : str
        Either AGB or portfolio_value, default AGB.
        - See full explanation in txn.get_turnover.

    Returns
    -------
    pd.Series
        Performance metrics.
    """

    stats = pd.Series()
    for stat_func in SIMPLE_STAT_FUNCS:
        stats[STAT_FUNC_NAMES[stat_func.__name__]] = stat_func(
            returns, annualization=APPROX_BDAYS_PER_YEAR)
    for stat_func in SIMPLE_STAT_FUNCS1:
        stats[STAT_FUNC_NAMES1[stat_func.__name__]] = stat_func(returns)

    if positions is not None:
        stats['Gross leverage'] = gross_lev(positions).mean()
        if transactions is not None:
            stats['Daily turnover'] = get_turnover(positions, transactions,
                                                   turnover_denom).mean()
    if factor_returns is not None:
        stats['Alpha'] = ep.alpha(returns,
                                  factor_returns,
                                  annualization=APPROX_BDAYS_PER_YEAR)
        stats['Beta'] = ep.beta(returns, factor_returns)
    # for stat_func in FACTOR_STAT_FUNCS:
    #     res = stat_func(returns, factor_returns, annualization=APPROX_BDAYS_PER_YEAR)
    #     stats[STAT_FUNC_NAMES[stat_func.__name__]] = res
    # for stat_func in FACTOR_STAT_FUNCS1:
    #     res = stat_func(returns, factor_returns)
    #     stats[STAT_FUNC_NAMES1[stat_func.__name__]] = res

    return stats
Exemplo n.º 3
0
def get_perf_att(series, bnchmark, rf=0.03 / 12, freq='monthly'):
    """F: that provides performance statistic of the returns
    params
    -------

        series: daily or monthly returns

    returns:
        dataframe of Strategy name and statistics"""
    port_mean, port_std, port_sr = (get_stats(series, dtime=freq))
    perf = pd.Series(
        {
            'Annualized_Mean':
            '{:,.2f}'.format(round(port_mean, 3)),
            'Annualized_Volatility':
            round(port_std, 3),
            'Sharpe Ratio':
            round(port_sr, 3),
            'Calmar Ratio':
            round(empyrical.calmar_ratio(series, period=freq), 3),
            'Alpha':
            round(empyrical.alpha(series, bnchmark, risk_free=rf, period=freq),
                  3),
            'Beta':
            round(empyrical.beta(series, bnchmark), 3),
            'Max Drawdown':
            '{:,.2%}'.format(drawdown(series, ret_='nottext')),
            'Sortino Ratio':
            round(
                empyrical.sortino_ratio(
                    series, required_return=rf, period=freq), 3),
        }, )
    perf.name = series.name
    return perf.to_frame()
Exemplo n.º 4
0
    def calculate_metrics(self):
        self.benchmark_period_returns = \
            cum_returns(self.benchmark_returns).iloc[-1]

        self.algorithm_period_returns = \
            cum_returns(self.algorithm_returns).iloc[-1]

        if not self.algorithm_returns.index.equals(
                self.benchmark_returns.index):
            message = "Mismatch between benchmark_returns ({bm_count}) and \
            algorithm_returns ({algo_count}) in range {start} : {end}"

            message = message.format(bm_count=len(self.benchmark_returns),
                                     algo_count=len(self.algorithm_returns),
                                     start=self._start_session,
                                     end=self._end_session)
            raise Exception(message)

        self.num_trading_days = len(self.benchmark_returns)
        self.trading_day_counts = pd.stats.moments.rolling_count(
            self.algorithm_returns, self.num_trading_days)

        self.mean_algorithm_returns = \
            self.algorithm_returns.cumsum() / self.trading_day_counts

        self.benchmark_volatility = annual_volatility(self.benchmark_returns)
        self.algorithm_volatility = annual_volatility(self.algorithm_returns)

        self.treasury_period_return = choose_treasury(
            self.treasury_curves,
            self._start_session,
            self._end_session,
            self.trading_calendar,
        )
        self.sharpe = sharpe_ratio(self.algorithm_returns, )
        # The consumer currently expects a 0.0 value for sharpe in period,
        # this differs from cumulative which was np.nan.
        # When factoring out the sharpe_ratio, the different return types
        # were collapsed into `np.nan`.
        # TODO: Either fix consumer to accept `np.nan` or make the
        # `sharpe_ratio` return type configurable.
        # In the meantime, convert nan values to 0.0
        if pd.isnull(self.sharpe):
            self.sharpe = 0.0
        self.downside_risk = downside_risk(self.algorithm_returns)
        self.sortino = sortino_ratio(self.algorithm_returns,
                                     _downside_risk=self.downside_risk)
        self.information = information_ratio(self.algorithm_returns,
                                             self.benchmark_returns)
        self.beta = beta(self.algorithm_returns, self.benchmark_returns)
        self.alpha = alpha(self.algorithm_returns,
                           self.benchmark_returns,
                           _beta=self.beta)
        self.excess_return = self.algorithm_period_returns - \
            self.treasury_period_return
        self.max_drawdown = max_drawdown(self.algorithm_returns)
        self.max_leverage = self.calculate_max_leverage()
Exemplo n.º 5
0
 def test_alpha_beta_equality(self, returns, benchmark):
     alpha_beta = empyrical.alpha_beta(returns, benchmark)
     assert_almost_equal(
         alpha_beta[0],
         empyrical.alpha(returns, benchmark),
         DECIMAL_PLACES)
     assert_almost_equal(
         alpha_beta[1],
         empyrical.beta(returns, benchmark),
         DECIMAL_PLACES)
Exemplo n.º 6
0
def _get_backtest_performance_metrics(ret, benchmark_ret):
    metrics = {
        'alpha': empyrical.alpha(ret, benchmark_ret),
        'beta': empyrical.beta(ret, benchmark_ret),
        'return': empyrical.cum_returns_final(ret),
        'cagr': empyrical.cagr(ret),
        'sharpe': empyrical.sharpe_ratio(ret),
        'max_drawdown': empyrical.max_drawdown(ret),
        'var': empyrical.value_at_risk(ret),
        'volatility': empyrical.annual_volatility(ret),
    }

    return metrics
Exemplo n.º 7
0
    def test_alpha(self, returns, benchmark, expected):
        observed = empyrical.alpha(returns, benchmark)
        assert_almost_equal(observed, expected, DECIMAL_PLACES)

        if len(returns) == len(benchmark):
            # Compare to scipy linregress
            returns_arr = returns.values
            benchmark_arr = benchmark.values
            mask = ~np.isnan(returns_arr) & ~np.isnan(benchmark_arr)
            slope, intercept, _, _, _ = stats.linregress(
                benchmark_arr[mask], returns_arr[mask])

            assert_almost_equal(observed, intercept * 252, DECIMAL_PLACES)
Exemplo n.º 8
0
    def test_alpha_beta_equality(self, returns, benchmark):
        alpha_beta = empyrical.alpha_beta(returns, benchmark)
        assert_almost_equal(alpha_beta[0], empyrical.alpha(returns, benchmark),
                            DECIMAL_PLACES)
        assert_almost_equal(alpha_beta[1], empyrical.beta(returns, benchmark),
                            DECIMAL_PLACES)

        if len(returns) == len(benchmark):
            # Compare to scipy linregress
            returns_arr = returns.values
            benchmark_arr = benchmark.values
            mask = ~np.isnan(returns_arr) & ~np.isnan(benchmark_arr)
            slope, intercept, _, _, _ = stats.linregress(
                returns_arr[mask], benchmark_arr[mask])

            assert_almost_equal(alpha_beta[0], intercept)
            assert_almost_equal(alpha_beta[1], slope)
Exemplo n.º 9
0
def alpha(close,
          benchmark_close,
          risk_free=0.0,
          period='daily',
          annualization=None,
          _beta=None):
    try:
        rets = daily_returns(close)
        benchmark_rets = daily_returns(benchmark_close)
        alpha_data = empyrical.alpha(rets,
                                     benchmark_rets,
                                     risk_free=risk_free,
                                     period=period,
                                     annualization=annualization,
                                     _beta=_beta)
        return alpha_data
    except Exception as e:
        raise (e)
Exemplo n.º 10
0
def alpha(returns, factor_returns):
    """Calculates annualized alpha.

    Parameters
    ----------
    returns : pd.Series
        Daily returns of the strategy, noncumulative.
        - See full explanation in :func:`~pyfolio.timeseries.cum_returns`.
    factor_returns : pd.Series
         Daily noncumulative returns of the factor to which beta is
         computed. Usually a benchmark such as the market.
         - This is in the same style as returns.

    Returns
    -------
    float
        Alpha.
    """

    return empyrical.alpha(returns, factor_returns=factor_returns)
Exemplo n.º 11
0
def alpha(daily_returns: Any,
          benchmark_daily_returns: Any,
          risk_free: float = 0.0,
          period: str = 'daily',
          annualization: Any = None,
          _beta: Any = None):
    """Alpha"""
    try:
        logger.info('Calculating Alpha...')
        check_inputs_length(daily_returns, benchmark_daily_returns)
        alpha_data = empyrical.alpha(daily_returns,
                                     benchmark_daily_returns,
                                     risk_free=risk_free,
                                     period=period,
                                     annualization=annualization,
                                     _beta=_beta)
        return alpha_data
    except Exception as exception:
        logger.error('Oops! An Error Occurred ⚠️')
        raise exception
Exemplo n.º 12
0
def alpha(returns, factor_returns):
    """
    Calculates annualized alpha.

    Parameters
    ----------
    returns : pd.Series
        Daily returns of the strategy, noncumulative.
        - See full explanation in :func:`~pyfolio.timeseries.cum_returns`.
    factor_returns : pd.Series
         Daily noncumulative returns of the factor to which beta is
         computed. Usually a benchmark such as the market.
         - This is in the same style as returns.

    Returns
    -------
    float
        Alpha.
    """

    return empyrical.alpha(returns, factor_returns=factor_returns)
def get_performance_table(return_df: pd.DataFrame,
                          benchmark_name: str = None,
                          periods: str = 'daily') -> pd.DataFrame:
    """收益指标

    Args:
        return_df (pd.DataFrame): 收益率表格
        benchmark_name (str): 基准的列名
        periods (str, optional): 频率. Defaults to 'daily'.

    Returns:
        pd.DataFrame
    """
    ser: pd.DataFrame = pd.DataFrame()
    ser['年化收益率'] = ep.annual_return(return_df, period=periods)
    ser['累计收益'] = ep.cum_returns(return_df).iloc[-1]
    ser['波动率'] = return_df.apply(
        lambda x: ep.annual_volatility(x, period=periods))
    ser['夏普'] = return_df.apply(ep.sharpe_ratio, period=periods)
    ser['最大回撤'] = return_df.apply(lambda x: ep.max_drawdown(x))

    if benchmark_name is not None:

        select_col = [
            col for col in return_df.columns if col != benchmark_name
        ]

        ser['IR'] = return_df[select_col].apply(
            lambda x: information_ratio(x, return_df[benchmark_name]))
        ser['Alpha'] = return_df[select_col].apply(
            lambda x: ep.alpha(x, return_df[benchmark_name], period=periods))

        ser['超额收益'] = ser['年化收益率'] - ser.loc[benchmark_name,
                                             '年化收益率']  #计算相对年化波动率

    return ser.T
Exemplo n.º 14
0
def alpha(portfolio_daily_returns, benchmark_returns=None):
    if benchmark_returns is None:
        benchmark_returns = sdata.get_sp500_index_returns(
            portfolio_daily_returns.index[0],
            portfolio_daily_returns.index[-1])
    return ep.alpha(portfolio_daily_returns, benchmark_returns)
Exemplo n.º 15
0
    def update(self, dt, algorithm_returns, benchmark_returns, leverage):
        # Keep track of latest dt for use in to_dict and other methods
        # that report current state.
        self.latest_dt = dt
        dt_loc = self.cont_index.get_loc(dt)
        self.latest_dt_loc = dt_loc

        self.algorithm_returns_cont[dt_loc] = algorithm_returns
        self.algorithm_returns = self.algorithm_returns_cont[: dt_loc + 1]
        algorithm_returns_series = pd.Series(self.algorithm_returns)

        self.num_trading_days = len(self.algorithm_returns)

        if self.create_first_day_stats:
            if len(self.algorithm_returns) == 1:
                self.algorithm_returns = np.append(0.0, self.algorithm_returns)

        self.algorithm_cumulative_returns[dt_loc] = cum_returns(algorithm_returns_series).iloc[-1]

        algo_cumulative_returns_to_date = self.algorithm_cumulative_returns[: dt_loc + 1]

        self.mean_returns_cont[dt_loc] = algo_cumulative_returns_to_date[dt_loc] / self.num_trading_days

        self.mean_returns = self.mean_returns_cont[: dt_loc + 1]

        self.annualized_mean_returns_cont[dt_loc] = self.mean_returns_cont[dt_loc] * 252

        self.annualized_mean_returns = self.annualized_mean_returns_cont[: dt_loc + 1]

        if self.create_first_day_stats:
            if len(self.mean_returns) == 1:
                self.mean_returns = np.append(0.0, self.mean_returns)
                self.annualized_mean_returns = np.append(0.0, self.annualized_mean_returns)

        self.benchmark_returns_cont[dt_loc] = benchmark_returns
        self.benchmark_returns = self.benchmark_returns_cont[: dt_loc + 1]
        benchmark_returns_series = pd.Series(self.benchmark_returns)
        if self.create_first_day_stats:
            if len(self.benchmark_returns) == 1:
                self.benchmark_returns = np.append(0.0, self.benchmark_returns)

        self.benchmark_cumulative_returns[dt_loc] = cum_returns(benchmark_returns_series).iloc[-1]

        benchmark_cumulative_returns_to_date = self.benchmark_cumulative_returns[: dt_loc + 1]

        self.mean_benchmark_returns_cont[dt_loc] = benchmark_cumulative_returns_to_date[dt_loc] / self.num_trading_days

        self.mean_benchmark_returns = self.mean_benchmark_returns_cont[:dt_loc]

        self.annualized_mean_benchmark_returns_cont[dt_loc] = self.mean_benchmark_returns_cont[dt_loc] * 252

        self.annualized_mean_benchmark_returns = self.annualized_mean_benchmark_returns_cont[: dt_loc + 1]

        self.algorithm_cumulative_leverages_cont[dt_loc] = leverage
        self.algorithm_cumulative_leverages = self.algorithm_cumulative_leverages_cont[: dt_loc + 1]

        if self.create_first_day_stats:
            if len(self.algorithm_cumulative_leverages) == 1:
                self.algorithm_cumulative_leverages = np.append(0.0, self.algorithm_cumulative_leverages)

        if not len(self.algorithm_returns) and len(self.benchmark_returns):
            message = "Mismatch between benchmark_returns ({bm_count}) and \
algorithm_returns ({algo_count}) in range {start} : {end} on {dt}"
            message = message.format(
                bm_count=len(self.benchmark_returns),
                algo_count=len(self.algorithm_returns),
                start=self.start_session,
                end=self.end_session,
                dt=dt,
            )
            raise Exception(message)

        self.update_current_max()
        self.benchmark_volatility[dt_loc] = annual_volatility(benchmark_returns_series)
        self.algorithm_volatility[dt_loc] = annual_volatility(algorithm_returns_series)

        # caching the treasury rates for the minutely case is a
        # big speedup, because it avoids searching the treasury
        # curves on every minute.
        # In both minutely and daily, the daily curve is always used.
        treasury_end = dt.replace(hour=0, minute=0)
        if np.isnan(self.daily_treasury[treasury_end]):
            treasury_period_return = choose_treasury(
                self.treasury_curves, self.start_session, treasury_end, self.trading_calendar
            )
            self.daily_treasury[treasury_end] = treasury_period_return
        self.treasury_period_return = self.daily_treasury[treasury_end]
        self.excess_returns[dt_loc] = self.algorithm_cumulative_returns[dt_loc] - self.treasury_period_return

        self.beta[dt_loc] = beta(algorithm_returns_series, benchmark_returns_series)
        self.alpha[dt_loc] = alpha(algorithm_returns_series, benchmark_returns_series, _beta=self.beta[dt_loc])
        self.sharpe[dt_loc] = sharpe_ratio(algorithm_returns_series)
        self.downside_risk[dt_loc] = downside_risk(algorithm_returns_series)
        self.sortino[dt_loc] = sortino_ratio(algorithm_returns_series, _downside_risk=self.downside_risk[dt_loc])
        self.information[dt_loc] = information_ratio(algorithm_returns_series, benchmark_returns_series)
        self.max_drawdown = max_drawdown(algorithm_returns_series)
        self.max_drawdowns[dt_loc] = self.max_drawdown
        self.max_leverage = self.calculate_max_leverage()
        self.max_leverages[dt_loc] = self.max_leverage
Exemplo n.º 16
0
def Strategy_performance(returns: pd.DataFrame,
                         mark_benchmark: str = 'benchmark',
                         periods: str = 'daily') -> pd.DataFrame:
    '''
    风险指标计算

    returns:index-date col-数据字段
    mark_benchmark:用于指明基准
    periods:频率
    '''

    df: pd.DataFrame = pd.DataFrame()

    df['年化收益率'] = ep.annual_return(returns, period=periods)

    df['累计收益'] = returns.apply(lambda x: ep.cum_returns(x).iloc[-1])

    df['波动率'] = returns.apply(
        lambda x: ep.annual_volatility(x, period=periods))

    df['夏普'] = returns.apply(ep.sharpe_ratio, period=periods)

    df['最大回撤'] = returns.apply(lambda x: ep.max_drawdown(x))

    df['索提诺比率'] = returns.apply(lambda x: ep.sortino_ratio(x, period=periods))

    df['Calmar'] = returns.apply(lambda x: ep.calmar_ratio(x, period=periods))

    # 相对指标计算
    if mark_benchmark in returns.columns:

        select_col = [col for col in returns.columns if col != mark_benchmark]
        df['IR'] = returns[select_col].apply(
            lambda x: information_ratio(x, returns[mark_benchmark]))

        df['Alpha'] = returns[select_col].apply(
            lambda x: ep.alpha(x, returns[mark_benchmark], period=periods))

        df['Beta'] = returns[select_col].apply(
            lambda x: ep.beta(x, returns[mark_benchmark]))

        # 计算相对年化波动率
        df['超额收益率'] = df['年化收益率'] - \
            df.loc[mark_benchmark, '年化收益率']

    return df.T


# def show_worst_drawdown_periods(returns: pd.Series,
#                                 benchmark_code: str = "000300.SH",
#                                 top: int = 5):
#     """
#     Prints information about the worst drawdown periods.

#     Prints peak dates, valley dates, recovery dates, and net
#     drawdowns.

#     Parameters
#     ----------
#     returns : pd.Series
#         Daily returns of the strategy, noncumulative.
#          - See full explanation in tears.create_full_tear_sheet.
#     top : int, optional
#         Amount of top drawdowns periods to plot (default 5).
#     """

#     drawdown_df = ts.gen_drawdown_table(returns, top=top)
#     drawdown_df.index = list(range(1, len(drawdown_df) + 1))

#     phase_change = compare_phase_change(returns, benchmark_code, top)

#     df = pd.concat((drawdown_df, phase_change), axis=1)

#     # print_table(
#     #     df.sort_values('区间最大回撤 %', ascending=False),
#     #     name='序号',
#     #     float_format='{0:.2f}'.format,
#     # )

#     return df

# def compare_phase_change(returns: pd.Series,
#                          benchmark_code: str,
#                          top: int = 5) -> pd.DataFrame:
#     '''
#     对比策略与基准在回撤区间内的收益
#     ------
#         returns:策略净值收益率
#         benchmark_code:基准的代码
#     '''

#     beginDt = returns.index.min()
#     endDt = returns.index.max()

#     benchmark = get_wsd_data(benchmark_code,
#                              'pct_chg',
#                              beginDt,
#                              endDt,
#                              'priceAdj=B',
#                              usedf=True)

#     benchmark = benchmark['PCT_CHG'] / 100

#     df = pd.DataFrame(columns=['策略收益%', '基准收益%'],
#                       index=list(range(1, top + 1)))

#     drawdowns_list = ts.get_top_drawdowns(returns, top=top)

#     for i, v in enumerate(drawdowns_list):

#         peak_date, _, recovery_date = v

#         if pd.isnull(recovery_date):

#             df.loc[i + 1, '策略收益%'] = np.nan
#             df.loc[i + 1, '基准收益'] = np.nan

#         else:
#             df.loc[i + 1, '策略收益%'] = ep.cum_returns(
#                 returns.loc[peak_date:recovery_date]).iloc[-1]
#             df.loc[i + 1, '基准收益%'] = ep.cum_returns(
#                 benchmark.loc[peak_date:recovery_date])[-1]

#     return df
Exemplo n.º 17
0
    def update(self, dt, algorithm_returns, benchmark_returns, leverage):
        # Keep track of latest dt for use in to_dict and other methods
        # that report current state.
        self.latest_dt = dt
        dt_loc = self.cont_index.get_loc(dt)
        self.latest_dt_loc = dt_loc

        self.algorithm_returns_cont[dt_loc] = algorithm_returns
        self.algorithm_returns = self.algorithm_returns_cont[:dt_loc + 1]
        algorithm_returns_series = pd.Series(self.algorithm_returns)

        self.num_trading_days = len(self.algorithm_returns)

        if self.create_first_day_stats:
            if len(self.algorithm_returns) == 1:
                self.algorithm_returns = np.append(0.0, self.algorithm_returns)

        self.algorithm_cumulative_returns[dt_loc] = cum_returns(
            algorithm_returns_series).iloc[-1]

        algo_cumulative_returns_to_date = \
            self.algorithm_cumulative_returns[:dt_loc + 1]

        self.mean_returns_cont[dt_loc] = \
            algo_cumulative_returns_to_date[dt_loc] / self.num_trading_days

        self.mean_returns = self.mean_returns_cont[:dt_loc + 1]

        self.annualized_mean_returns_cont[dt_loc] = \
            self.mean_returns_cont[dt_loc] * 252

        self.annualized_mean_returns = \
            self.annualized_mean_returns_cont[:dt_loc + 1]

        if self.create_first_day_stats:
            if len(self.mean_returns) == 1:
                self.mean_returns = np.append(0.0, self.mean_returns)
                self.annualized_mean_returns = np.append(
                    0.0, self.annualized_mean_returns)

        self.benchmark_returns_cont[dt_loc] = benchmark_returns
        self.benchmark_returns = self.benchmark_returns_cont[:dt_loc + 1]
        benchmark_returns_series = pd.Series(self.benchmark_returns)
        if self.create_first_day_stats:
            if len(self.benchmark_returns) == 1:
                self.benchmark_returns = np.append(0.0, self.benchmark_returns)

        self.benchmark_cumulative_returns[dt_loc] = cum_returns(
            benchmark_returns_series).iloc[-1]

        benchmark_cumulative_returns_to_date = \
            self.benchmark_cumulative_returns[:dt_loc + 1]

        self.mean_benchmark_returns_cont[dt_loc] = \
            benchmark_cumulative_returns_to_date[dt_loc] / \
            self.num_trading_days

        self.mean_benchmark_returns = self.mean_benchmark_returns_cont[:dt_loc]

        self.annualized_mean_benchmark_returns_cont[dt_loc] = \
            self.mean_benchmark_returns_cont[dt_loc] * 252

        self.annualized_mean_benchmark_returns = \
            self.annualized_mean_benchmark_returns_cont[:dt_loc + 1]

        self.algorithm_cumulative_leverages_cont[dt_loc] = leverage
        self.algorithm_cumulative_leverages = \
            self.algorithm_cumulative_leverages_cont[:dt_loc + 1]

        if self.create_first_day_stats:
            if len(self.algorithm_cumulative_leverages) == 1:
                self.algorithm_cumulative_leverages = np.append(
                    0.0, self.algorithm_cumulative_leverages)

        if not len(self.algorithm_returns) and len(self.benchmark_returns):
            message = "Mismatch between benchmark_returns ({bm_count}) and \
algorithm_returns ({algo_count}) in range {start} : {end} on {dt}"

            message = message.format(bm_count=len(self.benchmark_returns),
                                     algo_count=len(self.algorithm_returns),
                                     start=self.start_session,
                                     end=self.end_session,
                                     dt=dt)
            raise Exception(message)

        self.update_current_max()
        self.benchmark_volatility[dt_loc] = annual_volatility(
            benchmark_returns_series)
        self.algorithm_volatility[dt_loc] = annual_volatility(
            algorithm_returns_series)

        # caching the treasury rates for the minutely case is a
        # big speedup, because it avoids searching the treasury
        # curves on every minute.
        # In both minutely and daily, the daily curve is always used.
        treasury_end = dt.replace(hour=0, minute=0)
        if np.isnan(self.daily_treasury[treasury_end]):
            treasury_period_return = choose_treasury(
                self.treasury_curves,
                self.start_session,
                treasury_end,
                self.trading_calendar,
            )
            self.daily_treasury[treasury_end] = treasury_period_return
        self.treasury_period_return = self.daily_treasury[treasury_end]
        self.excess_returns[dt_loc] = (
            self.algorithm_cumulative_returns[dt_loc] -
            self.treasury_period_return)
        self.beta[dt_loc] = beta(algorithm_returns_series,
                                 benchmark_returns_series)
        self.alpha[dt_loc] = alpha(algorithm_returns_series,
                                   benchmark_returns_series)
        self.sharpe[dt_loc] = sharpe_ratio(algorithm_returns_series,
                                           benchmark_returns_series)
        self.downside_risk[dt_loc] = downside_risk(algorithm_returns_series,
                                                   benchmark_returns_series)
        self.sortino[dt_loc] = sortino_ratio(algorithm_returns_series,
                                             benchmark_returns_series)
        self.information[dt_loc] = information_ratio(algorithm_returns_series,
                                                     benchmark_returns_series)
        self.max_drawdown = max_drawdown(algorithm_returns_series)
        self.max_drawdowns[dt_loc] = self.max_drawdown
        self.max_leverage = self.calculate_max_leverage()
        self.max_leverages[dt_loc] = self.max_leverage
Exemplo n.º 18
0
def run_turtle():
    PROPERTY = START_MONEY
    CASH = START_MONEY

    show_df = None
    show_df = stock_df_dict['NDX'].copy()

    order_df = None
    order_df = pd.DataFrame(columns=[
        'buy_date', 'symbol', 'buy_count', 'buy_price', 'buy_reason',
        'sell_date', 'sell_price', 'sell_reason', 'profit', 'cash', 'property'
    ])
    count_day = 0
    yesterday = None

    for today in pd.period_range(start=start_date, end=end_date, freq='D'):
        count_day += 1

        if yesterday is None:
            yesterday = today
            continue

        if today not in stock_df_dict['NDX'].index:
            continue

        if IS_HAPPY_MONEY:
            if PROPERTY > START_MONEY * 2:
                global HAPPY_MONEY
                HAPPY_MONEY += int(START_MONEY / 2)
                PROPERTY -= int(START_MONEY / 2)
                CASH = PROPERTY

        # 买卖过程
        sell_signal = []
        buy_signal = []

        for symbol in NASDAQ100[:]:
            # for symbol in ['TSLA']:
            if symbol in [
                    'ALGN', 'ROST', 'ORLY', 'ESRX', 'ULTA', 'REGN', 'MNST'
            ]:
                # continue
                pass

            if symbol == 'NDX':
                continue

            if today not in stock_df_dict[
                    symbol].index or yesterday not in stock_df_dict[
                        symbol].index:
                continue

            # 突破下行趋势,清仓退出
            order_arr = order_df.to_records(index=False)
            if len(order_arr[(order_arr.symbol == symbol)
                             & (order_arr.sell_price == 0)]) != 0:
                is_sell = False
                for idx in order_df[(order_df['symbol'] == symbol)
                                    & (order_df['sell_price'] == 0)].index:
                    if order_df.loc[idx, 'buy_reason'] == 'SHORT':
                        is_sell = (
                            stock_df_dict[symbol].loc[today, 'open'] <=
                            stock_df_dict[symbol].loc[today,
                                                      'ROLLING_%d_MIN' %
                                                      TURTLE_SHORT_SELL_N])
                    if order_df.loc[idx, 'buy_reason'] == 'LONG':
                        is_sell = (
                            stock_df_dict[symbol].loc[today, 'open'] <=
                            stock_df_dict[symbol].loc[today,
                                                      'ROLLING_%d_MIN' %
                                                      TURTLE_LONG_SELL_N])
                    if is_sell:
                        CASH += order_df.loc[idx, 'buy_count'] * \
                            stock_df_dict[symbol].loc[today, 'open']
                        order_df.loc[idx, 'sell_date'] = today
                        order_df.loc[idx,
                                     'sell_price'] = stock_df_dict[symbol].loc[
                                         today, 'open']
                        order_df.loc[idx, 'sell_reason'] = 'EXIT'
                        order_df.loc[idx, 'profit'] = \
                            (order_df.loc[idx, 'sell_price'] - order_df.loc[idx, 'buy_price']) * order_df.loc[idx, 'buy_count']
                    # print(today, '退出', stock_df_dict[symbol].loc[today, 'open'], CASH)

            # 突破上行趋势,买入一份
            order_arr = order_df.to_records(index=False)
            if stock_df_dict[symbol].loc[
                    today, 'MA30'] >= stock_df_dict[symbol].loc[today,
                                                                'MA180']:
                is_buy = False
                if stock_df_dict[symbol].loc[today, 'open'] >= stock_df_dict[
                        symbol].loc[today,
                                    'ROLLING_%d_MAX' % TURTLE_LONG_BUY_N]:
                    is_buy = True
                    buy_reason = 'LONG'
                elif stock_df_dict[symbol].loc[today, 'open'] >= stock_df_dict[
                        symbol].loc[today,
                                    'ROLLING_%d_MAX' % TURTLE_SHORT_BUY_N]:
                    is_buy = True
                    buy_reason = 'SHORT'
                if is_buy:
                    buy_count = 0
                    if CASH >= PROPERTY / TURTLE_POS:
                        buy_count = int(
                            (PROPERTY / TURTLE_POS) /
                            stock_df_dict[symbol].loc[today, 'open'])
                    if buy_count > 0:
                        CASH -= buy_count * \
                            stock_df_dict[symbol].loc[today, 'open']
                        # print(today, '买入', buy_count, stock_df_dict[symbol].loc[today, 'open'], CASH)
                        order_df = order_df.append(
                            {
                                'buy_date':
                                today,
                                'symbol':
                                symbol,
                                'buy_count':
                                buy_count,
                                'buy_price':
                                stock_df_dict[symbol].loc[today, 'open'],
                                'buy_reason':
                                buy_reason,
                                'sell_date':
                                pd.np.nan,
                                'sell_price':
                                0,
                                'profit':
                                0,
                                'cash':
                                CASH,
                                'property':
                                PROPERTY,
                            },
                            ignore_index=True)

        # 每天盘点财产
        show_df.loc[today,
                    'CASH_TURTLE_%d_%d_%d' %
                    (TURTLE_POS, TURTLE_LONG_BUY_N, TURTLE_LONG_SELL_N)] = CASH
        PROPERTY = CASH + \
            sum(
                [
                    stock_df_dict[order_df.loc[idx, 'symbol']].loc[today,
                                                                   'open'] * order_df.loc[idx, 'buy_count']
                    for idx in order_df.loc[order_df['sell_price'] == 0].index
                ]
            )
        show_df.loc[today,
                    'PROPERTY_TURTLE_%d_%d_%d' %
                    (TURTLE_POS, TURTLE_LONG_BUY_N,
                     TURTLE_LONG_SELL_N)] = PROPERTY
        yesterday = today

    # 最终结果
    print('CASH', CASH)
    print('HAPPY_MONEY', HAPPY_MONEY)
    print('PROPERTY', PROPERTY)

    benchmark_symbol = 'NDX'
    s_p = stock_df_dict[benchmark_symbol][start_date:].iloc[0].open
    e_p = stock_df_dict[benchmark_symbol].iloc[-1].open
    print(benchmark_symbol, s_p, e_p, e_p / s_p)

    show_df = show_df[start_date:].dropna(how='any', inplace=False)
    show_df['strategy_pct'] = show_df['PROPERTY_TURTLE_%d_%d_%d' %
                                      (TURTLE_POS, TURTLE_LONG_BUY_N,
                                       TURTLE_LONG_SELL_N)].pct_change()
    # show_df['benchmark_pct'] = show_df['open'].pct_change()
    show_df['benchmark_pct'] = stock_df_dict[benchmark_symbol].open.pct_change(
    )
    # print('cum_returns', emp.cum_returns(show_df.strategy_pct))
    print('max_drawdown', emp.max_drawdown(show_df.strategy_pct))
    print(
        'MDD',
        MDD(show_df['PROPERTY_TURTLE_%d_%d_%d' %
                    (TURTLE_POS, TURTLE_LONG_BUY_N, TURTLE_LONG_SELL_N)]))
    print('annual_return', emp.annual_return(show_df.strategy_pct))
    print('annual_volatility',
          emp.annual_volatility(show_df.strategy_pct, period='daily'))
    print('calmar_ratio', emp.calmar_ratio(show_df.strategy_pct))
    print('sharpe_ratio', emp.sharpe_ratio(returns=show_df.strategy_pct))
    print(
        'alpha',
        emp.alpha(returns=show_df.strategy_pct,
                  factor_returns=show_df.benchmark_pct,
                  risk_free=0.00))
    print(
        'beta',
        emp.beta(returns=show_df.strategy_pct,
                 factor_returns=show_df.benchmark_pct,
                 risk_free=0.00))
Exemplo n.º 19
0
 def getAlpha(self, period='daily', annualization=None):
     return empyrical.alpha(self.returns, self.riskFreeRate, period, annualization, beta_=None)
Exemplo n.º 20
0
def work(PARAMS):
    info('work %s' % str(PARAMS))
    stock_df_dict = None
    show_df = None
    order_df = None
    PROPERTY = None
    STRATEGY = PARAMS[0]
    POS = PARAMS[1]
    N = PARAMS[2]
    K = PARAMS[3]
    M = PARAMS[4]
    global ROTATION_LIST
    ROTATION_LIST = ROTATION_LIST

    stock_df_dict = get_stock_df_dict(N, M)
    show_df, order_df, PROPERTY = run_turtle(ROTATION_LIST, stock_df_dict, STRATEGY, POS, N, K, M)

    df = show_df.dropna(how='any', inplace=False).copy()
    df = df.loc[start_date:end_date]
    algo = df['PROPERTY'].pct_change()
    benchmark = df.open.pct_change()

    DAYS_ALL = len(df)
    DAYS_NOFULLHOLD = len(df[df['CASH'] > (df['PROPERTY'] / POS)])

    output_str = ''
    for y in range(int(start_date.split('-')[0]), int(end_date.split('-')[0]) + 1, 1):
        # info('y = %d' % y)
        y_df = df.loc['%d-01-01' % y:'%d-01-01' % (y + 1)]
        if len(y_df) == 0:
            continue
        y_algo = y_df['PROPERTY'].pct_change()
        # info(y_algo)
        y_benchmark = y_df.open.pct_change()
        # info('y_benc')
        result = '%d-%d,%.3f,%.3f,%.3f,%.3f' % (
            y, y + 1, emp.cum_returns(y_algo)[-1], emp.cum_returns(y_benchmark)[-1], emp.max_drawdown(y_algo), emp.max_drawdown(y_benchmark)
        )
        output_str += result
        output_str += ';'
    # info(output_str)

    df = order_df.copy()
    df['pro_pct'] = (df.borrow_price - df.return_price) / df.return_price
    df = df.loc[:, ['symbol', 'pro_pct']]
    df = df.groupby(by='symbol').sum()
    buy_stock_count = len(df)

    score_sr = pd.Series({
        'START': start_date,
        'END': end_date,
        'STRATEGY': STRATEGY,
        'POS': POS,
        'N': N,
        'K': K,
        'M': M,
        'ORDER': len(order_df),
        'STOCK': buy_stock_count,
        'RETURN_ALGO': emp.cum_returns(algo)[-1],
        'RETURN_BENC': emp.cum_returns(benchmark)[-1],
        'MAXDROPDOWN_ALGO': emp.max_drawdown(algo),
        'MAXDROPDOWN_BENC': emp.max_drawdown(benchmark),
        'WINRATE_ORDER': len(order_df[order_df.profit > 0]) / len(order_df[order_df.profit != 0]),
        'WINRATE_YEARLY': 0,
        'ANNUAL_RETURN': emp.annual_return(algo),
        'ANNUAL_VOLATILITY': emp.annual_volatility(algo, period='daily'),
        'CALMAR_RATIO': emp.calmar_ratio(algo),
        'SHARPE_RATIO': emp.sharpe_ratio(returns=algo),
        'ALPHA': emp.alpha(returns=algo, factor_returns=benchmark, risk_free=0.00),
        'BETA': emp.beta(returns=algo, factor_returns=benchmark, risk_free=0.00),
        'DAYS_ALL': DAYS_ALL,
        'DAYS_NOFULLHOLD': DAYS_NOFULLHOLD,
        'RET_PER_YEAR': output_str,
    })

    YEAR_COUNT = 0
    ALGO_WIN_YEAR_COUNT = 0
    df = show_df.dropna(how='any', inplace=False).copy()
    df = df.loc[start_date:end_date]
    for y in range(int(start_date.split('-')[0]), int(end_date.split('-')[0]) + 1, 1):
        y_df = df.loc['%d-01-01' % y:'%d-01-01' % (y + 1)]
        # info('y = %d' % y)
        if len(y_df) == 0:
            continue
        y_algo = y_df['PROPERTY'].pct_change()
        y_benchmark = y_df.open.pct_change()
        score_sr['RETURN_ALGO_%d' % y] = emp.cum_returns(y_algo)[-1]
        score_sr['RETURN_BENC_%d' % y] = emp.cum_returns(y_benchmark)[-1]
        YEAR_COUNT += 1
        if score_sr['RETURN_ALGO_%d' % y] > score_sr['RETURN_BENC_%d' % y]:
            ALGO_WIN_YEAR_COUNT += 1

    score_sr['WINRATE_YEARLY'] = ALGO_WIN_YEAR_COUNT / YEAR_COUNT

    return PARAMS, score_sr, order_df
Exemplo n.º 21
0
    def calculate_metrics(self):
        self.benchmark_period_returns = \
            cum_returns(self.benchmark_returns).iloc[-1]

        self.algorithm_period_returns = \
            cum_returns(self.algorithm_returns).iloc[-1]

        if not self.algorithm_returns.index.equals(
            self.benchmark_returns.index
        ):
            message = "Mismatch between benchmark_returns ({bm_count}) and \
            algorithm_returns ({algo_count}) in range {start} : {end}"
            message = message.format(
                bm_count=len(self.benchmark_returns),
                algo_count=len(self.algorithm_returns),
                start=self._start_session,
                end=self._end_session
            )
            raise Exception(message)

        self.num_trading_days = len(self.benchmark_returns)
        self.trading_day_counts = pd.stats.moments.rolling_count(
            self.algorithm_returns, self.num_trading_days)

        self.mean_algorithm_returns = \
            self.algorithm_returns.cumsum() / self.trading_day_counts

        self.benchmark_volatility = annual_volatility(self.benchmark_returns)
        self.algorithm_volatility = annual_volatility(self.algorithm_returns)

        self.treasury_period_return = choose_treasury(
            self.treasury_curves,
            self._start_session,
            self._end_session,
            self.trading_calendar,
        )
        self.sharpe = sharpe_ratio(
            self.algorithm_returns,
        )
        # The consumer currently expects a 0.0 value for sharpe in period,
        # this differs from cumulative which was np.nan.
        # When factoring out the sharpe_ratio, the different return types
        # were collapsed into `np.nan`.
        # TODO: Either fix consumer to accept `np.nan` or make the
        # `sharpe_ratio` return type configurable.
        # In the meantime, convert nan values to 0.0
        if pd.isnull(self.sharpe):
            self.sharpe = 0.0
        self.downside_risk = downside_risk(
            self.algorithm_returns
        )
        self.sortino = sortino_ratio(
            self.algorithm_returns,
            _downside_risk=self.downside_risk
        )
        self.information = information_ratio(
            self.algorithm_returns,
            self.benchmark_returns
        )
        self.beta = beta(
            self.algorithm_returns,
            self.benchmark_returns
        )
        self.alpha = alpha(
            self.algorithm_returns,
            self.benchmark_returns,
            _beta=self.beta
        )
        self.excess_return = self.algorithm_period_returns - \
            self.treasury_period_return
        self.max_drawdown = max_drawdown(self.algorithm_returns)
        self.max_leverage = self.calculate_max_leverage()
    # 画出收益曲线图
    draw_return_rate_line(perf)
    return_list = perf['returns']
    # 计算年化收益率
    ann_return = annual_return(return_list)
    # 计算累计收益率
    cum_return_list = cum_returns(return_list)
    # 计算sharp ratio
    sharp = sharpe_ratio(return_list)
    # 最大回撤
    max_drawdown_ratio = max_drawdown(return_list)
    print("年化收益率 = {:.2%}, 累计收益率 = {:.2%}, 最大回撤 = {:.2%}, 夏普比率 = {:.2f} ".format
          (ann_return, cum_return_list[-1], max_drawdown_ratio, sharp))

    returns = pd.Series(
        index=pd.date_range('2017-03-10', '2017-03-19'),
        data=(-0.012143, 0.045350, 0.030957, 0.004902, 0.002341, -0.02103, 0.00148, 0.004820, -0.00023, 0.01201)
    )
    benchmark_returns = pd.Series(
        index=pd.date_range('2017-03-10', '2017-03-19'),
        data=(-0.031940, 0.025350, -0.020957, -0.000902, 0.007341, -0.01103, 0.00248, 0.008820, -0.00123, 0.01091)
    )
    alpha_return = alpha(returns=returns, factor_returns=benchmark_returns, risk_free=0.01)
    beta_return = beta(returns=returns, factor_returns=benchmark_returns, risk_free=0.01)
    print("alpha_return", alpha_return)
    print("\nbeta_return", beta_return)




Exemplo n.º 23
0
def test():
    # 构造测试数据
    returns = pd.Series(
        index = pd.date_range("2017-03-10", "2017-03-19"),
        data = (-0.012143, 0.045350, 0.030957, 0.004902, 0.002341, -0.02103, 0.00148, 0.004820, -0.00023, 0.01201))
    print(returns)
    benchmark_returns = pd.Series(
        index = pd.date_range("2017-03-10", "2017-03-19"),
        data = ( -0.031940, 0.025350, -0.020957, -0.000902, 0.007341, -0.01103, 0.00248, 0.008820, -0.00123, 0.01091))
    print(benchmark_returns)
    # 计算累积收益率
    creturns = ey.cum_returns(returns)
    print("累积收益率\n", creturns)
    risk = riskAnalyzer(returns, benchmark_returns, riskFreeRate = 0.01)
    results = risk.run()
    print(results)
    # 直接调用empyrical试试
    alpha = ey.alpha(returns = returns, factor_returns = benchmark_returns, risk_free = 0.01)
    calmar = ey.calmar_ratio(returns)
    print(alpha, calmar)
    # 自己计算阿尔法值
    annual_return = ey.annual_return(returns)
    annual_bench = ey.annual_return(benchmark_returns)
    print(annual_return, annual_bench)
    alpha2 = (annual_return - 0.01) - results["贝塔"]*(annual_bench - 0.01)
    print(alpha2)
    # 自己计算阿尔法贝塔
    def get_return(code, startdate, endate):
        df = ts.get_k_data(code, ktype = "D", autype = "qfq", start = startdate, end = endate)
        p1 = np.array(df.close[1:])
        p0 = np.array(df.close[:-1])
        logret = np.log(p1/p0)
        rate = pd.DataFrame()
        rate[code] = logret
        rate.index = df["date"][1:]
        return rate
    def alpha_beta(code, startdate, endate):
        mkt_ret = get_return("sh", startdate, endate)
        stock_ret = get_return(code, startdate, endate)
        df = pd.merge(mkt_ret, stock_ret, left_index = True, right_index = True)
        x = df.iloc[:, 0]
        y = df.iloc[:, 1]
        beta, alpha, r_value, p_value, std_err = stats.linregress(x, y)
        return (alpha, beta)
    def stocks_alpha_beta(stocks, startdate, endate):
        df = pd.DataFrame()
        alpha = []
        beta = []
        for code in stocks.values():
            a, b = alpha_beta(code, startdate, endate)
            alpha.append(float("%.4f"%a))
            beta.append(float("%.4f"%b))
        df["alpha"] = alpha
        df["beta"] = beta
        df.index = stocks.keys()
        return df
        
    startdate = "2017-01-01"
    endate = "2018-11-09"
    stocks={'中国平安':'601318','格力电器':'000651','招商银行':'600036','恒生电子':'600570','中信证券':'600030','贵州茅台':'600519'}
    results = stocks_alpha_beta(stocks, startdate, endate)
    print("自己计算结果")
    print(results)
    
    # 用empyrical计算
    def stocks_alpha_beta2(stocks, startdate, endate):
        df = pd.DataFrame()
        alpha = []
        beta = []
        for code in stocks.values():
            a, b = empyrical_alpha_beta(code, startdate, endate)
            alpha.append(float("%.4f"%a))
            beta.append(float("%.4f"%b))
        df["alpha"] = alpha
        df["beta"] = beta
        df.index = stocks.keys()
        return df
    def empyrical_alpha_beta(code, startdate, endate):
        mkt_ret = get_return("sh", startdate, endate)
        stock_ret = get_return(code, startdate, endate)
        alpha, beta = ey.alpha_beta(returns = stock_ret, factor_returns = mkt_ret,  annualization = 1)
        return (alpha, beta)
        
    results2 = stocks_alpha_beta2(stocks, startdate, endate)
    print("empyrical计算结果")
    print(results2)
    print(results2["alpha"]/results["alpha"])
Exemplo n.º 24
0
 def test_alpha(self, returns, benchmark, expected):
     assert_almost_equal(
         empyrical.alpha(returns, benchmark),
         expected,
         DECIMAL_PLACES)