程式
如何使用 Python 從加權投資組合中計算 Sortino 比率?
在這個工作範例中,我能夠從 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 ),這兩個結果之間存在細微偏差,這可能是由於語言之間使用的基於精度的值不同。不過,我希望這對您的實施有所幫助。