pybacktest 教程
本教程让你快速了解 pybacktest's 的功能。为此,我们回测精典交易策略移动平均线MA交叉。
- MA快线上穿慢线时,买进做多
- MA快线下穿慢线时,卖出做空
- 进场规则,也是退场规则,交易策略相反相成
软件包在此下载 https://github.com/ematvey/pybacktest
import pybacktest
import pandas as pd
pybacktest 要求的 k 线数据格式为 pandas.DataFrame
,以时间戳为索引,各列字段名称为 O
, H
, L
, C。实际上,目前只检查字段O的值是否为空。
从yahoo下载数据。
ohlc = pybacktest.load_from_yahoo('SPY')
ohlc.tail()
O | H | L | C | V | AC | |
---|---|---|---|---|---|---|
Date | ||||||
2013-04-22 | 155.78 | 156.54 | 154.75 | 156.17 | 106501600 | 156.17 |
2013-04-23 | 156.95 | 157.93 | 156.17 | 157.78 | 165950600 | 157.78 |
2013-04-24 | 157.83 | 158.30 | 157.54 | 157.88 | 96724000 | 157.88 |
2013-04-25 | 158.34 | 159.27 | 158.10 | 158.52 | 130916000 | 158.52 |
2013-04-26 | 158.33 | 158.60 | 157.73 | 158.24 | 95904500 | 158.24 |
定义交易策略。要创建以 True和False 表示交易信号的 Series
,和以浮点数表示交易价格的 Series。
够简单的吧?
short_ma = 50
long_ma = 200
ms = pandas.rolling_mean(ohlc.C, short_ma)
ml = pandas.rolling_mean(ohlc.C, long_ma)
buy = cover = (ms > ml) & (ms.shift() < ml.shift()) # ma cross up
sell = short = (ms < ml) & (ms.shift() > ml.shift()) # ma cross down
print '> Short MA\n%s\n' % ms.tail()
print '> Long MA\n%s\n' % ml.tail()
print '> Buy/Cover signals\n%s\n' % buy.tail()
print '> Short/Sell signals\n%s\n' % sell.tail()
> Short MA Date 2013-04-22 154.5438 2013-04-23 154.6634 2013-04-24 154.7856 2013-04-25 154.9156 2013-04-26 155.0374 > Long MA Date 2013-04-22 145.50725 2013-04-23 145.60910 2013-04-24 145.71455 2013-04-25 145.82970 2013-04-26 145.94430 > Buy/Cover signals Date 2013-04-22 False 2013-04-23 False 2013-04-24 False 2013-04-25 False 2013-04-26 False > Short/Sell signals Date 2013-04-22 False 2013-04-23 False 2013-04-24 False 2013-04-25 False 2013-04-26 False
开始回测吧。访问类对象 Backtest
的第一个参数,是从字典式的对象中剥离出的交易信号、价格等。可以是字典、pandas.DataFrame 或者其他任何东西。
为了简化编程,把局部命名空间用函数 locals()传递过去。命名空间的内容,是至今你所创建的全部变量
。
bt = pybacktest.Backtest(locals(), 'ma_cross')
Backtest
工作懒惰,只有在你访问它的属性时,它才会进行运算。它所运算的属性包括:
print filter(lambda x: not x.startswith('_'), dir(bt))
print '\n> bt.signals\n%s' % bt.signals.tail()
print '\n> bt.trades\n%s' % bt.trades.tail()
print '\n> bt.positions\n%s' % bt.positions.tail()
print '\n> bt.equity\n%s' % bt.equity.tail()
print '\n> bt.trade_price\n%s' % bt.trade_price.tail()
['dataobj', 'default_price', 'eqplot', 'equity', 'name', 'ohlc', 'plot_equity', 'plot_trades', 'positions', 'prices', 'report', 'run_time', 'signals', 'sigplot', 'summary', 'trade_price', 'trades', 'trdplot']
> bt.signals Buy Cover Sell Short Date 2013-04-22 False False False False 2013-04-23 False False False False 2013-04-24 False False False False 2013-04-25 False False False False 2013-04-26 False False False False > bt.trades pos price vol Date 2009-06-23 1 90.16 2 2010-07-06 -1 103.13 -2 2010-10-22 1 119.14 2 2011-08-12 -1 119.19 -2 2012-01-31 1 132.29 2 > bt.positions Date 2009-06-23 1 2010-07-06 -1 2010-10-22 1 2011-08-12 -1 2012-01-31 1 > bt.equity Date 2009-06-23 58.66 2010-07-06 12.97 2010-10-22 -16.01 2011-08-12 0.05 2012-01-31 -13.10 > bt.trade_price Date 2013-04-22 156.95 2013-04-23 157.83 2013-04-24 158.34 2013-04-25 158.33 2013-04-26 NaN Name: O
调用 Backtest 的函数summary ,可以得知常用的运算和运行数据
bt.summary()
Backtest('ma_cross', 2013-28-04 23:14:15 MSK) performance summary
================================================================= backtest: days: 6348 from: '1994-09-14 00:00:00' to: '2012-01-31 00:00:00' trades: 17 exposure: holding periods: max: 1476 days, 0:00:00 median: 354 days, 0:00:00 min: 7 days, 0:00:00 trades/month: 1.0625 performance: PF: 4.017 RF: 6.1555 averages: gain: 23.817 loss: -8.47 trade: 10.5224 payoff: 2.8119 profit: 178.88 winrate: 0.5882 risk/return profile: UPI: 1.0656 WCDD (monte-carlo 0.99 quantile): 52.09 maxdd: 74.67 sharpe: 0.4485 sortino: 1.6792 -----------------------------------------------------------------
看看净资产曲线吧。
figsize(10, 5)
bt.plot_equity()
回测运行过程中的精确图形,Backtest 可以为你画出。图中的说明 Legend 省略了,以节省空间。
bt.plot_trades()
pandas.rolling_mean(ohlc.C, short_ma).plot(c='green')
pandas.rolling_mean(ohlc.C, long_ma).plot(c='blue')
legend(loc='upper left')
<matplotlib.legend.Legend at 0x49eea10>
你能完全看清吗?我不行。因此,有个特别属性 trdplot
,让你用pandas的索引机制,指定你要画出的期间。而用属性 eqplot,可以画出净资产曲线。
bt.trdplot['2004':'2007']
pandas.rolling_mean(ohlc.C['2004':'2007'], short_ma).plot(c='green')
pandas.rolling_mean(ohlc.C['2004':'2007'], long_ma).plot(c='blue')
<matplotlib.axes.AxesSubplot at 0x7f7f38c09e50>
以上是pybacktest的大部分内容。下一个教程,会涉及更多高级功能。