Следующие показатели можно использовать для измерения эффективности вашего портфеля или торговой прибыли.

1. Коэффициент Шарпа

Коэффициент Шарпа (также известный как индекс Шарпа, мера Шарпа и отношение вознаграждения к изменчивости) измеряет эффективность инвестиций, таких как ценные бумаги или портфели, по сравнению с безрисковым активом после поправки на его риск. Он был назван в честь Уильяма Ф. Шарпа, который разработал его в 1966 году.

 def annualized_sharpe_ratio(self):
     return round(
         ( (self.returns.mean() - self.risk_free_rate) / (self.returns.std()) )\
                    * ( np.sqrt(self.frequency) ), 2
         )

2. Коэффициент Кальмара

Коэффициент Calmar (или коэффициент просадки) — это показатель эффективности, используемый для оценки советников по торговле товарами и хедж-фондов. Он был создан Терри У. Янгом и впервые опубликован в 1991 году в отраслевом журнале Futures.

def calmar_ratio(self):
    return round(self.annualized_returns()/abs(self.max_draw_down()), 2)

3. Коэффициент Сортино

Коэффициент Сортино измеряет доходность инвестиционного актива, портфеля или стратегии с поправкой на риск. Это модификация коэффициента Шарпа, но наказывается только та доходность, которая падает ниже указанной пользователем цели или требуемой нормы прибыли, в то время как коэффициент Шарпа в равной степени наказывает как восходящую, так и нисходящую волатильность.

def sortino_ratio(self):
    average_annual_return = np.nanmean(self.returns, axis=0) * self.frequency
    return round(
        (average_annual_return - self.risk_free_rate)/self.downside_risk(), 2
    )

4. Максимальная просадка

Максимальная просадка (MDD) — это максимальная наблюдаемая потеря от пика до минимума портфеля до достижения нового пика. Максимальная просадка — это показатель риска снижения за определенный период времени.

def max_draw_down(self):
    cum_returns = self.returns.add(1).cumprod()
    draw_down = cum_returns.div(cum_returns.cummax()).sub(1)
    max_draw_down = draw_down.min()*100
    return round( max_draw_down, 2 )

5. Волатильность

Волатильность часто относится к степени неопределенности или риска, связанного с размером изменений стоимости ценной бумаги. Более высокая волатильность означает, что стоимость ценной бумаги потенциально может быть распределена по более широкому диапазону значений.

def annualized_volatility(self):
    return round(
          self.returns.std()*np.sqrt(self.frequency)*100, 2
    )

6. Бета

Коэффициент бета может измерять волатильность отдельной акции по сравнению с систематическим риском всего рынка.

def beta(self,index):
    return round(self.returns.cov(index)/index.var(), 2)

Примеры показателей для Lockheed Martin ( LMT ) между 01.01.2022 и 01.01.2023

Весь код для запуска метрик приведен ниже, и его можно запустить для любой акции, указав тикер.

import pandas as pd
import pandas_datareader.data as web
import numpy as np

class Metrics():
    def __init__(self, returns, risk_free_rate=2, period='daily'):
        self.returns = returns
        self.period = {
            'monthly' : 12,
            'weekly' : 52,
            'daily' : 252
        }
        self.frequency = self.period[period]
        self.risk_free_rate = np.power(1+risk_free_rate*0.01,1/self.frequency) - 1

    def annualized_sharpe_ratio(self):
        return round(
            ( (self.returns.mean() - self.risk_free_rate) / (self.returns.std()) )\
                      * ( np.sqrt(self.frequency) ), 2
        )

    def annualized_volatility(self):
        return round(
            self.returns.std()*np.sqrt(self.frequency)*100, 2
        )

    def max_draw_down(self):
        cum_returns = self.returns.add(1).cumprod()
        draw_down = cum_returns.div(cum_returns.cummax()).sub(1)
        max_draw_down = draw_down.min()*100
        return round( max_draw_down, 2 )

    def cumulative_rets(self):
        return (self.returns+1).prod()

    def annualized_returns(self):
        num_years = len(self.returns) / self.frequency
        ending_value = self.cumulative_rets()
        return (ending_value **(1 / num_years) - 1)*100

    def calmar_ratio(self):
        return round(self.annualized_returns()/abs(self.max_draw_down()), 2)

    def downside_risk(self):
        df = pd.DataFrame()
        df['Returns'] = self.returns
        df['downside_returns'] = 0
        df.loc[df['Returns'] < 0, 'downside_returns'] = df['Returns']**2
        down_risk = np.sqrt(df['downside_returns'].mean())*np.sqrt(self.frequency)
        return down_risk

    def sortino_ratio(self):
        average_annual_return = np.nanmean(self.returns, axis=0) * self.frequency
        return round(
            (average_annual_return - self.risk_free_rate)/self.downside_risk(), 2
        )


    def beta(self,index):
        return round(self.returns.cov(index)/index.var(), 2)

if __name__ == '__main__':

    stock = 'LMT.US'
    index = '^DJI'

    start = '2022-01-01'
    end = '2023-01-01'

    lmt = web.DataReader(stock, 'stooq')
    lmt = lmt.sort_values(by='Date')
    lmt = lmt['Close'].pct_change()
    mask = ( start <= lmt.index ) & ( lmt.index <= end )
    lmt = lmt[mask]

    dji = web.DataReader(index, 'stooq')
    dji = dji.sort_values(by='Date')
    dji = dji['Close'].pct_change()
    mask = ( start <= dji.index ) & ( dji.index <= end )
    dji = dji[mask]


    metrics = Metrics(lmt)

    print('Sharpe Ratio ', metrics.annualized_sharpe_ratio())
    print('Calmar Ratio ', metrics.calmar_ratio())
    print('Sortino Ratio ', metrics.sortino_ratio())
    print('Max Draw Down ', metrics.max_draw_down())
    print('Volatility ', metrics.annualized_volatility())
    print('Beta ', metrics.beta(dji))

Код также можно найти здесь.

Вывод выглядит следующим образом

Sharpe Ratio  1.35
Calmar Ratio  2.4
Sortino Ratio  2.21
Max Draw Down  -16.94
Volatility  26.43
Beta  0.41