量化投资学习笔记140——股票实盘练习31——验证回测指标计算

最近实现了几个策略,回测结果都不太理想。会不会是我的回测程序有问题?于是我想验证一下。

先还是用各种库,发现结果各不相同。最后我决定先自己手算一遍吧。

先自己造个数据:

1
2
3
4
5
    date = pd.date_range("1/1/2021", "1/10/2021")

    priceA = [1.0, 1.1, 1.2, 1.3, 0.5, 0.8, 0.4, 0.6, 1.0, 1.2]

    priceB = [1.0, 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09]

日期为2021年1月1日至10日,共10天。

priceA是股价数据,priceB是基准数据。在第一天投入1.0元,开盘买入然后持有。故意造了中间有回撤。

然后计算每天的收益率数据序列,即比较每天和上一天的市值增长率。

1
2
3
retA = [0.0, 0.1, 0.0909, 0.0833, -0.6154, 0.6, -0.5, 0.5, 0.6667, 0.2]

retB = [0.0, 0.01, 0.0099, 0.0098, 0.0097, 0.0096, 0.0095, 0.0094, 0.0093, 0.0093]

用程序算一下

1
2
3
    data_ret = data.收盘.pct_change().fillna(0).tz_localize(None)

    bench_ret = bench.收盘.pct_change().fillna(0).tz_localize(None)

一样的。再传到回测框架里跑一遍,输出收益率数据,结果是一样的。注意要在cerobro初始化时设定cheat_on_open = True,因为backtrader一般是在下单后第二天执行交易的,如此设置就能在第一天买入。

证明backtrader里的bt.analyzers.TimeReturn记录的是每日收益率。

基础有了,下面开始计算其它回测指标。

参考这里

1.计算累积收益率

期末价格减去期初价格,再除以期初价格。

RcA = (1.2-1.0)/1.0 = 0.2

RcB = (1.09-1.0)/1.0 = 0.09

用程序算一下

累积收益率 0.19999999999999996 0.09000000000000008

一样的。

2.年化收益率

R是计算周期内的累积收益,m为天数,年化为250,n为周期的天数。

用程序算一下:

年化收益率 94.39621664406893 7.623080660403197

跟回测框架的数据算的不一样啊。先摆着吧。

3.最大回撤

在选定周期内任一历史时点往后推,于最低点时的收益率回撤幅度的最大值。最大回撤用来描述可能出现的最糟糕的情况。

i,j为周期中两个时间点,其中j晚于i。

先手算一下:

每个时间点的最大回测值

1
2
3
4
5
priceA = [1.0, 1.1, 1.2, 1.3, 0.5, 0.8, 0.4, 0.6, 1.0, 1.2]

MD_A = [-0.6, -0.6364, -0.6667, -0.6923, -0.2, -0.5, 0, 0, 0, 0]

MD_B = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

最大回撤值

MDA = -0.6923

MDB = 0

用程序算一遍,使用pandas的cummax。

最大回撤: 0.6923076923076923 0.0

用BackTrader框架回测的值也一样。

一样的。

4.Alpha和Beta值

Beta:相当于业绩评价基准收益的总体波动性。

Pi,Pm为个股和基准的收益率序列。Cov为二者协方差。Varm为基准每日收益的方差。

意义:如果值为1,策略波动与基准一致,如果大于1,策略波动大于基准,如果小于1,策略波动小于基准。

先按这个公式计算一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    # 计算β值

    # covAB = np.cov(data_ret, bench_ret)

    covAB = data_ret.cov(bench_ret)

    print("协方差", covAB)

    varB = np.var(bench_ret)

    beta = covAB/varB

    print("策略β值:", beta)

策略β值: 10.64411952517551

框架回测的beta值是9.579708,是用empyrical库算的。先摆着,完了再调。

Alpha:实际收益和按照Beta系数计算的期望收益之间的差额。代表策略多大程度上跑赢了预期的收益率。

可以使用资本资产定价模型(CAPM)来估计策略的beta和alpha的值。

E(ri)是股票i的预期收益率,rf是无风险利率,rm是市场指数收益率。Alpha可以理解为超额收益率。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    # 计算α值

    x = data_ret.values

    y = bench_ret.values

    b, a, r_value, p_value, std_err = stats.linregress(x, y)

    alpha = round(a*250, 4)

    beta = round(b, 4)

    print("α:", alpha, "β:", beta)

结果:α: 2.1509 β: 0.0005

跟回测框架的结果不一样,跟上面的计算结果也不一样……

5.夏普比率

代表每多承担一份风险,可以获得几份回报,即单位风险所获得的超额回报,该比率越高,策略承担单位风险得到的超额回报越高,所以夏普比率越高越好。

Rp是策略年化收益率,Rf为无风险收益率,σp为年化标准差。

1
2
3
4
5
6
7
8
9
10
11
    rf = 0.03

    exReturn = data_ret - rf/250.0

    sharpe = np.sqrt(len(exReturn)) * exReturn.mean() / exReturn.std()

    print("夏普比率:", sharpe)

结果:

夏普比率: 0.8375901064767365

又跟回测框架的值差很多。

6.信息比率

含义与夏普比率类似,用市场基准代替无风险收益率计算。

其中σt为策略与基准每日收益率差值的年化标准差。

1
2
3
4
5
6
7
8
9
    ex_return = data_ret - bench_ret

    information = np.sqrt(len(ex_return)) * ex_return.mean() / ex_return.std()

    print("信息比率:", information)

结果

信息比率: 0.7743390915190407

现在指标计算完了,自己算的跟框架算的差异很大。调试下看看。

从输出的数据看,收益率序列是一致的,累积收益率,最大回撤也是一致的。不一致的主要是年化收益率,以及那些风险指标。

折腾半天,终于看起来是对了,其实问题主要是计算的时候除以n还是n-1,以及进行年化转换时一年交易天数设置的问题。另外还发现在画图的时候还可以把benchmark收益率数据也加进去。现在看起来是对了。

接着把代码重构一下,以后就可以放心用了。

代码

实盘,今天涨了3分钱,不动。

声明:本文为个人学习记录,不构成投资建议!股市有风险,入市需谨慎!

我发文章的三个地方,欢迎大家在朋友圈等地方分享,欢迎点“在看”。

我的个人博客地址:https://zwdnet.github.io

我的知乎文章地址: https://www.zhihu.com/people/zhao-you-min/posts

我的微信个人订阅号:赵瑜敏的口腔医学学习园地

欢迎打赏!感谢支持!