程式

如何使用 Python 從加權投資組合中計算 Sortino 比率?

  • October 29, 2021

在這個工作範例中,我能夠從 3 種證券的加權投資組合中計算夏普比率(rf=0),但是如何修改下面的程式碼以計算索蒂諾比率?

import numpy as np
from pandas_datareader import data

tickers = ['AAPL', 'MSFT', '^GSPC']
start_date = '2010-01-01'
end_date = '2016-12-31'

weights = [1/3, 1/3, 1/3]

# Fetch data
df = data.DataReader(tickers, 'yahoo', start_date, end_date)['Close']

# Calculate historical returns
returns = df.pct_change(1).dropna()

# Weighted mean returns
exp_rets = returns.mean()
mean = sum(exp_rets * weights)

# Standard deviation
var = np.dot(np.dot(weights, returns.cov()), weights)

# Sharp ratio
sr = mean / np.sqrt(var)

print(sr)
0.054270779230564975

Python 中的 Sortino 系統:

經過我自己的盡職調查,我發現了一篇描述Sortino ratio 公式的論文,它遵循與之前評論中描述的此連結相同的設置。對於釀造,Sortino 比率的公式可以指定為:

$$ S = \frac{R - T}{TDD} $$

在哪裡 $ R $ 是平均期間回報率和 $ T $ 是目標回報(也稱為平均可接受回報,MAR)。而且,

$$ TDD = \sqrt{\frac{1}{N}\sum_{i=1}^N \min\left(0, X_i - T\right)^2} $$

表示目標下行偏差,其中 $ X_i $ 作為 $ i $ 第一次回來。使用上面的公式,我們可以在 Python 中計算 Sortino 比率。忽略上面程式碼的第一部分(定義權重、獲取股票數據等),我們可以使用以下函式計算 Sortino 比率:

def SortinoRatio(df, T):
   """Calculates the Sortino ratio from univariate excess returns.


   Args:
       df ([float]): The dataframe or pandas series of univariate excess returns.
       T ([integer]): The targeted return. 
   """

   #downside deviation:

   temp = np.minimum(0, df - T)**2
   temp_expectation = np.mean(temp)
   downside_dev = np.sqrt(temp_expectation)

   #Sortino ratio:

   sortino_ratio = np.mean(df - T) / downside_dev

   return(sortino_ratio)

您現在可以建構投資組合回報,定義您指定的目標回報 $ T $ 並將這些輸入到函式中:

#portfolio returns:
port_ret = returns.dot(weights)

#-------------------output:-----------------------
print(np.round(SortinoRatio(port_ret, T = 0),4))
0.0782

這導致 Sortino 比率為 0.0782。

確認:

驗證上述功能的一個好方法是從“受人尊敬的”來源中找到一個已經實現的功能。在這裡,PerformanceAnalytics包 fromR包含一個計算 Sortino 比率的函式。在數據框的前 10 行(稱為 ret)上使用此函式,我們得到以下資訊:

#R code:
ret <- matrix( 
c(0.001729,  0.000323,  0.003116,
-0.015906, -0.006137,  0.000546,
-0.001849, -0.010400,  0.004001,
0.006648,  0.006897,  0.002882,
-0.008821, -0.012720,  0.001747,
-0.011375, -0.006607, -0.009381,
0.014106,  0.009312,  0.008326,
-0.005792,  0.020099,  0.002426,
-0.016712, -0.003230, -0.010823,
0.044238, 0.007777, 0.012500), nrow = 10, ncol = 3, byrow = TRUE)

weights <- c(1/3, 1/3, 1/3)

portret <- as.xts(ret %*% weights, order.by = as.Date(1:10))

#-------------------output:-----------------------
round(SortinoRatio(portret, MAR = 0), 4)
                          [,1]
> Sortino Ratio (MAR = 0%) 0.1664

在這裡,Python 中的函式給出了相同的結果(更高的小數點略有不同):

return_test = returns.head(10)@weights

#-------------------output:-----------------------
print(np.round(SortinoRatio(return_test, T = 0),4))
0.1664

對於更多小數點 ( >5 ),這兩個結果之間存在細微偏差,這可能是由於語言之間使用的基於精度的值不同。不過,我希望這對您的實施有所幫助

引用自:https://quant.stackexchange.com/questions/68556