本模块为量化策略回测框架中的指标系统,该模块用于衡量策略表现,现可支持如下指标:
表 1:回测系统策略表现衡量指标及说明
指标名称 | 代码指标 | 指标含义说明 |
---|---|---|
年化收益率 | Return | 策略的年化收益率 |
年化波动率 | Sigma | 策略的年化波动率 |
收益-风险比 | R/S | 策略年化收益率:策略年化波动率 |
偏度 | Skew | 策略收益率序列的偏度 |
峰度 | Kurt | 策略收益率序列的峰度 |
最大回撤 | MDD | 策略净值序列的最大回撤值 |
最大回撤比率 | MDD_R | 策略净值序列的的最大回撤比率 |
最大回撤周期 | MDD_P | 策略净值序列的的最大回撤周期长度 |
在险价值 | VaR | 策略最坏条件下的损失情况 |
条件在险价值 | CVaR | 策略最坏条件下的平均损失 |
策略赢率 | Odd | 策略正收益天数-负收益天数比率 |
下行风险(半方差) | DR | 低于平均收益率与均值的均方和 |
夏普比率 | SR | 策略单位波动率上的收益率 |
詹森Alpha | Alpha | 策略收益率无法由市场风险解释的收益 |
系统性风险 | Beta | 策略收益率在市场风险中的暴露敞口 |
特雷诺比率 | TR | 策略单位系统风险上的收益率 |
注:本模块会随着需求而升级换代。现在的版本为0.0.2,最后更新时间:5/29/2020
0.0.1 版功能更新
该版本为原始版本。发布时间5/18/2020.
0.0.2 版功能更新
发布时间:5/29/2020
(1)加入Performance模块,加入更多指标
(2)修改了CVaR模块算法的bug
(3)收益序列和净值序列暂时仅支持二维list类型输入,暂不支持DataFrame格式,会在下一版本进行更新==
# -*- coding: utf-8 -*-
# author: Mikey_Sun time: 5/16/2020
# all copyright belongs to the author. NO COPY ALLOWED.
import numpy as np
import pandas as pd
import math
from scipy import stats
##################################
##### Module 0: 更新版本说明 ######
##################################
def print_version():
version = '0.0.2'
print("现在版本为:{}".format{version})
#########################################
##### Module 1: 名称、格式相关的内嵌模块 ####
#########################################
# 1. 设置策略名称(若收益序列为DataFrame格式,则保留该策略名称;否则根据输入顺序命名为“策略x号”)
def set_name(r_series):
columns = []
if type(r_series) == pd.DataFrame:
columns = r_series.columns
else:
for i in range(len(r_series)):
columns.append("策略" + str(i+1) + "号")
return columns
# 2. 设置收益序列的频率
def set_period(Period):
T = 1 # 首先默认参数为年化指标
Period = str(Period).upper()
if Period is 'D' or 'DAY' or 'DAILY': # 日频数据
T = 242
elif Period is 'W' or 'WEEK' or 'WEEKLY': # 周频数据
T = 49
elif Period is 'M' or 'MONTH' or 'MONTHLY': # 月频数据
T = 12
elif Period is 'S' or 'SEASON' or 'SEASONAL' or 'Q' or 'Quarter' or 'Quarterly': # 季频数据
T = 4
elif Period is 'Y' or 'YEAR' or 'YEARLY': # 年化数据
T = 1
else:
pass # 可以进一步拓展
return T
#########################################
## Module 1: 收益率序列一阶至三阶矩计算模块 ##
#########################################
# 1. 矩量名称索引函数(支持一阶、二阶、三阶、四阶矩量)
def Annualized_Moment_indicators():
return ['Return', 'Sigma', 'R/S', 'Skew', 'Kurt']
# 2. 矩量计算函数
def Annualized_Moment(r_series, Period = 'Y', indicators = Annualized_Moment_indicators(), output_type = 'DataFrame'):
"""
计算序列样本矩。矩算法时间复杂度:O(m·n)
:param r_series: 收益率数据,默认格式为pd.DataFrame
:param Period: str格式,输入的收益率数据频率(可以输入:‘D’(日频)、 ‘W’(周频)、 ‘M’(月频)、 ‘S’(季频)、 ‘Y’(年频)。默认收益率序列为年频数据)
:param indicators: list格式,选择输出哪些矩量(可以输入:Annualized_Moment_indicators()函数中的全部指标。默认全部矩量值)
:param output_type: str格式,输出格式(可以输入:'list', 'dataframe'。默认输出格式为 dataframe)
:return: pd.DataFrame
"""
# Step 1: 处理周期输入变量
T = set_period(Period)
# Step 2: 处理序列输入模块
columns = set_name(r_series)
# Step 3: 计算矩变量
r = []
sigma = []
skew = []
kurt = []
R_S = []
for i in range(len(r_series)):
r.append(np.mean(r_series[i]) * T)
sigma.append(np.std(r_series[i]) * math.sqrt(T))
R_S.append(r[i]/sigma[i])
skew.append(stats.skew(r_series[i] * T))
kurt.append(stats.kurtosis(r_series[i] * T))
# Step 4: 返回函数值
outcome = pd.DataFrame({'Return':r, 'Sigma':sigma, 'R/S': R_S, 'Skew':skew, 'Kurt':kurt}, index = columns)[indicators]
if output_type.upper() == 'LIST':
return np.transpose(outcome.values.tolist())
else:
return outcome
#######################################
####### Module 2: 净值序列计算模块 #######
#######################################
# 1. 最大回撤类名称索引函数(支持最大回撤、最大回撤比率和最大回撤长度)
def MDD_indicators():
return ['MDD', 'MDD_R', 'MDD_P']
# 2. 计算一维序列的最大回撤族指标
def MDD_single(nv_series, output = 'All', output_type = 'DataFrame'):
"""
计算最大回撤、最大回撤率与最大回撤周期。算法时间复杂度:O(n)
:param nv_series: list格式,净值序列
:param output: str格式,返回指定指标代码。默认为返回全部指标。
:param output_type: str格式,输出格式(可以输入:'list', 'dataframe'。默认输出格式为 dataframe)
:return:
"""
output = str(output).upper()
# Step 1: 计算回撤指标
start = start_temp = 0 # 最大回撤起始点临时指针
end = end_temp = 0 # 最大回撤结束点临时指针
for i in range(1, len(nv_series)):
if nv_series[i] > nv_series[start_temp]:
start_temp = i
end_temp = i
elif nv_series[i] < nv_series[end_temp]:
end_temp = i
if (nv_series[start_temp] - nv_series[end_temp]) > (nv_series[start] - nv_series[end]):
start = start_temp
end = end_temp
if start == end: #若没有任何回撤
start = end = 0
MDD = nv_series[start] - nv_series[end] #最大回撤
MDD_RATE = (nv_series[start] - nv_series[end]) / nv_series[start] #最大回撤比率
MDD_PERIOD = end - start #最大回撤周期
# Step2: 返回对应的回撤指标
if output == 'MDD':
return MDD
elif output == 'MDD_R':
return MDD_RATE
elif output == 'MDD_P':
return MDD_PERIOD
else:
if output_type.upper() == 'LIST':
return [MDD, MDD_RATE, MDD_PERIOD]
else:
outcome = pd.DataFrame({'MDD':MDD, 'MDD_R': MDD_RATE, 'MDD_P':MDD_PERIOD})
return outcome
# 3. 计算多个净值序列的最大回撤族指标
def MDD(nv_series, indicators=MDD_indicators(), output_type='pd.DataFrame'):
"""
指标计算函数
:param nv_series: 输入的净值序列(既可以是二维list格式,也可以是pd.DataFrame格式)
:param indicators: str格式或list格式,希望输出的风险指标(可以输入MDD_indicators()中的指标,默认为全部输出)
:param output_type: str格式,输出格式(可以输入:'list', 'dataframe'。默认输出格式为 dataframe)
:return: pd.DataFrame
"""
# Step 1: 设置策略名称
columns = set_name(nv_series)
# Step 2: 计算各指标
MDDs = []
for i in range(len(nv_series)):
MDD_i = MDD_single(nv_series[i], output = 'all', output_type = 'list')
MDDs.append(MDD_i)
# Step 3: 设置输出格式
if output_type.upper() == 'LIST':
return MDDs
else:
outcome = pd.DataFrame(MDDs, columns = ['MDD', 'MDD_R', 'MDD_P'], index = columns)[indicators]
return outcome
########################################
####### Module 3: 尾部风险计算模块 #######
########################################
# 1. VaR类指标(支持VaR和CVaR)
def VaR_indicators():
return ['VaR', 'CVaR']
# 2. VaR指标计算
def VaR(r_series, alpha = 0.05, indicators = VaR_indicators(), output_type = 'pd.DataFrame'):
"""
:param r_series: 二维list类型或DataFrame类型。
:param alpha: float类型。设置置信度(默认为0.05)
:param indicators: list格式,选择输出哪些矩量(可以输入:VaR_indicators()函数中的全部指标。默认全部变量)
:param output_type: str格式,输出格式(可以输入:'list', 'dataframe'。默认输出格式为 dataframe)
:return:
"""
# Step 1: 处理序列输入模块
columns = set_name(r_series)
# Step 2: 计算矩变量
VaR = []
CVaR = []
for i in range(len(r_series)):
loc = int(alpha * len(r_series[i])) # 寻找VaR点位置
r_series_sort = np.sort(r_series[i])
VaR.append(np.max([0, -r_series_sort[loc]]))
CVaR.append(np.max([0, -np.mean(r_series_sort[0:(loc+1)])]))
# Step 3: 返回函数值
outcome = pd.DataFrame({'VaR': VaR, 'CVaR': CVaR}, index=columns)[indicators]
if output_type.upper() == 'LIST':
return np.transpose(outcome.values.tolist())
else:
return outcome
########################################
####### Module 4: 其他表现指标模块 #######
########################################
# 1. 一元回归模型(x为因变量,y为自变量,输入变量可以是一维array或一维list)
def SLR(x, y):
"""
:param x: list类型或array类型。自变量。
:param y: list类型或array类型。因变量。
:return: 返回类型为元组
"""
x = list(x)
y = list(y)
n = len(x)
dinominator = 0
numerator = 0
for i in range(n):
numerator += (x[i] - np.mean(x)) * (y[i] - np.mean(y))
dinominator += (x[i] - np.mean(x)) ** 2
beta = numerator / float(dinominator) # 计算斜率项
alpha = np.mean(y) - beta * float(np.mean(x)) # 计算截距项
return (alpha, beta)
# 2. Performance类指标(支持夏普比率SR、下行风险DR、赔率Odd、詹森Alpha、系统风险Beta和特雷诺比率TR)
def Performance_indicators():
return ['Odd', 'DR', 'SR', 'Alpha', 'Beta', 'TR']
# 3. Performance类指标计算模块
def Performance(r_series, rf_series = None, bm_series = None, Period = 'Y', indicators = Performance_indicators(), output_type = 'pd.DataFrame'):
# Step 1: 处理周期输入变量
T = set_period(Period)
# Step 2: 处理序列输入模块
columns = set_name(r_series)
# Step 3: 指标计算
Odd = [] # 组合赔率
DR = [] # 下行风险
SR = [] # 夏普比率 Sharpe Ratio(需要输入无风险利率)
Alpha = [] # 詹森Alpha (需要输入无风险利率和基准收益序列)
Beta = [] # 系统性风险Beta(需要输入无风险利率和基准收益序列)
TR = [] # 策略的特雷诺比率(需要输入无风险利率和基准收益序列)
for i in range(len(r_series)):
# (1)计算策略的赢率
n_win = np.sum(list(map(lambda x: x >= 0, r_series[i])))
n_lose = np.sum(list(map(lambda x: x < 0, r_series[i])))
if n_lose != 0:
Odd.append(n_win/n_lose)
else:
Odd.append(np.inf)
# (2) 计算策略的下行风险
sum = 0
for j in range(len(r_series[i])):
ave = np.mean(r_series[i])
if r_series[i][j] < ave:
sum += (r_series[i][j] - ave)**2
DR.append(np.sqrt(sum/(len(r_series[i])-1)) * np.sqrt(T))
# (3)计算策略的夏普比率
if r_series is not None:
rf = np.mean(rf_series)
SR.append((np.mean(r_series[i]) - rf) / np.std(r_series[i]) * np.sqrt(T))
# (4) 计算策略的系统风险beta和詹森alpha:
if bm_series is not None:
alpha, beta = SLR(np.array(bm_series) - rf, np.array(r_series[i]) - rf)
Alpha.append(alpha)
Beta.append(beta)
# (5) 计算策略的特雷诺比率
TR.append((np.mean(r_series[i]) - rf) / beta * T)
# Step 4: 返回函数值
if rf_series is not None and bm_series is not None:
outcome = pd.DataFrame({'Odd': Odd, 'DR': DR, 'SR': SR, 'Alpha': Alpha, 'Beta': Beta, 'TR': TR}, index=columns)[indicators]
elif rf_series is not None and bm_series is None:
ids = [id for id in indicators if id in ['Odd', 'DR', 'SR']]
outcome = pd.DataFrame({'Odd': Odd, 'DR': DR, 'SR': SR}, index=columns)[ids]
else:
ids = [id for id in indicators if id in ['Odd', 'DR']]
outcome = pd.DataFrame({'Odd': Odd, 'DR': DR}, index=columns)[ids]
if output_type.upper() == 'LIST':
return np.transpose(outcome.values.tolist())
else:
return outcome
##############################
## Module 5: 汇总输出计算模块 ##
##############################
# 1. 风险指标汇总输出
def Risk_Indicators(r_series, nv_series, rf_series = None, bm_series = None, Period = 'Y', Indicators = 'All', alpha = 0.05, output_type = 'pd.DataFrame'):
# Step 1: 计算全部风险指标
Risks = pd.concat([Annualized_Moment(r_series, Period = Period),
MDD(nv_series),
VaR(r_series, alpha = alpha),
Performance(r_series, rf_series = rf_series, bm_series = bm_series, Period = Period)], axis=1)
# Step 2: 找到对应的风险指标
# 若为“ALL”指令,则把库函数中设置的全部风险指标全部打印出来
if type(Indicators) == str and Indicators.upper() == 'ALL':
pass
# 若为指标集,则应从指标库中找出对应的风险指标,剔除不存在的指标(剔除的指标以warning形式输出)
else:
Indicators_Moment = [indicator for indicator in Indicators if indicator in Annualized_Moment_indicators()]
Indicators_MDD = [indicator for indicator in Indicators if indicator in MDD_indicators()]
Indicators_VaR = [indicator for indicator in Indicators if indicator in VaR_indicators()]
Indicators_Performance = [indicator for indicator in Indicators if indicator in Performance_indicators()]
Indicators_All = Indicators_Moment + Indicators_MDD + Indicators_VaR + Indicators_Performance
Risks = Risks[Indicators_All]
output_type = str(output_type)
# Step 3: 按给定输出格式
if output_type.upper() == 'LIST': # 以list格式输出
return np.transpose(Risks.value.tolist())
else: # 否则,以默认格式输出。默认格式为pd.DataFrame
return Risks
####### Test Run ########
def test():
r_series = [[0.012, 0.032, -0.04, -0.013, -0.034, 0.0045, 0.002, 0.023, 0, 0, 0, 0, 0],
[0.012, 0.032, -0.04, -0.013, -0.034, 0.0045, 0.002, 0.023, 0, 0, 0, 0, 0]]
#r_series = pd.DataFrame(np.transpose(r_series), columns=['纯股策略', '纯债策略'])
nv_series = [[1, 1.1, 1.21, 1.3, 1.2, 1.1, 1.12, 1.13, 1.08, 1.06],
[1, 1.01, 1.021, 1.03, 1.02, 1.01, 1.012, 1.013, 1.008, 1.006]]
rf = 0.0008
bm_series = [0.012, 0.032, -0.04, -0.013, -0.034, 0.0045, 0.002, 0.023, 0, 0, 0, 0, 0]
Period = 'D'
Indicators = 'ALL'
alpha = 0.05
output_type = 'DataFrame'
Risks = Risk_Indicators(r_series, nv_series, rf_series=rf, bm_series=bm_series, Period=Period,
Indicators=Indicators, alpha=alpha, output_type=output_type)
# 打印风险值情况
print(Risks[Risks.columns[:5]])
print(Risks[Risks.columns[5:10]])
print(Risks[Risks.columns[10:]])
#test()
本文所附代码为作者原创,版权归作者所有,未经允许或授权不得转载或用于商业用途。