예제 #1
0
 def test_omega_ratio(self, test_risk_free, test_required_return):
     res_a = empyrical.omega_ratio(ret['a'],
                                   risk_free=test_risk_free,
                                   required_return=test_required_return)
     if np.isnan(res_a):
         res_a = np.inf
     res_b = empyrical.omega_ratio(ret['b'],
                                   risk_free=test_risk_free,
                                   required_return=test_required_return)
     if np.isnan(res_b):
         res_b = np.inf
     res_c = empyrical.omega_ratio(ret['c'],
                                   risk_free=test_risk_free,
                                   required_return=test_required_return)
     if np.isnan(res_c):
         res_c = np.inf
     assert isclose(
         ret['a'].vbt.returns.omega_ratio(
             risk_free=test_risk_free,
             required_return=test_required_return), res_a)
     pd.testing.assert_series_equal(
         ret.vbt.returns.omega_ratio(risk_free=test_risk_free,
                                     required_return=test_required_return),
         pd.Series([res_a, res_b, res_c],
                   index=ret.columns).rename('omega_ratio'))
     pd.testing.assert_series_equal(
         ret.vbt.returns.rolling_omega_ratio(
             ret.shape[0],
             minp=1,
             risk_free=test_risk_free,
             required_return=test_required_return).iloc[-1],
         pd.Series([res_a, res_b, res_c],
                   index=ret.columns).rename(ret.index[-1]))
예제 #2
0
    def single_sim(self):
        bootret_by_year = []
        cumulative_lengths = []
        data_panel = []
        for i in range(self.holding_period):
            index_start = self.data.sample().index[0]
            index_start = self.data.index.get_loc(index_start)
            L_i = self.holding_period + 1
            while L_i > self.holding_period:
                L_i = geom.rvs(p = 1/self.mean_block_length)
            cumulative_lengths.append(L_i)
            if sum(cumulative_lengths) > self.holding_period:
                L_final = self.holding_period - sum(cumulative_lengths[:-1])
                if L_final > len(self.data) - index_start:
                    diff = L_final - (len(self.data) - index_start)
                    subsample_generated = self.data.iloc[index_start-diff: (index_start-diff + L_final), :]
                else:
                    subsample_generated = self.data.iloc[index_start: index_start + L_final, :]
                data_panel.append(subsample_generated)
                break
            else:
                subsample_generated = self.data.iloc[index_start: index_start + L_i, :]
                if L_i > len(self.data) - index_start :
                    L_i = len(self.data) - index_start
                data_panel.append(subsample_generated)
                cumulative_lengths[-1] = L_i

        bootstrapSample = pd.concat([subsample for subsample in data_panel], axis = 0, ignore_index = True)

        if self.stress_freq:
            historical_ret_by_year = self.data @ np.array([self.w1_stock, self.w2_bond, self.w3_gold]).T
            year_min_ret = historical_ret_by_year.idxmin()
            for i in range(self.holding_period):
                extreme_event_dummy = True if np.random.rand() < 0.05 else False
                if extreme_event_dummy:
                    if self.stress_intensity == 1:
                        bootstrapSample.iloc[i,:] = self.data.loc[year_min_ret,:]
                    else:
                        bootstrapSample.iloc[i,:] = self.data.loc[year_min_ret,:]
                        bootstrapSample.iloc[i,:] *= 1.5

        total_ret_by_year = bootstrapSample @ np.array([self.w1_stock, self.w2_bond, self.w3_gold]).T
        total_ret_by_year -= self.TER

        portfolio_path = self.capital * np.cumprod(total_ret_by_year + 1)

        cagr = (portfolio_path.values[-1] / self.capital) ** (1/self.holding_period) - 1
        annual_volatility = total_ret_by_year.std()
        maxDrawdown = max_drawdown(pd.Series(total_ret_by_year))
        omega_ratio2 = omega_ratio(pd.Series(total_ret_by_year), required_return = 0.02, annualization = 1)
        omega_ratio4 = omega_ratio(pd.Series(total_ret_by_year), required_return = 0.04, annualization = 1)
        omega_ratio8 = omega_ratio(pd.Series(total_ret_by_year), required_return = 0.08, annualization = 1)
        return (np.insert(portfolio_path.values, 0, self.capital), cagr, annual_volatility, maxDrawdown,
                omega_ratio2, omega_ratio4, omega_ratio8)
    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}')
예제 #4
0
def omega_ratio(returns, annual_return_threshhold=0.0):
    """
    Determines the Omega ratio of a strategy.

    Parameters
    ----------
    returns : pd.Series
        Daily returns of the strategy, noncumulative.
        - See full explanation in :func:`~pyfolio.timeseries.cum_returns`.
    annual_return_threshold : float, optional
        Minimum acceptable return of the investor. Annual threshold over which
        returns are considered positive or negative. It is converted to a
        value appropriate for the period of the returns for this ratio.
        E.g. An annual minimum acceptable return of 100 translates to a daily
        minimum acceptable return of 0.01848.
            (1 + 100) ** (1. / 252) - 1 = 0.01848
        Daily returns must exceed this value to be considered positive. The
        daily return yields the desired annual return when compounded over
        the average number of business days in a year.
            (1 + 0.01848) ** 252 - 1 = 99.93
        - Defaults to 0.0


    Returns
    -------
    float
        Omega ratio.

    Note
    -----
    See https://en.wikipedia.org/wiki/Omega_ratio for more details.
    """

    return empyrical.omega_ratio(returns,
                                 required_return=annual_return_threshhold)
예제 #5
0
    def _get_reward(self) -> float:
        """
        This method computes the reward from each action, by looking at the annualized
        ratio, provided in the reward_function
        :return: annualized value of the selected reward ratio
        """
        lookback = min(self.current_step, self._returns_lookback)
        returns = np.diff(self.portfolio[-lookback:])

        if np.count_nonzero(returns) < 1:
            return 0

        if np.count_nonzero(returns) < 1:
            return 0

        if self._reward_function == 'sortino':
            reward = sortino_ratio(returns, annualization=365 * 24)
        elif self._reward_function == 'calmar':
            reward = calmar_ratio(returns, annualization=365 * 24)
        elif self._reward_function == 'omega':
            reward = omega_ratio(returns, annualization=365 * 24)
        else:
            reward = returns[-1]

        return reward if np.isfinite(reward) else 0
예제 #6
0
def omega_ratio(returns, annual_return_threshhold=0.0):
    """
    Determines the Omega ratio of a strategy.

    Parameters
    ----------
    returns : pd.Series
        Daily returns of the strategy, noncumulative.
        - See full explanation in :func:`~pyfolio.timeseries.cum_returns`.
    annual_return_threshold : float, optional
        Minimum acceptable return of the investor. Annual threshold over which
        returns are considered positive or negative. It is converted to a
        value appropriate for the period of the returns for this ratio.
        E.g. An annual minimum acceptable return of 100 translates to a daily
        minimum acceptable return of 0.01848.
            (1 + 100) ** (1. / 252) - 1 = 0.01848
        Daily returns must exceed this value to be considered positive. The
        daily return yields the desired annual return when compounded over
        the average number of business days in a year.
            (1 + 0.01848) ** 252 - 1 = 99.93
        - Defaults to 0.0


    Returns
    -------
    float
        Omega ratio.

    Note
    -----
    See https://en.wikipedia.org/wiki/Omega_ratio for more details.
    """

    return ep.omega_ratio(returns, required_return=annual_return_threshhold)
예제 #7
0
 def test_omega(self, returns, risk_free, required_return,
                expected):
     assert_almost_equal(
         empyrical.omega_ratio(
             returns,
             risk_free=risk_free,
             required_return=required_return),
         expected,
         DECIMAL_PLACES)
예제 #8
0
def calculate_empyrical(fund_type):
    filename = '%s/%s_return.pkl'%(const.FOF_DIR, fund_type)
    ret_df = pd.read_pickle(filename)
    # Omega Ratio
    df = pd.DataFrame(index=ret_df.columns)
    df.loc[:, 'omega'] = ret_df.apply(lambda x: empyrical.omega_ratio(x))

    fname = '%s/%s_empyrical.xlsx'%(const.FOF_DIR, fund_type)
    df.to_excel(fname)
예제 #9
0
    def plot(self):
        # show a plot of portfolio vs mean market performance
        df_info = pd.DataFrame(self.infos)
        df_info.set_index('current step', inplace=True)
        #   df_info.set_index('date', inplace=True)
        rn = np.asarray(df_info['portfolio return'])

        try:
            spf = df_info['portfolio value'].iloc[1]  #   Start portfolio value
            epf = df_info['portfolio value'].iloc[-1]  #   End portfolio value
            pr = (epf - spf) / spf
        except:
            pr = 0

        try:
            sr = sharpe_ratio(rn)
        except:
            sr = 0

        try:
            sor = sortino_ratio(rn)
        except:
            sor = 0

        try:
            mdd = max_drawdown(rn)
        except:
            mdd = 0

        try:
            cr = calmar_ratio(rn)
        except:
            cr = 0

        try:
            om = omega_ratio(rn)
        except:
            om = 0

        try:
            dr = downside_risk(rn)
        except:
            dr = 0

        print("First portfolio value: ",
              np.round(df_info['portfolio value'].iloc[1]))
        print("Last portfolio value: ",
              np.round(df_info['portfolio value'].iloc[-1]))

        title = self.strategy_name + ': ' + 'profit={: 2.2%} sharpe={: 2.2f} sortino={: 2.2f} max drawdown={: 2.2%} calmar={: 2.2f} omega={: 2.2f} downside risk={: 2.2f}'.format(
            pr, sr, sor, mdd, cr, om, dr)
        #   df_info[['market value', 'portfolio value']].plot(title=title, fig=plt.gcf(), figsize=(15,10), rot=30)
        df_info[['portfolio value']].plot(title=title,
                                          fig=plt.gcf(),
                                          figsize=(15, 10),
                                          rot=30)
예제 #10
0
def omega_ratio(close, risk_free=0.0, required_return=0.0, trading_days=252):
    try:
        rets = daily_returns(close)
        omr_data = empyrical.omega_ratio(rets,
                                         risk_free=risk_free,
                                         required_return=required_return,
                                         annualization=trading_days)
        return omr_data
    except Exception as e:
        raise (e)
예제 #11
0
    def _get_reward(self, current_prices, next_prices):
        if self.compute_reward == compute_reward.profit:
            returns_rate = next_prices / current_prices
            #   pip_value = self._calculate_pip_value_in_account_currency(account_currency.USD, next_prices)
            #   returns_rate = np.multiply(returns_rate, pip_value)
            log_returns = np.log(returns_rate)
            last_weight = self.current_weights
            securities_value = self.current_portfolio_values[:-1] * returns_rate
            self.current_portfolio_values[:-1] = securities_value
            self.current_weights = self.current_portfolio_values / np.sum(
                self.current_portfolio_values)
            reward = last_weight[:-1] * log_returns
        elif self.compute_reward == compute_reward.sharpe:
            try:
                sr = sharpe_ratio(np.asarray(self.returns))
            except:
                sr = 0
            reward = sr
        elif self.compute_reward == compute_reward.sortino:
            try:
                sr = sortino_ratio(np.asarray(self.returns))
            except:
                sr = 0
            reward = sr
        elif self.compute_reward == compute_reward.max_drawdown:
            try:
                mdd = max_drawdown(np.asarray(self.returns))
            except:
                mdd = 0
            reward = mdd
        elif self.compute_reward == compute_reward.calmar:
            try:
                cr = calmar_ratio(np.asarray(self.returns))
            except:
                cr = 0
            reward = cr
        elif self.compute_reward == compute_reward.omega:
            try:
                om = omega_ratio(np.asarray(self.returns))
            except:
                om = 0
            reward = om
        elif self.compute_reward == compute_reward.downside_risk:
            try:
                dr = downside_risk(np.asarray(self.returns))
            except:
                dr = 0
            reward = dr

        try:
            reward = reward.mean()
        except:
            reward = reward

        return reward
예제 #12
0
def RiskRewardStats(df):
    global RiskRewardList
    RiskRewardIndex = ['Sharpe Ratio','Sortino Ratio','Omega Ratio','Skewness','Kurtosis',
                      'Correlation vs MSCI World TR Index','Correlation vs Bloomberg Index']
    OmegaRatio = omega_ratio(df['Monthly Return'])
    Kurtosis = df['Monthly Return'].kurt()
    Skewness = df['Monthly Return'].skew()
    SharpeRatio = sharpe_ratio(df['Monthly Return'],period='monthly')
    SortinoRatio = sortino_ratio(df['Monthly Return'],period='monthly')
    RiskRewardList = [SharpeRatio,SortinoRatio,OmegaRatio,Skewness,Kurtosis,MSCIIndex,BloombergIndex]
    RiskRewardDf = pd.DataFrame(RiskRewardList,columns=['Value'],index=RiskRewardIndex)
    return RiskRewardDf
예제 #13
0
def _reward(self):
      length = min(self.current_step, self.reward_len)
      returns = np.diff(self.net_worths)[-length:]

      if self.reward_func == 'sortino':
          reward = sortino_ratio(returns)
      elif self.reward_func == 'calmar':
          reward = calmar_ratio(returns)
      elif self.reward_func == 'omega':
          reward = omega_ratio(returns)
      else
          reward = np.mean(returns)

      return reward if abs(reward) != inf and not np.isnan(reward) else 0
예제 #14
0
 def test_omega_ratio(self, test_risk_free, test_required_return):
     res_a = empyrical.omega_ratio(ret['a'],
                                   risk_free=test_risk_free,
                                   required_return=test_required_return)
     if np.isnan(res_a):
         res_a = np.inf
     res_b = empyrical.omega_ratio(ret['b'],
                                   risk_free=test_risk_free,
                                   required_return=test_required_return)
     if np.isnan(res_b):
         res_b = np.inf
     res_c = empyrical.omega_ratio(ret['c'],
                                   risk_free=test_risk_free,
                                   required_return=test_required_return)
     if np.isnan(res_c):
         res_c = np.inf
     assert isclose(
         ret['a'].vbt.returns.omega_ratio(
             risk_free=test_risk_free,
             required_return=test_required_return), res_a)
     pd.testing.assert_series_equal(
         ret.vbt.returns.omega_ratio(risk_free=test_risk_free,
                                     required_return=test_required_return),
         pd.Series([res_a, res_b, res_c], index=ret.columns))
예제 #15
0
def omega_ratio(daily_returns,
                risk_free=0.0,
                required_return=0.0,
                trading_days=252):
    """Omega Ratio"""
    try:
        logger.info("Calculating Omega Ratio...")
        omr_data = empyrical.omega_ratio(daily_returns,
                                         risk_free=risk_free,
                                         required_return=required_return,
                                         annualization=trading_days)
        return omr_data
    except Exception as exception:
        logger.error('Oops! An Error Occurred ⚠️')
        raise exception
예제 #16
0
    def _reward(self):
        length = min(self.current_step, self.forecast_len)
        returns = np.diff(self.net_worths[-length:])

        if np.count_nonzero(returns) < 1:
            return 0

        if self.reward_func == 'sortino':
            reward = sortino_ratio(returns, annualization=365 * 24)
        elif self.reward_func == 'calmar':
            reward = calmar_ratio(returns, annualization=365 * 24)
        elif self.reward_func == 'omega':
            reward = omega_ratio(returns, annualization=365 * 24)
        else:
            reward = returns[-1]

        return reward if np.isfinite(reward) else 0
    def _reward(self):
        length = min(self.current_step, self.window_size)
        returns = np.diff(self.net_worths[-length:])

        if np.count_nonzero(returns) < 1:
            return 0

        if self.reward_func == 'sortino':
            reward = sortino_ratio(returns, annualization=self.annualization)
        elif self.reward_func == 'calmar':
            reward = calmar_ratio(returns, annualization=self.annualization)
        elif self.reward_func == 'omega':
            reward = omega_ratio(returns, annualization=self.annualization)
        elif self.reward_func == "logret":
            reward = np.log(returns[-1])
        else:
            reward = returns[-1]

        return reward if np.isfinite(reward) else 0
예제 #18
0
import pandas as pd
import empyrical as emp

df = pd.read_csv('ac-worth-from-2017/002138.csv')
df['daily_return'] = df['worth'].pct_change()

days = df['date'].count()
return_days = days / 3.347
risk_free = 0.03 / return_days

annual_return = emp.annual_return(df['daily_return'],
                                  annualization=return_days)
max_drawdown = emp.max_drawdown(df['daily_return'])
sharpe_ratio = emp.sharpe_ratio(df['daily_return'],
                                risk_free,
                                annualization=return_days)
sortino_ratio = emp.sortino_ratio(df['daily_return'],
                                  risk_free,
                                  annualization=return_days)
omega_ratio = emp.omega_ratio(df['daily_return'],
                              risk_free,
                              annualization=return_days)
print(annual_return, max_drawdown, sharpe_ratio, sortino_ratio, omega_ratio)
예제 #19
0
 def _omega(self):
     self.__omega = ey.omega_ratio(returns = self.__returns, risk_free = self.__risk_free)
예제 #20
0
 def test_omega_returns(self, returns, required_return_less,
                        required_return_more):
     assert empyrical.omega_ratio(returns, required_return_less) > \
         empyrical.omega_ratio(returns, required_return_more)
예제 #21
0
def trades(trades_list: list, daily_balance: list):
    starting_balance = 0
    current_balance = 0

    for e in store.exchanges.storage:
        starting_balance += store.exchanges.storage[e].starting_assets[
            jh.app_currency()]
        current_balance += store.exchanges.storage[e].assets[jh.app_currency()]

    starting_balance = round(starting_balance, 2)
    current_balance = round(current_balance, 2)

    if len(trades_list) == 0:
        return None

    df = pd.DataFrame.from_records([t.to_dict() for t in trades_list])

    total_completed = len(df)
    winning_trades = df.loc[df['PNL'] > 0]
    total_winning_trades = len(winning_trades)
    losing_trades = df.loc[df['PNL'] < 0]
    total_losing_trades = len(losing_trades)

    losing_i = df['PNL'] < 0
    losing_streaks = losing_i.ne(losing_i.shift()).cumsum()
    losing_streak = losing_streaks[losing_i].value_counts().max()

    winning_i = df['PNL'] > 0
    winning_streaks = winning_i.ne(winning_i.shift()).cumsum()
    winning_streak = winning_streaks[winning_i].value_counts().max()
    largest_losing_trade = round(df['PNL'].min(), 2)
    largest_winning_trade = round(df['PNL'].max(), 2)

    win_rate = len(winning_trades) / (len(losing_trades) + len(winning_trades))
    max_R = round(df['R'].max(), 2)
    min_R = round(df['R'].min(), 2)
    mean_R = round(df['R'].mean(), 2)
    longs_count = len(df.loc[df['type'] == 'long'])
    shorts_count = len(df.loc[df['type'] == 'short'])
    longs_percentage = longs_count / (longs_count + shorts_count) * 100
    short_percentage = 100 - longs_percentage
    fee = df['fee'].sum()
    net_profit = round(df['PNL'].sum(), 2)
    net_profit_percentage = round((net_profit / starting_balance) * 100, 2)
    average_win = round(winning_trades['PNL'].mean(), 2)
    average_loss = round(abs(losing_trades['PNL'].mean()), 2)
    ratio_avg_win_loss = average_win / average_loss
    expectancy = (0 if np.isnan(average_win) else average_win) * win_rate - (
        0 if np.isnan(average_loss) else average_loss) * (1 - win_rate)
    expectancy = round(expectancy, 2)
    expectancy_percentage = round((expectancy / starting_balance) * 100, 2)
    expected_net_profit_every_100_trades = round(expectancy_percentage * 100,
                                                 2)
    average_holding_period = df['holding_period'].mean()
    average_winning_holding_period = winning_trades['holding_period'].mean()
    average_losing_holding_period = losing_trades['holding_period'].mean()
    gross_profit = round(df.loc[df['PNL'] > 0]['PNL'].sum(), 2)
    gross_loss = round(df.loc[df['PNL'] < 0]['PNL'].sum(), 2)

    daily_returns = pd.Series(daily_balance).pct_change(1).values
    max_drawdown = round(empyrical.max_drawdown(daily_returns) * 100, 2)
    annual_return = round(empyrical.annual_return(daily_returns) * 100, 2)
    sharpe_ratio = round(empyrical.sharpe_ratio(daily_returns), 2)
    calmar_ratio = round(empyrical.calmar_ratio(daily_returns), 2)
    sortino_ratio = round(empyrical.sortino_ratio(daily_returns), 2)
    omega_ratio = round(empyrical.omega_ratio(daily_returns), 2)
    total_open_trades = store.app.total_open_trades
    open_pl = store.app.total_open_pl

    return {
        'total':
        np.nan if np.isnan(total_completed) else total_completed,
        'total_winning_trades':
        np.nan if np.isnan(total_winning_trades) else total_winning_trades,
        'total_losing_trades':
        np.nan if np.isnan(total_losing_trades) else total_losing_trades,
        'starting_balance':
        np.nan if np.isnan(starting_balance) else starting_balance,
        'finishing_balance':
        np.nan if np.isnan(current_balance) else current_balance,
        'win_rate':
        np.nan if np.isnan(win_rate) else win_rate,
        'max_R':
        np.nan if np.isnan(max_R) else max_R,
        'min_R':
        np.nan if np.isnan(min_R) else min_R,
        'mean_R':
        np.nan if np.isnan(mean_R) else mean_R,
        'ratio_avg_win_loss':
        np.nan if np.isnan(ratio_avg_win_loss) else ratio_avg_win_loss,
        'longs_count':
        np.nan if np.isnan(longs_count) else longs_count,
        'longs_percentage':
        np.nan if np.isnan(longs_percentage) else longs_percentage,
        'short_percentage':
        np.nan if np.isnan(short_percentage) else short_percentage,
        'shorts_count':
        np.nan if np.isnan(shorts_count) else shorts_count,
        'fee':
        np.nan if np.isnan(fee) else fee,
        'net_profit':
        np.nan if np.isnan(net_profit) else net_profit,
        'net_profit_percentage':
        np.nan if np.isnan(net_profit_percentage) else net_profit_percentage,
        'average_win':
        np.nan if np.isnan(average_win) else average_win,
        'average_loss':
        np.nan if np.isnan(average_loss) else average_loss,
        'expectancy':
        np.nan if np.isnan(expectancy) else expectancy,
        'expectancy_percentage':
        np.nan if np.isnan(expectancy_percentage) else expectancy_percentage,
        'expected_net_profit_every_100_trades':
        np.nan if np.isnan(expected_net_profit_every_100_trades) else
        expected_net_profit_every_100_trades,
        'average_holding_period':
        average_holding_period,
        'average_winning_holding_period':
        average_winning_holding_period,
        'average_losing_holding_period':
        average_losing_holding_period,
        'gross_profit':
        gross_profit,
        'gross_loss':
        gross_loss,
        'max_drawdown':
        max_drawdown,
        'annual_return':
        annual_return,
        'sharpe_ratio':
        sharpe_ratio,
        'calmar_ratio':
        calmar_ratio,
        'sortino_ratio':
        sortino_ratio,
        'omega_ratio':
        omega_ratio,
        'total_open_trades':
        total_open_trades,
        'open_pl':
        open_pl,
        'winning_streak':
        winning_streak,
        'losing_streak':
        losing_streak,
        'largest_losing_trade':
        largest_losing_trade,
        'largest_winning_trade':
        largest_winning_trade,
    }
예제 #22
0
    def calculate_statistics(self, df: DataFrame = None, output=True):
        """"""
        self.output("开始计算策略统计指标")

        # Check DataFrame input exterior
        if df is None:
            df = self.daily_df

        # Check for init DataFrame
        if df is None:
            # Set all statistics to 0 if no trade.
            start_date = ""
            end_date = ""
            total_days = 0
            profit_days = 0
            loss_days = 0
            end_balance = 0
            max_drawdown = 0
            max_ddpercent = 0
            max_drawdown_duration = 0
            max_drawdown_end = 0
            total_net_pnl = 0
            daily_net_pnl = 0
            total_commission = 0
            daily_commission = 0
            total_slippage = 0
            daily_slippage = 0
            total_turnover = 0
            daily_turnover = 0
            total_trade_count = 0
            daily_trade_count = 0
            total_return = 0
            annual_return = 0
            daily_return = 0
            return_std = 0
            sharpe_ratio = 0
            sortino_info = 0
            win_ratio = 0
            return_drawdown_ratio = 0
            tail_ratio_info = 0
            stability_return = 0
            win_loss_pnl_ratio = 0
            pnl_medio = 0
            duration_medio = 0
            calmar_ratio = 0
        else:
            # Calculate balance related time series data
            df["balance"] = df["net_pnl"].cumsum() + self.capital
            df["return"] = np.log(df["balance"] /
                                  df["balance"].shift(1)).fillna(0)
            df["highlevel"] = (df["balance"].rolling(min_periods=1,
                                                     window=len(df),
                                                     center=False).max())
            df["drawdown"] = df["balance"] - df["highlevel"]
            df["ddpercent"] = df["drawdown"] / df["highlevel"] * 100

            # Calculate statistics value
            start_date = df.index[0]
            end_date = df.index[-1]

            total_days = len(df)
            profit_days = len(df[df["net_pnl"] > 0])
            loss_days = len(df[df["net_pnl"] < 0])

            end_balance = df["balance"].iloc[-1]
            max_drawdown = df["drawdown"].min()
            max_ddpercent = df["ddpercent"].min()
            max_drawdown_end = df["drawdown"].idxmin()

            if isinstance(max_drawdown_end, date):
                max_drawdown_start = df["balance"][:max_drawdown_end].idxmax()
                max_drawdown_duration = (max_drawdown_end -
                                         max_drawdown_start).days
            else:
                max_drawdown_duration = 0

            total_net_pnl = df["net_pnl"].sum()
            daily_net_pnl = total_net_pnl / total_days

            win = df[df["net_pnl"] > 0]
            win_amount = win["net_pnl"].sum()
            win_pnl_medio = win["net_pnl"].mean()
            # win_duration_medio = win["duration"].mean().total_seconds()/3600
            win_count = win["trade_count"].sum()
            pnl_medio = df["net_pnl"].mean()
            # duration_medio = df["duration"].mean().total_seconds()/3600

            loss = df[df["net_pnl"] < 0]
            loss_amount = loss["net_pnl"].sum()
            loss_pnl_medio = loss["net_pnl"].mean()
            # loss_duration_medio = loss["duration"].mean().total_seconds()/3600

            total_commission = df["commission"].sum()
            daily_commission = total_commission / total_days

            total_slippage = df["slippage"].sum()
            daily_slippage = total_slippage / total_days

            total_turnover = df["turnover"].sum()
            daily_turnover = total_turnover / total_days

            total_trade_count = df["trade_count"].sum()
            win_ratio = (win_count / total_trade_count) * 100
            win_loss_pnl_ratio = -win_pnl_medio / loss_pnl_medio
            daily_trade_count = total_trade_count / total_days

            total_return = (end_balance / self.capital - 1) * 100
            annual_return = total_return / total_days * 240
            daily_return = df["return"].mean() * 100
            return_std = df["return"].std() * 100

            if return_std:
                sharpe_ratio = daily_return / return_std * np.sqrt(240)
            else:
                sharpe_ratio = 0

            return_drawdown_ratio = -total_return / max_ddpercent

            #calmar_ratio:年化收益率与历史最大回撤率之间的比率
            calmar_ratio = annual_return / abs(max_ddpercent)

            #sortino_info
            sortino_info = sortino_ratio(df['return'])
            omega_info = omega_ratio(df['return'])
            #年化波动率
            annual_volatility_info = annual_volatility(df['return'])
            #年化复合增长率
            cagr_info = cagr(df['return'])
            #年化下行风险率
            annual_downside_risk = downside_risk(df['return'])
            """CVaR即条件风险价值,其含义为在投资组合的损失超过某个给定VaR值的条件下,该投资组合的平均损失值。"""
            c_var = conditional_value_at_risk(df['return'])
            """风险价值(VaR)是对投资损失风险的一种度量。它估计在正常的市场条件下,在设定的时间段(例如一天)中,
            一组投资可能(以给定的概率)损失多少。金融业中的公司和监管机构通常使用VaR来衡量弥补可能损失所需的资产数量"""
            var_info = value_at_risk(df['return'])

            #收益稳定率
            stability_return = stability_of_timeseries(df['return'])
            #尾部比率0.25 == 1/4,收益1,风险4
            tail_ratio_info = tail_ratio(df['return'])

        # Output
        if output:
            self.output("-" * 30)
            self.output(f"首个交易日:\t{start_date}")
            self.output(f"最后交易日:\t{end_date}")

            self.output(f"总交易日:\t{total_days}")
            self.output(f"盈利交易日:\t{profit_days}")
            self.output(f"亏损交易日:\t{loss_days}")

            self.output(f"起始资金:\t{self.capital:,.2f}")
            self.output(f"结束资金:\t{end_balance:,.2f}")

            self.output(f"总收益率:\t{total_return:,.2f}%")
            self.output(f"年化收益:\t{annual_return:,.2f}%")
            self.output(f"最大回撤: \t{max_drawdown:,.2f}")
            self.output(f"百分比最大回撤: {max_ddpercent:,.2f}%")
            self.output(f"最长回撤天数: \t{max_drawdown_duration}")

            self.output(f"总盈亏:\t{total_net_pnl:,.2f}")
            self.output(f"总手续费:\t{total_commission:,.2f}")
            self.output(f"总滑点:\t{total_slippage:,.2f}")
            self.output(f"总成交金额:\t{total_turnover:,.2f}")
            self.output(f"总成交笔数:\t{total_trade_count}")

            self.output(f"日均盈亏:\t{daily_net_pnl:,.2f}")
            self.output(f"日均手续费:\t{daily_commission:,.2f}")
            self.output(f"日均滑点:\t{daily_slippage:,.2f}")
            self.output(f"日均成交金额:\t{daily_turnover:,.2f}")
            self.output(f"日均成交笔数:\t{daily_trade_count}")

            self.output(f"日均收益率:\t{daily_return:,.2f}%")
            self.output(f"收益标准差:\t{return_std:,.2f}%")
            self.output(f"胜率:\t{win_ratio:,.2f}")
            self.output(f"盈亏比:\t\t{win_loss_pnl_ratio:,.2f}")

            self.output(f"平均每笔盈亏:\t{pnl_medio:,.2f}")
            self.output(f"calmar_ratio:\t{calmar_ratio:,.3f}")
            # self.output(f"平均持仓小时:\t{duration_medio:,.2f}")
            self.output(f"Sharpe Ratio:\t{sharpe_ratio:,.2f}")
            self.output(f"sortino Ratio:\t{sortino_info:,.3f}")
            self.output(f"收益回撤比:\t{return_drawdown_ratio:,.2f}")

        statistics = {
            "start_date": start_date,
            "end_date": end_date,
            "total_days": total_days,
            "profit_days": profit_days,
            "loss_days": loss_days,
            "capital": self.capital,
            "end_balance": end_balance,
            "max_drawdown": max_drawdown,
            "max_ddpercent": max_ddpercent,
            "max_drawdown_end": max_drawdown_end,
            "max_drawdown_duration": max_drawdown_duration,
            "total_net_pnl": total_net_pnl,
            "daily_net_pnl": daily_net_pnl,
            "total_commission": total_commission,
            "daily_commission": daily_commission,
            "total_slippage": total_slippage,
            "daily_slippage": daily_slippage,
            "total_turnover": total_turnover,
            "daily_turnover": daily_turnover,
            "total_trade_count": total_trade_count,
            "daily_trade_count": daily_trade_count,
            "total_return": total_return,
            "annual_return": annual_return,
            "daily_return": daily_return,
            "return_std": return_std,
            "sharpe_ratio": sharpe_ratio,
            'sortino_info': sortino_info,
            "win_ratio": win_ratio,
            "return_drawdown_ratio": return_drawdown_ratio,
            "tail_ratio_info": tail_ratio_info,
            "stability_return": stability_return,
            "win_loss_pnl_ratio": win_loss_pnl_ratio,
            "pnl_medio": pnl_medio,
            "calmar_ratio": calmar_ratio
        }

        # Filter potential error infinite value
        for key, value in statistics.items():
            if value in (np.inf, -np.inf):
                value = 0
            statistics[key] = np.nan_to_num(value)

        self.output("策略统计指标计算完成")
        return statistics
예제 #23
0
 def getOmegaRatio(returns,
                   risk_free=0.0,
                   required_return=0.0,
                   annualization=252):
     return empyrical.omega_ratio(returns, risk_free, required_return,
                                  annualization)
예제 #24
0
파일: test.py 프로젝트: no7dw/py-practice
    max_drawdown,
    sharpe_ratio,
    sortino_ratio,
    calmar_ratio,
    omega_ratio,
    tail_ratio
)
import pandas as pd
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)
)
creturns = cum_returns(returns)
max_drawdown(returns)
annual_return(returns)
annual_volatility(returns, period='daily')
calmar_ratio(returns)
omega_ratio(returns=returns, risk_free=0.01)
sharpe_ratio(returns=returns, risk_free=0.01)
sortino_ratio(returns=returns)
downside_risk(returns=returns)
alpha(returns=returns, factor_returns=benchmark_returns, risk_free=0.01)
beta(returns=returns, factor_returns=benchmark_returns, risk_free=0.01)
tail_ratio(returns=returns)