"""导入常用模块"""import numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport datetimefrom environment import * # 导入大树工作室开发的回测模块
import talib as tlfrom functools import reduce# SMA计算函数def SMA(close, timeperiod) :close = np.nan_to_num(close)return reduce(lambda x, y: ((timeperiod - 1) * x y) / timeperiod, close)# KDJ计算函数def KDJ(high, low, close, fastk_period, slowk_period, fastd_period) :kValue, dValue = tl.STOCHF(high, low, close, fastk_period, fastd_period=1, fastd_matype=0) kValue = np.array(list(map(lambda x : SMA(kValue[:x], slowk_period), range(1, len(kValue) 1)))) dValue = np.array(list(map(lambda x : SMA(kValue[:x], fastd_period), range(1, len(kValue) 1)))) jValue = 3 * kValue - 2 * dValue func = lambda arr : np.array([0 if x < 0 else (100 if x > 100 else x) for x in arr]) kValue = func(kValue) dValue = func(dValue) jValue = func(jValue)return kValue, dValue, jValue# 获取某标的的KDJ信息def get_kdj(stock, count, end_date, unit):data = get_bars(security=stock, count=count, unit=unit, include_now=False, end_dt=end_date, fq_ref_date=None) close = data['close'] open = data['open'] high = data['high'] low = data['low']return KDJ(high, low, close, 9, 3, 3)
KDJ是一种摆动指标,20与80的位置是我们对当前超买超卖状态的最基本判断。接下来的择时条件如下:
当D线处于20位置以下时,买进;
当D线处于80位置以上时,卖出;
另外,20与80的位置并不是硬性指标,我们可以为其指定一个浮动范围;我们将这个范围N值定在1%~9%之间,然后做回测,并查看其结果。
trade_list = [] N =[n/100 for n in range(1, 10)]for n in N:"""初始化以下内容"""context = Context() # 账户对象order = Order(context) # 下单对象trade = Trade(context, order) # 回测对旬context.start_date = '2005-05-01'context.end_date = '2019-02-22'context.universe = ['000300.XSHG'] context.base = '000300.XSHG'"""策略主体"""def handle(context, order):stock = context.universe[0] current_date = trade.context.current_dt kdj_day = get_kdj(stock, 30, current_date, '1d') line_bottm = 20 * (1 n) line_top = 80 * (1-n) k1 = kdj_day[0][-1] d1 = kdj_day[1][-1] j1 = kdj_day[2][-1] k2 = kdj_day[0][-2] d2 = kdj_day[1][-2] j2 = kdj_day[2][-2] close = get_price(security=stock, end_date=context.current_dt, frequency='daily', fields=None, skip_paused=False, fq='pre', count=5)['close']if d2 > line_bottm and d1 < line_bottm :if stock in context.position.keys():returnorder.buy(stock, close[-1], context.cash // close[-1])elif d2 < line_top and d1 > line_top:if stock not in context.position.keys():returnorder.sell(stock, close[-1], context.position[stock]['count'])"""执行策略"""trade.trade(handle, show=False, log=True) trade_list.append(trade)# 展示Trade.show_ratio_compare('n', N, trade_list, 3, 3)
End Time : 2019-03-10 16:01:27.192853, Elapsed Time: 0:00:18.351210End Time : 2019-03-10 16:01:45.031913, Elapsed Time: 0:00:17.838861End Time : 2019-03-10 16:02:02.843599, Elapsed Time: 0:00:17.811513End Time : 2019-03-10 16:02:20.318987, Elapsed Time: 0:00:17.475214End Time : 2019-03-10 16:02:38.392089, Elapsed Time: 0:00:18.072942End Time : 2019-03-10 16:02:55.567773, Elapsed Time: 0:00:17.175470End Time : 2019-03-10 16:03:13.802732, Elapsed Time: 0:00:18.234765End Time : 2019-03-10 16:03:32.918843, Elapsed Time: 0:00:19.115479End Time : 2019-03-10 16:03:51.401436, Elapsed Time: 0:00:18.482391
Trade.show_result('n', N, trade_list)
从上图来看,kdj在超买与超卖区的反应对于沪深300指数来说,反应并不好。
当k线与d线形成金叉时买进;
当k线与d线形成死叉时卖出;
金叉与死叉形成时,最小的时间段是前天与当天的值的比较,这个时间段也可以被当作一种参数D,其取值范围是1~9天。查看回测结果:
trade_list = [] D = range(1, 10)for d in D:"""初始化以下内容"""context = Context() # 账户对象order = Order(context) # 下单对象trade = Trade(context, order) # 回测对旬context.start_date = '2005-05-01'context.end_date = '2019-02-22'context.universe = ['000300.XSHG'] context.base = '000300.XSHG'"""策略主体"""def handle(context, order):stock = context.universe[0] current_date = trade.context.current_dt kdj_day = get_kdj(stock, 30, current_date, '1d') k1 = kdj_day[0][-1] d1 = kdj_day[1][-1] j1 = kdj_day[2][-1] k2 = kdj_day[0][-d-1] d2 = kdj_day[1][-d-1] j2 = kdj_day[2][-d-1] close = get_price(security=stock, end_date=context.current_dt, frequency='daily', fields=None, skip_paused=False, fq='pre', count=5)['close']if k2 < d2 and k1 > d1:if stock in context.position.keys():returnorder.buy(stock, close[-1], context.cash // close[-1])elif k2 > d2 and k1 < d1:if stock not in context.position.keys():returnorder.sell(stock, close[-1], context.position[stock]['count'])"""执行策略"""trade.trade(handle, show=False, log=True) trade_list.append(trade)# 展示Trade.show_ratio_compare('d', D, trade_list, 3, 3)
End Time : 2019-03-10 16:04:13.577469, Elapsed Time: 0:00:20.034098End Time : 2019-03-10 16:04:33.005696, Elapsed Time: 0:00:19.428044End Time : 2019-03-10 16:04:52.154929, Elapsed Time: 0:00:19.149037End Time : 2019-03-10 16:05:12.142793, Elapsed Time: 0:00:19.987659End Time : 2019-03-10 16:05:31.073016, Elapsed Time: 0:00:18.930031End Time : 2019-03-10 16:05:51.557113, Elapsed Time: 0:00:20.483901End Time : 2019-03-10 16:06:10.902478, Elapsed Time: 0:00:19.345159End Time : 2019-03-10 16:06:29.924519, Elapsed Time: 0:00:19.021839End Time : 2019-03-10 16:06:48.871547, Elapsed Time: 0:00:18.946834
Trade.show_result('d', D, trade_list)
从上面结果来看,当d=2时回测的效果比较好,但整体看来,仍旧没有跑赢大盘。因此,效果也并不理想。
当j线与价格发生底背离时,买进;
当j线与价格发生顶背离时,卖出;
背离计算的是一段时间内,j线的趋势与价格的趋势在方向上不一致,把时间段设为D值,取值范围是1~9天。回测并查看结果:
trade_list = [] D = range(1, 10)for d in D:"""初始化以下内容"""context = Context() # 账户对象order = Order(context) # 下单对象trade = Trade(context, order) # 回测对旬context.start_date = '2005-05-01'context.end_date = '2019-02-22'context.universe = ['000300.XSHG'] context.base = '000300.XSHG'"""策略主体"""def handle(context, order):stock = context.universe[0] current_date = trade.context.current_dt kdj_day = get_kdj(stock, 30, current_date, '1d') k1 = kdj_day[0][-1] d1 = kdj_day[1][-1] j1 = kdj_day[2][-1] k2 = kdj_day[0][-d-1] d2 = kdj_day[1][-d-1] j2 = kdj_day[2][-d-1] close = get_price(security=stock, end_date=context.current_dt, frequency='daily', fields=None, skip_paused=False, fq='pre', count=20)['close']if j1 > j2 and close[-1] < close[-d-1]:if stock in context.position.keys():returnorder.buy(stock, close[-1], context.cash // close[-1])elif j1 < j2 and close[-1] > close[-d-1]:if stock not in context.position.keys():returnorder.sell(stock, close[-1], context.position[stock]['count'])"""执行策略"""trade.trade(handle, show=False, log=True) trade_list.append(trade)# 展示Trade.show_ratio_compare('d', D, trade_list, 3, 3)
End Time : 2019-03-10 16:07:10.097162, Elapsed Time: 0:00:19.401507End Time : 2019-03-10 16:07:30.041172, Elapsed Time: 0:00:19.943802End Time : 2019-03-10 16:07:51.642053, Elapsed Time: 0:00:21.600708End Time : 2019-03-10 16:08:12.491229, Elapsed Time: 0:00:20.848990End Time : 2019-03-10 16:08:32.879961, Elapsed Time: 0:00:20.388533End Time : 2019-03-10 16:08:53.409177, Elapsed Time: 0:00:20.528626End Time : 2019-03-10 16:09:12.488550, Elapsed Time: 0:00:19.079192End Time : 2019-03-10 16:09:32.450308, Elapsed Time: 0:00:19.961573End Time : 2019-03-10 16:09:52.517584, Elapsed Time: 0:00:20.067092
Trade.show_result('d', D, trade_list)
从上图来看,j线的背离效果也不好,k线与d线的背离效果这里就不做加测了。
"""初始化以下内容"""context = Context() # 账户对象order = Order(context) # 下单对象trade = Trade(context, order) # 回测对旬context.start_date = '2005-05-01'context.end_date = '2019-02-22'context.universe = ['000300.XSHG'] context.base = '000300.XSHG'"""策略主体"""def handle(context, order):stock = context.universe[0] current_date = trade.context.current_dt kdj_day = get_kdj(stock, 30, current_date, '1d') k1 = kdj_day[0][-1] d1 = kdj_day[1][-1] j1 = kdj_day[2][-1] k2 = kdj_day[0][-2-1] d2 = kdj_day[1][-2-1] j2 = kdj_day[2][-2-1] close = get_price(security=stock, end_date=context.current_dt, frequency='daily', fields=None, skip_paused=False, fq='pre', count=20)['close']if k2 < d2 and k1 > d1:if stock in context.position.keys():returnorder.buy(stock, close[-1], context.cash // close[-1])elif k2 > d2 and k1 < d1:if stock not in context.position.keys():returnorder.sell(stock, close[-1], context.position[stock]['count'])"""执行策略"""trade.trade(handle, show=True, log=True)
End Time : 2019-03-10 16:11:04.901546, Elapsed Time: 0:00:20.362267
本社区仅针对特定人员开放
查看需注册登录并通过风险意识测评
5秒后跳转登录页面...
移动端课程