【基于python的量化策略回测框架搭建】策略表现衡量指标模块

1. 代码模块用途说明

本模块为量化策略回测框架中的指标系统,该模块用于衡量策略表现,现可支持如下指标:

表 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格式,会在下一版本进行更新==


2. 代码块

# -*- 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()

版权声明

本文所附代码为作者原创,版权归作者所有,未经允许或授权不得转载或用于商业用途。

你可能感兴趣的:(Python,量化回测系统)