可变性加权回报率(或 VWR)
原文: https://www.backtrader.com/blog/posts/2016-09-06-vwr/vwr/
根据改进的SharpeRatio 的一些提示,backtrader将这台分析仪添加到了它的武器库中。
文献载于:
从对数回报的好处开始,接着是在 Shaperatio 方程分母中使用标准偏差的副作用,本文件开发了分析仪的公式和期望值。
最重要的特性之一可能是:
- 跨时间段的一致值
SharpeRatio
使用超额收益与无风险利率/资产的算术平均值除以超额收益与无风险利率/资产的标准偏差。这使得最终值取决于样本数量和标准偏差,甚至可能是0
。在这种情况下,SharpeRatio
将是无限的。
反向交易者包括一个样本,用于使用样本数据测试SharpeRatio
,样本数据包括2005
和2006
的价格。不同时间段的返回值:
-
TimeFrame.Years
:11.6473
-
TimeFrame.Months
:0.5425
-
TimeFrame.Weeks
:0.457
-
TimeFrame.Days
:0.4274
笔记
为了保持一致性,该比率是按年计算的。sharpe-timereturn
样本,通过以下方式执行:
--annualize --timeframe xxx
其中xxx
代表days
、weeks
、months
或years
(默认值)
在这个示例中,有一点是明确的:
- 时间段越小,
SharpeRatio
的值越小
这是由于较小的时间段中样本数量较大,增加了变异性,从而增加了标准偏差,这是SharpeRatio
方程中的分母。
对标准偏差的变化有大的敏感性
这正是VWR
试图通过在时间段上提供一致的值来解决的问题。相同的策略具有以下价值:
-
TimeFrame.Years
:1.5368
-
TimeFrame.Months
:1.5163
-
TimeFrame.Weeks
:1.5383
-
TimeFrame.Days
:1.5221
笔记
VWR
始终以年度形式返回(参考文献)。该样本是通过以下方式执行的:
--timeframe xxx
其中xxx
代表days
、weeks
、months
或years
默认为None
,使用days
数据的基础时间段
一致性值表明,在提供一致回报方面,可以在任何时间范围内评估战略的绩效。
笔记
理论上,这些值应该相同,但这需要将tann
参数(年化周期数)微调到准确的交易周期。这里并没有这样做,因为目的只是看一致性。
结论
用户可以使用一种新工具,该工具提供了一种与时间无关的策略评估方法
样本使用
$ ./vwr.py --help
usage: vwr.py [-h] [--data DATA] [--cash CASH] [--fromdate FROMDATE]
[--todate TODATE] [--writercsv]
[--tframe {weeks,months,days,years}] [--sigma-max SIGMA_MAX]
[--tau TAU] [--tann TANN] [--stddev-sample] [--plot [kwargs]]
TimeReturns and VWR
optional arguments:
-h, --help show this help message and exit
--data DATA, -d DATA data to add to the system (default:
../../datas/2005-2006-day-001.txt)
--cash CASH Starting Cash (default: None)
--fromdate FROMDATE, -f FROMDATE
Starting date in YYYY-MM-DD format (default: None)
--todate TODATE, -t TODATE
Starting date in YYYY-MM-DD format (default: None)
--writercsv, -wcsv Tell the writer to produce a csv stream (default:
False)
--tframe {weeks,months,days,years}, --timeframe {weeks,months,days,years}
TimeFrame for the Returns/Sharpe calculations
(default: None)
--sigma-max SIGMA_MAX
VWR Sigma Max (default: None)
--tau TAU VWR tau factor (default: None)
--tann TANN Annualization factor (default: None)
--stddev-sample Consider Bessels correction for stddeviation (default:
False)
--plot [kwargs], -p [kwargs]
Plot the read data applying any kwargs passed For
example: --plot style="candle" (to plot candles)
(default: None)
示例代码
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import argparse
import datetime
import backtrader as bt
TFRAMES = dict(
days=bt.TimeFrame.Days,
weeks=bt.TimeFrame.Weeks,
months=bt.TimeFrame.Months,
years=bt.TimeFrame.Years)
def runstrat(pargs=None):
args = parse_args(pargs)
# Create a cerebro
cerebro = bt.Cerebro()
if args.cash is not None:
cerebro.broker.set_cash(args.cash)
dkwargs = dict()
# Get the dates from the args
if args.fromdate is not None:
fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d')
dkwargs['fromdate'] = fromdate
if args.todate is not None:
todate = datetime.datetime.strptime(args.todate, '%Y-%m-%d')
dkwargs['todate'] = todate
# Create the 1st data
data = bt.feeds.BacktraderCSVData(dataname=args.data, **dkwargs)
cerebro.adddata(data) # Add the data to cerebro
cerebro.addstrategy(bt.strategies.SMA_CrossOver) # Add the strategy
lrkwargs = dict()
if args.tframe is not None:
lrkwargs['timeframe'] = TFRAMES[args.tframe]
if args.tann is not None:
lrkwargs['tann'] = args.tann
cerebro.addanalyzer(bt.analyzers.Returns, **lrkwargs) # Returns
vwrkwargs = dict()
if args.tframe is not None:
vwrkwargs['timeframe'] = TFRAMES[args.tframe]
if args.tann is not None:
vwrkwargs['tann'] = args.tann
if args.sigma_max is not None:
vwrkwargs['sigma_max'] = args.sigma_max
if args.tau is not None:
vwrkwargs['tau'] = args.tau
cerebro.addanalyzer(bt.analyzers.VWR, **vwrkwargs) # VWR Analyzer
# Add a writer to get output
cerebro.addwriter(bt.WriterFile, csv=args.writercsv, rounding=4)
cerebro.run() # And run it
# Plot if requested
if args.plot:
pkwargs = dict(style='bar')
if args.plot is not True: # evals to True but is not True
npkwargs = eval('dict(' + args.plot + ')') # args were passed
pkwargs.update(npkwargs)
cerebro.plot(**pkwargs)
def parse_args(pargs=None):
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description='TimeReturns and SharpeRatio')
parser.add_argument('--data', '-d',
default='../../datas/2005-2006-day-001.txt',
help='data to add to the system')
parser.add_argument('--cash', default=None, type=float, required=False,
help='Starting Cash')
parser.add_argument('--fromdate', '-f',
default=None,
help='Starting date in YYYY-MM-DD format')
parser.add_argument('--todate', '-t',
default=None,
help='Starting date in YYYY-MM-DD format')
parser.add_argument('--writercsv', '-wcsv', action='store_true',
help='Tell the writer to produce a csv stream')
parser.add_argument('--tframe', '--timeframe', default=None,
required=False, choices=TFRAMES.keys(),
help='TimeFrame for the Returns/Sharpe calculations')
parser.add_argument('--sigma-max', required=False, action='store',
type=float, default=None,
help='VWR Sigma Max')
parser.add_argument('--tau', required=False, action='store',
type=float, default=None,
help='VWR tau factor')
parser.add_argument('--tann', required=False, action='store',
type=float, default=None,
help=('Annualization factor'))
parser.add_argument('--stddev-sample', required=False, action='store_true',
help='Consider Bessels correction for stddeviation')
# Plot options
parser.add_argument('--plot', '-p', nargs='?', required=False,
metavar='kwargs', const=True,
help=('Plot the read data applying any kwargs passed\n'
'\n'
'For example:\n'
'\n'
' --plot style="candle" (to plot candles)\n'))
if pargs is not None:
return parser.parse_args(pargs)
return parser.parse_args()
if __name__ == '__main__':
runstrat()