Esempio n. 1
0
 def test_beta(self):
     res_a = empyrical.beta(ret['a'], benchmark_rets['a'])
     res_b = empyrical.beta(ret['b'], benchmark_rets['b'])
     res_c = empyrical.beta(ret['c'], benchmark_rets['c'])
     assert isclose(ret['a'].vbt.returns.beta(benchmark_rets['a']), res_a)
     pd.testing.assert_series_equal(
         ret.vbt.returns.beta(benchmark_rets),
         pd.Series([res_a, res_b, res_c], index=ret.columns))
Esempio n. 2
0
 def test_beta(self):
     res_a = empyrical.beta(ret['a'], benchmark_rets['a'])
     res_b = empyrical.beta(ret['b'], benchmark_rets['b'])
     res_c = empyrical.beta(ret['c'], benchmark_rets['c'])
     assert isclose(ret['a'].vbt.returns.beta(benchmark_rets['a']), res_a)
     pd.testing.assert_series_equal(
         ret.vbt.returns.beta(benchmark_rets),
         pd.Series([res_a, res_b, res_c], index=ret.columns).rename('beta'))
     pd.testing.assert_series_equal(
         ret.vbt.returns.rolling_beta(ret.shape[0], benchmark_rets,
                                      minp=1).iloc[-1],
         pd.Series([res_a, res_b, res_c],
                   index=ret.columns).rename(ret.index[-1]))
Esempio n. 3
0
def comp_analysis(start_date='2017-07-01'):
    '''
    分析区间内基金公司收益率、波动率、beta与仓位变化
    '''
    comp_ret = pd.read_excel('%s/comp_ret.xlsx' % (const.FOF_DIR), index_col=0)
    comp_pos = pd.read_excel('%s/comp_position.xlsx' % (const.FOF_DIR),
                             index_col=0)
    wdf = pd.read_csv('%s/881001.WI.csv' % (const.INDEX_DIR), index_col=1)
    wseries = wdf.pct_change()[wdf.index >= start_date]['close']
    wseries.index = pd.to_datetime(wseries.index)
    df = pd.DataFrame(index=comp_ret.columns,
                      columns=['ret', 'vol', 'beta', 'pos'])
    for c in df.index:
        series = comp_ret[c]
        series = series[series.index >= start_date]
        df.loc[c, 'ret'] = (1 + series).cumprod()[-1] - 1
        df.loc[c, 'vol'] = empyrical.annual_volatility(series)
        wseries = wseries[(wseries.index >= series.index[0])
                          & (wseries.index <= series.index[-1])]
        df.loc[c, 'beta'] = empyrical.beta(series, wseries)
        if comp_pos[c].shape[0] > 1 and comp_pos[c][-2] != 0:
            df.loc[c, 'pos'] = (comp_pos[c][-1] -
                                comp_pos[c][-2]) / comp_pos[c][-2]
    df = df.sort_values('ret', ascending=False)
    df = df.dropna()
    df.to_excel('%s/comp_analysis.xlsx' % (const.FOF_DIR))
Esempio n. 4
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()
    def evaluation(self):
        ap.sound(f'entry: create_df')

        mdd = empyrical.max_drawdown(self.df.eac_stgy_rt)
        stgy_ret_an = empyrical.annual_return(self.df.eac_stgy_rt, annualization=self.cls.annualization)
        bcmk_ret_an = empyrical.annual_return(self.df.eac_bcmk_rt, annualization=self.cls.annualization)
        stgy_vlt_an = empyrical.annual_volatility(self.df.eac_stgy_rt, annualization=self.cls.annualization)
        bcmk_vlt_an = empyrical.annual_volatility(self.df.eac_bcmk_rt, annualization=self.cls.annualization)
        calmar = empyrical.calmar_ratio(self.df.eac_stgy_rt, annualization=self.cls.annualization)
        omega = empyrical.omega_ratio(self.df.eac_stgy_rt, risk_free=self.cls.rf, annualization=self.cls.annualization)
        sharpe = qp.sharpe_ratio(stgy_ret_an, self.df.cum_stgy_rt, self.cls.rf)
        sortino = empyrical.sortino_ratio(self.df.eac_stgy_rt, annualization=self.cls.annualization)
        dsrk = empyrical.downside_risk(self.df.eac_stgy_rt, annualization=self.cls.annualization)
        information = empyrical.information_ratio(self.df.eac_stgy_rt, factor_returns=self.df.eac_bcmk_rt)
        beta = empyrical.beta(self.df.eac_stgy_rt, factor_returns=self.df.eac_bcmk_rt, risk_free=self.cls.rf)
        tail_rt = empyrical.tail_ratio(self.df.eac_stgy_rt)
        alpha = qp.alpha_ratio(stgy_ret_an, bcmk_ret_an, self.cls.rf, beta)

        stgy_ttrt_rt = (self.cls.yd.ttas[-1] - self.cls.yd.ttas[0]) / self.cls.yd.ttas[0]
        bcmk_ttrt_rt = (self.cls.pc.close[-1] - self.cls.pc.close[0]) / self.cls.pc.close[0]
        car_rt = stgy_ttrt_rt - bcmk_ttrt_rt
        car_rt_an = stgy_ret_an - bcmk_ret_an

        self.cls.df_output = pd.DataFrame(
            {'sgty_ttrt_rt': [stgy_ttrt_rt], 'bcmk_ttrt_rt': [bcmk_ttrt_rt], 'car_rt': [car_rt],
             'stgy_ret_an': [stgy_ret_an], 'bcmk_ret_an': [bcmk_ret_an], 'car_rt_an': [car_rt_an],
             'stgy_vlt_an': [stgy_vlt_an], 'bcmk_vlt_an': [bcmk_vlt_an], 'mdd': [mdd],
             'sharpe': [sharpe], 'alpha': [alpha], 'beta': [beta], 'information': [information],
             'tail_rt': [tail_rt], 'calmar': [calmar], 'omega': [omega], 'sortino': [sortino], 'dsrk': [dsrk]})
        print(f'feedback: \n{self.cls.df_output.T}')
Esempio n. 6
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
Esempio n. 7
0
def beta(close, benchmark_close, risk_free=0.0):
    try:
        rets = daily_returns(close)
        benchmark_rets = daily_returns(benchmark_close)
        beta_data = empyrical.beta(rets, benchmark_rets, risk_free=risk_free)
        return beta_data
    except Exception as e:
        raise (e)
Esempio n. 8
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()
Esempio n. 9
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)
Esempio n. 10
0
def beta(daily_returns, benchmark_daily_returns, risk_free=0.0):
    """Beta"""
    try:
        logger.info('Calculating Beta...')
        check_inputs_length(daily_returns, benchmark_daily_returns)
        beta_data = empyrical.beta(daily_returns,
                                   benchmark_daily_returns,
                                   risk_free=risk_free)
        return beta_data
    except Exception as exception:
        raise exception
Esempio n. 11
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
Esempio n. 12
0
    def test_beta(self, returns, benchmark, expected):
        observed = empyrical.beta(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, slope)
Esempio n. 13
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)
Esempio n. 14
0
def rolling_beta(returns, factor_returns,
                 rolling_window=APPROX_BDAYS_PER_MONTH * 6):
    """
    Determines the rolling beta of a strategy.

    Parameters
    ----------
    returns : pd.Series
        Daily returns of the strategy, noncumulative.
         - See full explanation in tears.create_full_tear_sheet.
    factor_returns : pd.Series or pd.DataFrame
        Daily noncumulative returns of the benchmark factor to which betas are
        computed. Usually a benchmark such as market returns.
         - If DataFrame is passed, computes rolling beta for each column.
         - This is in the same style as returns.
    rolling_window : int, optional
        The size of the rolling window, in days, over which to compute
        beta (default 6 months).

    Returns
    -------
    pd.Series
        Rolling beta.

    Note
    -----
    See https://en.wikipedia.org/wiki/Beta_(finance) for more details.
    """

    if factor_returns.ndim > 1:
        # Apply column-wise
        return factor_returns.apply(partial(rolling_beta, returns),
                                    rolling_window=rolling_window)
    else:
        out = pd.Series(index=returns.index)
        for beg, end in zip(returns.index[0:-rolling_window],
                            returns.index[rolling_window:]):
            out.loc[end] = ep.beta(
                returns.loc[beg:end],
                factor_returns.loc[beg:end])

        return out
Esempio n. 15
0
def rolling_beta(returns,
                 factor_returns,
                 rolling_window=APPROX_BDAYS_PER_MONTH * 6):
    """
    Determines the rolling beta of a strategy.

    Parameters
    ----------
    returns : pd.Series
        Daily returns of the strategy, noncumulative.
         - See full explanation in tears.create_full_tear_sheet.
    factor_returns : pd.Series or pd.DataFrame
        Daily noncumulative returns of the benchmark factor to which betas are
        computed. Usually a benchmark such as market returns.
         - If DataFrame is passed, computes rolling beta for each column.
         - This is in the same style as returns.
    rolling_window : int, optional
        The size of the rolling window, in days, over which to compute
        beta (default 6 months).

    Returns
    -------
    pd.Series
        Rolling beta.

    Note
    -----
    See https://en.wikipedia.org/wiki/Beta_(finance) for more details.
    """

    if factor_returns.ndim > 1:
        # Apply column-wise
        return factor_returns.apply(partial(rolling_beta, returns),
                                    rolling_window=rolling_window)
    else:
        out = pd.Series(index=returns.index)
        for beg, end in zip(returns.index[0:-rolling_window],
                            returns.index[rolling_window:]):
            out.loc[end] = ep.beta(returns.loc[beg:end],
                                   factor_returns.loc[beg:end])

        return out
Esempio n. 16
0
def beta(returns, factor_returns):
    """Calculates beta.

    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
        Beta.
    """

    return empyrical.beta(returns, factor_returns)
Esempio n. 17
0
def beta(returns, factor_returns):
    """
    Calculates beta.

    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
        Beta.
    """

    return empyrical.beta(returns, factor_returns)
Esempio n. 18
0
    def compute(self, today, assets, out, x):
        ################
        self.i = self.i + 1
        if self.i % 21 == 1:
            nav = pd.DataFrame(x)
            y = nav.pct_change(self.time)
            ben_nav = pd.DataFrame(x[:, assets == self.index_sid])
            valid_regression_r1 = ben_nav.pct_change(
                self.time) - 0.025 * 5.0 / 25
            x1 = valid_regression_r1.loc[y.index]
            wbeta = pd.Series(np.zeros(y.shape[1])).astype(float)

            for j in range(0, y.shape[1]):
                temp = y.iloc[:, j]
                if np.isnan(temp[self.time:]).any():
                    wbeta[y.columns[j]] = np.nan
                else:
                    yy = temp[~temp.isnull()]
                    xx = x1.iloc[yy.index, 0]
                    wbeta[y.columns[j]] = beta(yy, xx, risk_free=self.rf)
            out[:] = wbeta
        else:
            out[:] = np.nan
bm_returns = benchmark_rets.daily_performance['returns']
bm_positions = benchmark_rets.pyfolio_positions
bm_transactions = benchmark_rets.pyfolio_transactions

# ### Use Algo from Leverage Lecture
# Use same algo as in the Leverage Lecture!
bt = get_backtest('5986b969dbab994fa4264696')
bt_returns = bt.daily_performance['returns']
bt_positions = bt.pyfolio_positions
bt_transactions = bt.pyfolio_transactions

bt_returns.plot()
plt.savefig(PATH + 'rets.png', dpi=300)
plt.close()

print(empyrical.beta(bt_returns, bm_returns))

# # PyFolio Plots
benchmark_rets = bm_returns

# Cumulative Returns
plt.subplot(2, 1, 1)
pf.plotting.plot_rolling_returns(bt_returns, benchmark_rets)

# Daily, Non-Cumulative Returns
plt.subplot(2, 1, 2)
pf.plotting.plot_returns(bt_returns)
plt.tight_layout()
plt.savefig(PATH + 'daily_and_cum_rets.png', dpi=300)
plt.close()
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
Esempio n. 21
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
Esempio n. 22
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))
Esempio n. 23
0
def vizResults(slippageAdjustedReturn, returnStream, factorReturn, plotting = False):
    ##ENSURE EQUAL LENGTH
    factorReturn = factorReturn[returnStream.index[0]:] ##IF FACTOR DOES NOT START AT SAME SPOT CAN CREATE VERY SKEWED RESULTS

    ##CALCULATE SHARPE WITH SLIPPAGE
    sharpeDiffSlippage = empyrical.sharpe_ratio(slippageAdjustedReturn) - empyrical.sharpe_ratio(factorReturn)
    relativeSharpeSlippage = sharpeDiffSlippage / empyrical.sharpe_ratio(factorReturn) * (empyrical.sharpe_ratio(factorReturn)/abs(empyrical.sharpe_ratio(factorReturn)))

    alpha, beta = empyrical.alpha_beta(returnStream, factorReturn)
    alphaSlippage, betaSlippage = empyrical.alpha_beta(slippageAdjustedReturn, factorReturn)
    metrics = {"SHARPE": empyrical.sharpe_ratio(returnStream),
               "SHARPE SLIPPAGE":empyrical.sharpe_ratio(slippageAdjustedReturn),
               "STABILITY": empyrical.stability_of_timeseries(returnStream),
               "ALPHA":alpha,
               "ALPHA SLIPPAGE":alphaSlippage,
               "BETA":abs(beta),
               "ANNUALIZED RETURN": empyrical.annual_return(returnStream)[0],
               "ACTIVITY": np.count_nonzero(returnStream)/float(len(returnStream)),
               "TREYNOR": ((empyrical.annual_return(returnStream.values)[0] - empyrical.annual_return(factorReturn.values)[0]) \
                           / abs(empyrical.beta(returnStream, factorReturn))),
               "RAW BETA":abs(empyrical.alpha_beta(returnStream.apply(lambda x:applyBinary(x), axis=0), factorReturn.apply(lambda x:applyBinary(x), axis=0))[1]),
               "SHARPE DIFFERENCE": empyrical.sharpe_ratio(returnStream) - empyrical.sharpe_ratio(factorReturn),
               "RELATIVE SHARPE": (empyrical.sharpe_ratio(returnStream) - empyrical.sharpe_ratio(factorReturn))/empyrical.sharpe_ratio(factorReturn) * (empyrical.sharpe_ratio(factorReturn)/abs(empyrical.sharpe_ratio(factorReturn))),
               "FACTOR SHARPE": empyrical.sharpe_ratio(factorReturn),
               "SHARPE DIFFERENCE SLIPPAGE":sharpeDiffSlippage,
               "RELATIVE SHARPE SLIPPAGE":relativeSharpeSlippage,
              }

    metrics["FACTOR PROFITABILITY"] = len((factorReturn.values)[factorReturn.values > 0])/len(factorReturn.values)
    metrics["PROFITABILITY"] = len((returnStream.values)[returnStream.values > 0])/len(returnStream.values)

    metrics["PROFITABILITY DIFFERENCE"] = metrics["PROFITABILITY"] - metrics["FACTOR PROFITABILITY"] 

    metrics["PROFITABILITY SLIPPAGE"] = len((slippageAdjustedReturn.values)[slippageAdjustedReturn.values > 0])/len(slippageAdjustedReturn.values)
    
    metrics["ACTIVE PROFITABILITY"] = len((returnStream.values)[returnStream.values > 0])/len((returnStream.values)[returnStream.values != 0])
    metrics["ACTIVE PROFITABILITY SLIPPAGE"] = len((slippageAdjustedReturn.values)[slippageAdjustedReturn.values > 0])/len((slippageAdjustedReturn.values)[slippageAdjustedReturn.values != 0])

    metrics["TOTAL DAYS SEEN"] = len(returnStream)
    metrics["SHARPE SLIPPAGE DECAY"] = metrics["SHARPE DIFFERENCE SLIPPAGE"] - metrics["SHARPE DIFFERENCE"]
    ##MEASURES BINARY STABILITY OF PREDICTIONS
    metrics["EXTREME STABILITY ROLLING 600"] = (returnStream.rolling(600, min_periods=600).apply(lambda x:empyrical.stability_of_timeseries(applyBinarySkipZero(x)) * (-1 if x[-1] - x[0] < 0 else 1)).dropna()).min().values[0]
    metrics["EXTREME STABILITY"] = empyrical.stability_of_timeseries(applyBinarySkipZero(returnStream.values))
    rollingPeriod = 252


    

    rollingSharpe = returnStream.rolling(rollingPeriod, min_periods=rollingPeriod).apply(lambda x:empyrical.sharpe_ratio(x)).dropna()
    rollingSharpe.columns = ["252 Day Rolling Sharpe"]
    rollingSharpeFactor = factorReturn.rolling(rollingPeriod, min_periods=rollingPeriod).apply(lambda x:empyrical.sharpe_ratio(x)).dropna()
    rollingSharpe = rollingSharpe.join(rollingSharpeFactor)
    rollingSharpe.columns = ["252 Day Rolling Sharpe Algo", "252 Day Rolling Sharpe Factor"]
    
    if len(rollingSharpe["252 Day Rolling Sharpe Algo"].values) > 50:

        diffSharpe = pd.DataFrame(rollingSharpe.apply(lambda x: x[0] - x[1], axis=1), columns=["Sharpe Difference"])
        metrics["SHARPE DIFFERENCE MIN"] = np.percentile(diffSharpe["Sharpe Difference"].values, 1)
        metrics["SHARPE DIFFERENCE AVERAGE"] = np.percentile(diffSharpe["Sharpe Difference"].values, 50)
        difVals = diffSharpe["Sharpe Difference"].values
        metrics["SHARPE DIFFERENCE GREATER THAN 0"] = len(difVals[np.where(difVals > 0)])/float(len(difVals))
        metrics["25TH PERCENTILE SHARPE DIFFERENCE"] = np.percentile(diffSharpe["Sharpe Difference"].values, 25)
        ###

        relDiffSharpe = pd.DataFrame(rollingSharpe.apply(lambda x: (x[0] - x[1])/x[1] * (x[1]/abs(x[1])), axis=1), columns=["Sharpe Difference"])
        metrics["RELATIVE SHARPE DIFFERENCE MIN"] = np.percentile(relDiffSharpe["Sharpe Difference"].values, 1)
        metrics["RELATIVE SHARPE DIFFERENCE AVERAGE"] = np.percentile(relDiffSharpe["Sharpe Difference"].values, 50)
        relDifVals = relDiffSharpe["Sharpe Difference"].values
        metrics["RELATIVE SHARPE DIFFERENCE GREATER THAN 0"] = len(relDifVals[np.where(relDifVals > 0)])/float(len(relDifVals))
        metrics["25TH PERCENTILE RELATIVE SHARPE DIFFERENCE"] = np.percentile(relDiffSharpe["Sharpe Difference"].values, 25)
        ###
    
        metrics["ROLLING SHARPE BETA"] = abs(empyrical.beta(rollingSharpe["252 Day Rolling Sharpe Algo"], rollingSharpe["252 Day Rolling Sharpe Factor"]))
        metrics["25TH PERCENTILE SHARPE"] = np.percentile(rollingSharpe["252 Day Rolling Sharpe Algo"].values, 25)
        metrics["MIN ROLLING SHARPE"] = np.percentile(rollingSharpe["252 Day Rolling Sharpe Algo"].values, 1)

        rollingDownside = returnStream.rolling(rollingPeriod, min_periods=rollingPeriod).apply(lambda x:empyrical.max_drawdown(x)).dropna()
        rollingDownside.columns = ["252 Day Rolling Downside"]
        rollingDownsideFactor = factorReturn.rolling(rollingPeriod, min_periods=rollingPeriod).apply(lambda x:empyrical.max_drawdown(x)).dropna()
        rollingDownside = rollingDownside.join(rollingDownsideFactor)
        rollingDownside.columns = ["252 Day Rolling Downside Algo", "252 Day Rolling Downside Factor"]

        metrics["ROLLING SHARPE STABILITY"] = abs(stats.linregress(np.arange(len(rollingSharpe["252 Day Rolling Sharpe Algo"].values)),
                                rollingSharpe["252 Day Rolling Sharpe Algo"].values).rvalue)
    

        rollingReturn = returnStream.rolling(rollingPeriod, min_periods=rollingPeriod).apply(lambda x:empyrical.cum_returns(x)[-1]).dropna()
        rollingReturn.columns = ["ROLLING RETURN"]
        metrics["SMART INFORMATION RATIO"] = (np.percentile(rollingReturn["ROLLING RETURN"].values, 25) - empyrical.annual_return(factorReturn.values[0]))\
                        / returnStream.values.std()

        metrics["ROLLING SHARPE ERROR"] = rollingSharpe["252 Day Rolling Sharpe Algo"].std()
        metrics["ONE STD SHARPE"] = empyrical.sharpe_ratio(slippageAdjustedReturn) - metrics["ROLLING SHARPE ERROR"]
        if plotting == True:
            import matplotlib.pyplot as plt 
            rollingSharpe.plot()
            rollingDownside.plot()

    rollingPeriod = 90


    rollingSharpe = returnStream.rolling(rollingPeriod, min_periods=rollingPeriod).apply(lambda x:empyrical.sharpe_ratio(x)).dropna()
    rollingSharpe.columns = ["90 Day Rolling Sharpe"]

    if len(rollingSharpe["90 Day Rolling Sharpe"].values) > 50:

        metrics["25TH PERCENTILE SHARPE 90"] = np.percentile(rollingSharpe["90 Day Rolling Sharpe"].values, 25)
        metrics["MIN ROLLING SHARPE 90"] = np.percentile(rollingSharpe["90 Day Rolling Sharpe"].values, 1)
        metrics["ROLLING SHARPE ERROR 90"] = rollingSharpe["90 Day Rolling Sharpe"].std()
        metrics["SHARPE TO MIN RATIO 90"] = metrics["SHARPE"] / abs(metrics["MIN ROLLING SHARPE 90"])
        
        metrics["MIN PROFITABILITY 90"] = np.percentile(returnStream.rolling(rollingPeriod, min_periods=rollingPeriod).apply(lambda x:len((x)[x > 0])/len(x)).dropna().values, 1)
        metrics["PROFITABILITY DROP 90"] = metrics["PROFITABILITY"] - metrics["MIN PROFITABILITY 90"]
        metrics["25TH PROFITABILITY 90"] = np.percentile(returnStream.rolling(rollingPeriod, min_periods=rollingPeriod).apply(lambda x:len((x)[x > 0])/len(x)).dropna().values, 25)
        
        metrics["MIN FACTOR PROFITABILITY 90"] = np.percentile(factorReturn.rolling(rollingPeriod, min_periods=rollingPeriod).apply(lambda x:len((x)[x > 0])/len(x)).dropna().values, 1)
        metrics["MIN PROFITABILITY DIFFERENCE 90"] = metrics["MIN PROFITABILITY 90"] - metrics["MIN FACTOR PROFITABILITY 90"] 

    rollingPeriod = 45


    rollingSharpe = returnStream.rolling(rollingPeriod, min_periods=rollingPeriod).apply(lambda x:empyrical.sharpe_ratio(x)).dropna()
    rollingSharpe.columns = ["45 Day Rolling Sharpe"]

    if len(rollingSharpe["45 Day Rolling Sharpe"].values) > 50:

        metrics["25TH PERCENTILE SHARPE 45"] = np.percentile(rollingSharpe["45 Day Rolling Sharpe"].values, 25)
        metrics["MIN ROLLING SHARPE 45"] = np.percentile(rollingSharpe["45 Day Rolling Sharpe"].values, 1)
        metrics["ROLLING SHARPE ERROR 45"] = rollingSharpe["45 Day Rolling Sharpe"].std()
        metrics["SHARPE TO MIN RATIO 45"] = metrics["SHARPE"] / abs(metrics["MIN ROLLING SHARPE 45"])
        
        metrics["MIN PROFITABILITY 45"] = np.percentile(returnStream.rolling(rollingPeriod, min_periods=rollingPeriod).apply(lambda x:len((x)[x > 0])/len(x)).dropna().values, 1)
        metrics["PROFITABILITY DROP 45"] = metrics["PROFITABILITY"] - metrics["MIN PROFITABILITY 45"]
        metrics["25TH PROFITABILITY 45"] = np.percentile(returnStream.rolling(rollingPeriod, min_periods=rollingPeriod).apply(lambda x:len((x)[x > 0])/len(x)).dropna().values, 25)

        metrics["MIN FACTOR PROFITABILITY 45"] = np.percentile(factorReturn.rolling(rollingPeriod, min_periods=rollingPeriod).apply(lambda x:len((x)[x > 0])/len(x)).dropna().values, 1)
        metrics["MIN PROFITABILITY DIFFERENCE 45"] = metrics["MIN PROFITABILITY 45"] - metrics["MIN FACTOR PROFITABILITY 45"] 

    returns = returnStream.apply(lambda x:empyrical.cum_returns(x))
    returns.columns = ["algo"]
    factorReturn = factorReturn.apply(lambda x:empyrical.cum_returns(x))
    returns = returns.join(factorReturn)
    returns.columns = ["Algo Return", "Factor Return"]


        ##FORCE SHOW
    if plotting == True:
        import matplotlib.pyplot as plt 
        returns.plot()
        plt.show()
    return metrics
    # 画出收益曲线图
    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)




Esempio n. 25
0
#   ACTUAL ASSET'S BACKTEST
bt = get_backtest("hashcode")
bt_returns = bt.daily_performance['returns']
bt_positions = bt.pyfolio_positions
bt_transactions = bt.pyfolio_transactions
#   BENCHMARK BACKTEST TOO
benchmark = get_backtest("another hashcode")
bn_returns = benchmark.daily_performance['returns']
bn_positions = benchmark.pyfolio_positions
bn_transactions = benchmark.pyfolio_transactions

# CALC'ING THE SHARPE RATIO
bt_sr = empyrical.sharpe_ratio(bt_returns)
bn_sr = empyrical.sharpe_ratio(bn_returns)
# CALC'ING BETA
beta = empyrical.beta(bt_returns, bn_returns)

#   PLOTTING WITH PyFolio (ALL TYPES OF PLOTS AVAILABLE - pf.plotting.type_of_plot())
# CUMULATIVE RETURNS
plt.subplot(2, 1, 1)
pf.plotting.plot_rolling_returns(bt_returns, bn_returns)
# DAILY (NON-CUMULATIVE) RETURNS
plt.subplot(2, 1, 2)
pf.plotting.plot_returns(bt_returns)
plt.tight_layout()

#
#   ACTUAL ALGORITHM TO BE BACKTESTED (WHILE THE CODE ABOVE DOES ANALYSIS, USING THE BACKTESTING RESULTS)
#   COMES WITH initialize() & shit

#
Esempio n. 26
0
def beta(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.beta(portfolio_daily_returns, benchmark_returns)
Esempio n. 27
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()
Esempio n. 28
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
Esempio n. 29
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
Esempio n. 30
0
def treynor_ratio_annualised(excess_returns, index_excess_returns):
    _beta = ep.beta(excess_returns, index_excess_returns)
    return 252 * excess_returns.mean() / _beta

# Get benchmark returns
benchmark_rets = get_backtest('5986c511c94d014fc81acf7b')
bm_returns = benchmark_rets.daily_performance['returns']
bm_positions = benchmark_rets.pyfolio_positions
bm_transactions = benchmark_rets.pyfolio_transactions
# ### Use Algo from Leverage Lecture
# Use same algo as in the Leverage Lecture!
bt = get_backtest('5986b969dbab994fa4264696')
bt_returns = bt.daily_performance['returns']
bt_positions = bt.pyfolio_positions
bt_transactions = bt.pyfolio_transactions
bt_returns.plot()
# In[46]:
empyrical.beta(bt_returns, bm_returns)
# # PyFolio Plots
benchmark_rets = bm_returns
# Cumulative Returns
plt.subplot(2, 1, 1)
pf.plotting.plot_rolling_returns(bt_returns, benchmark_rets)
# Daily, Non-Cumulative Returns
plt.subplot(2, 1, 2)
pf.plotting.plot_returns(bt_returns)
plt.tight_layout()
# In[49]:
fig = plt.figure(1)
plt.subplot(1, 3, 1)
pf.plot_annual_returns(bt_returns)
plt.subplot(1, 3, 2)
pf.plot_monthly_returns_dist(bt_returns)
Esempio n. 32
0
 def getBeta(self):
     return empyrical.beta(self.returns, self.riskFreeRate)
Esempio n. 33
0
# Process the Benchmark Results to Normalize the data and have a comparison
benchmark = get_backtest('insert benchmark hash')
benchmark_returns = benchmark.daily_performance['returns']
benchmark_positions = benchmark.pyfolio_positions
benchmark_transactions = benchmark.pyfolio_transactions

##################################
#          Sharpe Ratio          #
#   for backtest and benchmark   #
#         Combined Beta          #
##################################
backtest_sharpe = empyrical.sharpe_ratio(backtest_returns)
benchmark_sharpe = empyrical.sharpe_ratio(benchmark_returns)

combined_beta = empyrical.beta(backtest_returns, benchmark_returns)

############################
#         Round Trip       #
#         Tear Sheet       #
#      right = positive    #
#      left = negative     #
############################
tear_sheet = pf.create_round_trip_tear_sheet(backtest_returns,
                                             backtest_positions,
                                             backtest_transactions)

# Cumulative Returns
plt.subplot(2, 1, 1)
pf.plotting.plot_rolling_returns(backtest_returns, benchmark_returns)
Esempio n. 34
0
    def runModelsChunksSkipMP(self, dataOfInterest, daysToCheck = None):
        xVals, yVals, yIndex, xToday = self.walkForward.generateWindows(dataOfInterest)
        mpEngine = mp.get_context('fork')
        with mpEngine.Manager() as manager:
            returnDict = manager.dict()
            
            identifiersToCheck = []
            
            for i in range(len(xVals) - 44): ##44 is lag...should not overlap with any other predictions or will ruin validity of walkforward optimization
                if i < 600:
                    ##MIN TRAINING
                    continue
                identifiersToCheck.append(str(i))
                
            if daysToCheck is not None:
                identifiersToCheck = identifiersToCheck[-daysToCheck:]


            ##FIRST CHECK FIRST 500 IDENTIFIERS AND THEN IF GOOD CONTINUE
            

            identifierWindows = [identifiersToCheck[:252], identifiersToCheck[252:600], identifiersToCheck[600:900], identifiersToCheck[900:1200], identifiersToCheck[1200:]] ##EXACTLY TWO YEARS
            returnStream = None
            factorReturn = None
            predictions = None
            slippageAdjustedReturn = None
            shortSeen = 0
            for clippedIdentifiers in identifierWindows:
                
                splitIdentifiers = np.array_split(np.array(clippedIdentifiers), 16)
                
                
                runningP = []
                k = 0
                for identifiers in splitIdentifiers:
                    p = mpEngine.Process(target=endToEnd.runDayChunking, args=(self, xVals, yVals, identifiers, returnDict,k))
                    p.start()
                    runningP.append(p)
                    
                    k += 1
                    

                while len(runningP) > 0:
                    newP = []
                    for p in runningP:
                        if p.is_alive() == True:
                            newP.append(p)
                        else:
                            p.join()
                    runningP = newP
                    
                
                preds = []
                actuals = []
                days = []
                for i in clippedIdentifiers:
                    preds.append(returnDict[i])
                    actuals.append(yVals[int(i) + 44])
                    days.append(yIndex[int(i) + 44])

                loss = log_loss(np.array(endToEnd.transformTargetArr(np.array(actuals), self.threshold)), np.array(preds))
                roc_auc = roc_auc_score(np.array(endToEnd.transformTargetArr(np.array(actuals), self.threshold)), np.array(preds))
                accuracy = accuracy_score(np.array(endToEnd.transformTargetArr(np.array(actuals), self.threshold)), np.array(preds).round())
                print(loss, roc_auc, accuracy)
                ##CREATE ACCURATE BLENDING ACROSS DAYS
                predsTable = pd.DataFrame(preds, index=days, columns=["Predictions"])
                i = 1
                tablesToJoin = []
                while i < self.walkForward.predictionPeriod:
                    thisTable = predsTable.shift(i)
                    thisTable.columns = ["Predictions_" + str(i)]
                    tablesToJoin.append(thisTable)
                    i += 1
                predsTable = predsTable.join(tablesToJoin)
                
                transformedPreds = pd.DataFrame(predsTable.apply(lambda x:computePosition(x), axis=1), columns=["Predictions"]).dropna()
                dailyFactorReturn = getDailyFactorReturn(self.walkForward.targetTicker, dataOfInterest)
                transformedPreds = transformedPreds.join(dailyFactorReturn).dropna()
                returnStream = pd.DataFrame(transformedPreds.apply(lambda x:x[0] * x[1], axis=1), columns=["Algo Return"]) if returnStream is None else pd.concat([returnStream, pd.DataFrame(transformedPreds.apply(lambda x:x[0] * x[1], axis=1), columns=["Algo Return"])])
                factorReturn = pd.DataFrame(transformedPreds[["Factor Return"]]) if factorReturn is None else pd.concat([factorReturn, pd.DataFrame(transformedPreds[["Factor Return"]])])
                predictions = pd.DataFrame(transformedPreds[["Predictions"]]) if predictions is None else pd.concat([predictions, pd.DataFrame(transformedPreds[["Predictions"]])])

                alpha, beta = empyrical.alpha_beta(returnStream, factorReturn)
                rawBeta = abs(empyrical.alpha_beta(returnStream.apply(lambda x:applyBinary(x), axis=0), factorReturn.apply(lambda x:applyBinary(x), axis=0))[1])
                shortSharpe = empyrical.sharpe_ratio(returnStream)
                activity = np.count_nonzero(returnStream)/float(len(returnStream))
                algoAnnualReturn = empyrical.annual_return(returnStream.values)[0]
                algoVol = empyrical.annual_volatility(returnStream.values)
                factorAnnualReturn = empyrical.annual_return(factorReturn.values)[0]
                factorVol = empyrical.annual_volatility(factorReturn.values)
                treynor = ((empyrical.annual_return(returnStream.values)[0] - empyrical.annual_return(factorReturn.values)[0]) \
                           / abs(empyrical.beta(returnStream, factorReturn)))
                sharpeDiff = empyrical.sharpe_ratio(returnStream) - empyrical.sharpe_ratio(factorReturn)
                relativeSharpe = sharpeDiff / empyrical.sharpe_ratio(factorReturn) * (empyrical.sharpe_ratio(factorReturn)/abs(empyrical.sharpe_ratio(factorReturn)))
                stability = empyrical.stability_of_timeseries(returnStream)

                ##CALCULATE SHARPE WITH SLIPPAGE
                estimatedSlippageLoss = portfolioGeneration.estimateTransactionCost(predictions)
                estimatedSlippageLoss.columns = returnStream.columns
                slippageAdjustedReturn = (returnStream - estimatedSlippageLoss).dropna()
                slippageSharpe = empyrical.sharpe_ratio(slippageAdjustedReturn)
                sharpeDiffSlippage = empyrical.sharpe_ratio(slippageAdjustedReturn) - empyrical.sharpe_ratio(factorReturn)
                relativeSharpeSlippage = sharpeDiffSlippage / empyrical.sharpe_ratio(factorReturn) * (empyrical.sharpe_ratio(factorReturn)/abs(empyrical.sharpe_ratio(factorReturn)))

                if (empyrical.sharpe_ratio(returnStream) < 0.0 or abs(beta) > 0.7 or activity < 0.5 or accuracy < 0.45) and shortSeen == 0:
                    return None, {
                            "sharpe":shortSharpe, ##OVERLOADED IN FAIL
                            "factorSharpe":empyrical.sharpe_ratio(factorReturn),
                            "sharpeSlippage":slippageSharpe,
                            "beta":abs(beta),
                            "alpha":alpha,
                            "activity":activity,
                            "treynor":treynor,
                            "period":"first 252 days",
                            "algoReturn":algoAnnualReturn,
                            "algoVol":algoVol,
                            "factorReturn":factorAnnualReturn,
                            "factorVol":factorVol,
                            "sharpeDiff":sharpeDiff,
                            "relativeSharpe":relativeSharpe,
                            "sharpeDiffSlippage":sharpeDiffSlippage,
                            "relativeSharpeSlippage":relativeSharpeSlippage,
                            "rawBeta":rawBeta,
                            "stability":stability,
                            "loss":loss,
                            "roc_auc":roc_auc,
                            "accuracy":accuracy
                    }, None, None
                
                elif (((empyrical.sharpe_ratio(returnStream) < 0.25 or slippageSharpe < 0.0) and shortSeen == 1) or ((empyrical.sharpe_ratio(returnStream) < 0.25 or slippageSharpe < 0.0) and (shortSeen == 2 or shortSeen == 3)) or abs(beta) > 0.6 or activity < 0.6 or stability < 0.4  or accuracy < 0.45) and (shortSeen == 1 or shortSeen == 2 or shortSeen == 3):
                    periodName = "first 600 days"
                    if shortSeen == 2:
                        periodName = "first 900 days"
                    elif shortSeen == 3:
                        periodName = "first 1200 days"
                    return None, {
                            "sharpe":shortSharpe, ##OVERLOADED IN FAIL
                            "factorSharpe":empyrical.sharpe_ratio(factorReturn),
                            "sharpeSlippage":slippageSharpe,
                            "alpha":alpha,
                            "beta":abs(beta),
                            "activity":activity,
                            "treynor":treynor,
                            "period":periodName,
                            "algoReturn":algoAnnualReturn,
                            "algoVol":algoVol,
                            "factorReturn":factorAnnualReturn,
                            "factorVol":factorVol,
                            "sharpeDiff":sharpeDiff,
                            "relativeSharpe":relativeSharpe,
                            "sharpeDiffSlippage":sharpeDiffSlippage,
                            "relativeSharpeSlippage":relativeSharpeSlippage,
                            "rawBeta":rawBeta,
                            "stability":stability,
                            "loss":loss,
                            "roc_auc":roc_auc,
                            "accuracy":accuracy
                    }, None, None
                    
                elif shortSeen < 4:
                    print("CONTINUING", "SHARPE:", shortSharpe, "SHARPE DIFF:", sharpeDiff, "RAW BETA:", rawBeta, "TREYNOR:", treynor)
                   
                shortSeen += 1

            return returnStream, factorReturn, predictions, slippageAdjustedReturn