事件回测的最大好处是基本上可以避免未来函数的出现。
代码如下:
3 | from __future__ import division |
11 | data = ts.get_hist_data( "510050" ,start= "2017-01-01" , end = "2017-09-08" ) |
12 | data = data.sort_values( "date" ) |
14 | df[ 'close' ] = data[ 'close' ] |
15 | df[ 'change' ] = df[ 'close' ]- df[ 'close' ].shift(1) |
16 | df = df.dropna() #将带有Na的去掉,返回一个新的对像 |
18 | close5_array = np.zeros(5) #缓存过去5天收盘价 |
19 | close20_array = np.zeros(20) |
20 | last_signal = 0 #最近交易信号,初始化为0。因为双均线策略要使用前一天的收盘价,就需要将信号缓存下来,第2天计算仓位的时候使用 |
21 | last_pos = 0 #最近的持仓,初始化为0 |
32 | self.last_pos = 0 #昨日持仓 |
38 | def calculate(self, date ,close,change, last_signal, last_pos): |
44 | self.pos = last_signal |
45 | self.last_pos = last_pos |
48 | self.pnl = self.change * self.pos |
49 | self.fee = abs (self.pos-self.last_pos) * 1.5/10000 |
50 | self.net_pnl = self.pnl - self.fee |
53 | #iterrows生成迭代器,enumerate在迭代过程中返回当前的变量的计数情况。df刚好有 date , close, change三列。叠代过程中会以tuple的形式返回每一行,其中的第一个元素是日期,第二个元素是数值段。 |
54 | for i, row in enumerate(df.iterrows()): |
56 | close =row[1][ 'close' ] |
57 | change = row[1][ 'change' ] |
60 | close5_array[0:4] = close5_array[1:5] |
61 | close20_array[0:19] = close20_array[1:20] |
64 | close5_array[-1] = close |
65 | close20_array[-1] = close |
67 | #如果尚未有20个数据点的缓存数量,则不执行后续逻辑 |
73 | dr.calculate( date , close, change, last_signal,last_pos) |
81 | ma5 = close5_array.mean() |
82 | ma20 = close20_array.mean() |
89 | result_df = pd.DataFrame() |
90 | result_df[ 'net_pnl' ] = [dr.net_pnl for dr in dr_list] #将dailyresult列表中的数据转换为pandas的dataframe |
91 | result_df.index = [dr. date for dr in dr_list] #添加日期索引 |
93 | result_df[ 'cum_pnl' ] = result_df[ 'net_pnl' ].cumsum() #累积求和 |
94 | result_df[ 'cum_pnl' ].plot() |
在jupyter运行结果如下:
