alonecat06

上了三个小象学院的量化交易网课,是时候写点东西了。按照进阶课的内容,先把宋战江老师第一课针对商品期货的海龟交易法写一下,他是在TB上写的,我想将代码改到聚宽上。

先上聚宽搜商品期货数据的信息,看到有个帖子直接给出了海龟交易法,由于第一次用聚宽,先逐字敲一下代码

  1 # 克隆自聚宽文章:https://www.joinquant.com/post/9184
  2 # 标题:商品期货策略——海龟交易法
  3 # 作者:ScintiGimcki
  4 
  5 # 导入函数库
  6 import jqdata
  7 #import statsmodels.api as sm
  8 #from statsmodels.tsa.stattools import adfuller
  9 
 10 ## 初始化函数,设定基准等等
 11 def initialize(context):
 12     # 设置参数
 13     set_params(context)
 14     # 设定基准
 15     set_benchmark(get_future_code(g.future_index))
 16     # 开启动态复权模式(真实价格)
 17     set_option(\'use_real_price\', True)
 18     # 过滤掉order系列API产生的比error级别低的log
 19     log.set_level(\'order\', \'error\')
 20     # 初始化标的
 21     g.future = get_future_code(g.future_index)
 22 
 23 
 24     ### 期货相关设定 ###
 25     # 设定账户为金融账户
 26     set_subportfolios([SubPortfolioConfig(cash=context.portfolio.starting_cash, type=\'index_futures\')])
 27     # 期货类每笔交易时的手续费是:买入时万分之0.23,卖出时万分之0.23,平今仓为万分之23
 28     set_order_cost(OrderCost(open_commission=0.000023, close_commission=0.000023,close_today_commission=0.0023), type=\'index_futures\')
 29     # 设定保证金比例
 30     set_option(\'futures_margin_rate\', 0.15)
 31 
 32     # 运行函数(reference_security为运行时间的参考标的;传入的标的只做种类区分,因此传入\'IF1512.CCFX\'或\'IH1602.CCFX\'是一样的)
 33       # 开盘前运行
 34     run_daily( before_market_open, time=\'before_open\', reference_security=get_future_code(g.future_index))
 35       # 开盘时运行
 36     run_daily( while_open, time=\'open\', reference_security=get_future_code(g.future_index))
 37       # 收盘后运行
 38     run_daily( after_market_close, time=\'after_close\', reference_security=get_future_code(g.future_index))
 39 
 40 
 41 def set_params(context):
 42     # 设置唐奇安通道时间窗口
 43     g.window = 10
 44     # 最大unit数目
 45     g.limit_unit = 6
 46     # 每次交易unit数目
 47     g.unit = 0
 48     # 加仓次数
 49     g.add_time = 0
 50     # 持仓状态
 51     g.position = 0
 52     # 最高价指标,用作移动止损
 53     g.price_mark = 0
 54     # 最近一次交易的合约
 55     g.last_future = None
 56     # 上一次交易的价格
 57     g.last_price = 0
 58     # 合约
 59     g.future_index = \'CU\'
 60     
 61 
 62     
 63 ## 开盘前运行函数     
 64 def before_market_open(context):
 65     ## 获取要操作的期货(g.为全局变量)
 66       # 获取当月期货合约
 67     g.future = get_dominant_future(g.future_index)
 68     
 69     
 70     
 71         
 72     
 73     
 74 ## 开盘时运行函数
 75 def while_open(context):
 76     # 如果期货标的改变,重置参数
 77     if g.last_future == None:
 78         g.last_future = g.future
 79     elif g.last_future != g.future:
 80         if g.position == -1:
 81             order_target(g.last_future,0,side=\'short\')
 82             g.position == 0
 83         elif g.position == 1:
 84             order_target(g.last_future,0,side=\'long\')
 85             g.position == 0
 86         g.last_future = g.future
 87         re_set()
 88         log.info("主力合约改变,平仓!")
 89     
 90     # 当月合约
 91     future = g.future
 92     # 获取当月合约交割日期
 93     end_date = get_CCFX_end_date(future)
 94     # 当月合约交割日当天不开仓
 95     if (context.current_dt.date() == end_date):
 96         return
 97     price_list = attribute_history(future,g.window+1,\'1d\',[\'close\',\'high\',\'low\'])
 98     # 如果没有数据,返回
 99     if len(price_list) == 0: 
100         return
101     close_price = price_list[\'close\'].iloc[-1] 
102     # 计算ATR
103     ATR = get_ATR(price_list,g.window)
104     
105     ## 判断加仓或止损
106       # 先判断是否持仓
107     #g.position = get_position(context)
108     if g.position != 0 :   
109         signal = get_next_signal(close_price,g.last_price,ATR,g.position)
110         # 判断加仓且持仓没有达到上限
111         if signal == 1 and g.add_time < g.limit_unit:  
112             g.unit = get_unit(context.portfolio.total_value,ATR,g.future_index)
113             # 多头加仓
114             if g.position == 1: 
115                 order(future,g.unit,side=\'long\')
116                 log.info( \'多头加仓成功:\',context.current_dt.time(),future,g.unit)
117                 g.last_prcie = close_price
118                 g.add_time += 1
119             # 空头加仓
120             elif g.position == -1: 
121                 order(future,g.unit,side=\'short\')
122                 log.info( \'空头加仓成功:\',context.current_dt.time(),future,g.unit)
123                 g.last_prcie = close_price
124                 g.add_time += 1
125         # 判断平仓止损
126         elif signal == -1:
127             # 多头平仓
128             if g.position == 1:
129                 order_target(future,0,side=\'long\')
130                 g.price_mark = 0
131                 g.position = 0
132                 log.info( \'多头止损成功:\',context.current_dt.time(),future)
133                 log.info(\'----------------------------------------------------------\')
134             # 空头平仓
135             elif g.position == -1:  
136                 order_target(future,0,side=\'long\')
137                 g.price_mark = 0
138                 g.position = 0
139                 log.info( \'空头止损成功:\',context.current_dt.time(),future)
140                 log.info(\'----------------------------------------------------------\')
141             # 重新初始化参数
142             re_set()
143     
144     ## 开仓
145       # 得到开仓信号
146     open_signal = check_break(price_list,close_price,g.window)
147     # 多头开仓
148     if open_signal ==1 and g.position !=1:  
149         # 检测否需要空头平仓
150         if g.position == -1:
151             order_target(future,0,side=\'short\')
152             if context.portfolio.short_positions[future].total_amount==0:
153                 g.price_mark = 0
154                 # 重新初始化参数
155                 re_set()
156                 log.info( \'空头平仓成功:\',context.current_dt.time(),future)
157                 log.info(\'----------------------------------------------------------\')
158         # 多头开仓
159         g.unit = get_unit(context.portfolio.total_value,ATR,g.future_index)
160         order(future,g.unit,side=\'long\')
161         if context.portfolio.positions[future].total_amount>0:
162             g.position = 1
163             g.price_mark = context.portfolio.long_positions[future].price
164             log.info( \'多头建仓成功:\',context.current_dt.time(),future,g.unit)
165             log.info(\'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\')
166             g.add_time = 1
167             g.last_prcie = close_price
168             g.last_future= future
169     # 空头开仓
170     elif open_signal == -1 and g.position != -1:
171         # 检测否需要多头平仓
172         if g.position == 1:
173             order_target(future,0,side=\'long\')
174             if context.portfolio.positions[future].total_amount==0:
175                 g.price_mark = 0
176                 # 重新初始化参数
177                 re_set()
178                 log.info( \'多头平仓成功:\',context.current_dt.time(),future)
179                 log.info(\'----------------------------------------------------------\')
180         # 空头开仓
181         g.unit = get_unit(context.portfolio.total_value,ATR,g.future_index)
182         order(future,g.unit,side=\'short\')
183         if context.portfolio.short_positions[future].total_amount > 0:
184             g.position = -1
185             g.price_mark = context.portfolio.short_positions[future].price
186             log.info( \'空头建仓成功:\',context.current_dt.time(),future,g.unit)
187             log.info(\'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\')
188             g.add_time = 1
189             g.last_prcie = close_price
190             g.last_future= future
191     
192     # 判断今日是否出现最高价
193     if g.position != 0:
194         set_price_mark(context,future)
195     # 得到止损信号
196     signal = get_risk_signal(context,future)
197     # 止损平仓
198     if signal:
199         order_target(future, 0, side=\'short\')
200         order_target(future, 0, side=\'long\')
201         if context.portfolio.positions[future].total_amount==0 and context.portfolio.short_positions[future].total_amount==0:
202             log.info("止损平仓!")
203             g.position = 0
204             g.price_mark = 0
205     return
206     
207 
208         
209 ## 收盘后运行函数  
210 def after_market_close(context):
211     pass
212 
213 
214 ########################## 自定义函数 #################################
215 # 重置参数
216 def re_set():
217     # 每次交易unit数目
218     g.unit = 0
219     # 加仓次数
220     g.add_time = 0
221     # 持仓状态
222     g.position = 0
223 
224 def check_break(price_list,price,T):
225     up = max(price_list[\'high\'].iloc[-T-1:-2])
226     down = min(price_list[\'low\'].iloc[-T-1:-2])  
227     if price>up:
228         return 1
229     elif price<down:
230         return -1
231     else:
232         return 0 
233 
234 def get_ATR(price_list,T):
235     TR_list = [max(price_list[\'high\'].iloc[i]-price_list[\'low\'].iloc[i],abs(price_list[\'high\'].iloc[i]-price_list[\'close\'].iloc[i-1]),abs(price_list[\'close\'].iloc[i-1]-price_list[\'low\'].iloc[i])) for i in range(1,T+1)]
236     ATR = np.array(TR_list).mean()
237     return ATR
238 
239 def get_next_signal(price,last_price,ATR,position):# 加仓或止损
240     if (price >= last_price + 0.5*ATR and position==1) or (price <= last_price - 0.5*ATR and position==-1): # 多头加仓或空头加仓
241         return 1
242     elif (price <= last_price - 2*ATR and position==1) or (price >= last_price + 2*ATR and position==-1):  # 多头止损或空头止损
243         return -1
244     else:
245         return 0
246     
247 def get_position(context): # 0为未持仓,1为持多,-1为持空 
248     try:
249         tmp = context.portfolio.positions.keys()[0]
250         if not context.portfolio.long_positions[tmp].total_amount and not context.portfolio.short_positions[tmp].total_amount:
251             return 0
252         elif context.portfolio.long_positions[tmp].total_amount:
253             return 1
254         elif context.portfolio.short_positions[tmp].total_amount:
255             return -1
256         else:
257             return 0
258     except:
259         return 0
260 
261 def get_unit(cash,ATR,symbol):
262     future_coef_list = {\'A\':10, \'AG\':15, \'AL\':5, \'AU\':1000,
263                         \'B\':10, \'BB\':500, \'BU\':10, \'C\':10, 
264                         \'CF\':5, \'CS\':10, \'CU\':5, \'ER\':10, 
265                         \'FB\':500, \'FG\':20, \'FU\':50, \'GN\':10, 
266                         \'HC\':10, \'I\':100, \'IC\':200, \'IF\':300, 
267                         \'IH\':300, \'J\':100, \'JD\':5, \'JM\':60, 
268                         \'JR\':20, \'L\':5, \'LR\':10, \'M\':10, 
269                         \'MA\':10, \'ME\':10, \'NI\':1, \'OI\':10, 
270                         \'P\':10, \'PB\':5, \'PM\':50, \'PP\':5, 
271                         \'RB\':10, \'RI\':20, \'RM\':10, \'RO\':10, 
272                         \'RS\':10, \'RU\':10, \'SF\':5, \'SM\':5, 
273                         \'SN\':1, \'SR\':10, \'T\':10000, \'TA\':5, 
274                         \'TC\':100, \'TF\':10000, \'V\':5, \'WH\':20, 
275                         \'WR\':10, \'WS\':50, \'WT\':10, \'Y\':10, 
276                         \'ZC\':100, \'ZN\':5}
277     return (cash*0.01/ATR)/future_coef_list[symbol]
278 
279 def set_price_mark(context,future):
280     if g.position == -1:
281         g.price_mark = min(context.portfolio.short_positions[future].price,g.price_mark)
282     elif g.position == 1:
283         g.price_mark = max(context.portfolio.long_positions[future].price,g.price_mark)
284                 
285 def get_risk_signal(context,future):
286     if g.position == -1:
287         if context.portfolio.short_positions[future].price >=1.05*g.price_mark:
288             log.info("空头仓位止损,时间: "+str(context.current_dt.time()))
289             return True
290         else:
291             return False
292     elif g.position == 1:
293         if context.portfolio.long_positions[future].price <= 0.95*g.price_mark:
294             log.info("多头仓位止损,时间: "+str(context.current_dt.time()))
295             return True
296         else:
297             return False
298 
299 ########################## 获取期货合约信息,请保留 #################################
300 # 获取当天时间正在交易的期货主力合约
301 def get_future_code(symbol):
302     future_code_list = {\'A\':\'A9999.XDCE\', \'AG\':\'AG9999.XSGE\', \'AL\':\'AL9999.XSGE\', \'AU\':\'AU9999.XSGE\',
303                         \'B\':\'B9999.XDCE\', \'BB\':\'BB9999.XDCE\', \'BU\':\'BU9999.XSGE\', \'C\':\'C9999.XDCE\', 
304                         \'CF\':\'CF9999.XZCE\', \'CS\':\'CS9999.XDCE\', \'CU\':\'CU9999.XSGE\', \'ER\':\'ER9999.XZCE\', 
305                         \'FB\':\'FB9999.XDCE\', \'FG\':\'FG9999.XZCE\', \'FU\':\'FU9999.XSGE\', \'GN\':\'GN9999.XZCE\', 
306                         \'HC\':\'HC9999.XSGE\', \'I\':\'I9999.XDCE\', \'IC\':\'IC9999.CCFX\', \'IF\':\'IF9999.CCFX\', 
307                         \'IH\':\'IH9999.CCFX\', \'J\':\'J9999.XDCE\', \'JD\':\'JD9999.XDCE\', \'JM\':\'JM9999.XDCE\', 
308                         \'JR\':\'JR9999.XZCE\', \'L\':\'L9999.XDCE\', \'LR\':\'LR9999.XZCE\', \'M\':\'M9999.XDCE\', 
309                         \'MA\':\'MA9999.XZCE\', \'ME\':\'ME9999.XZCE\', \'NI\':\'NI9999.XSGE\', \'OI\':\'OI9999.XZCE\', 
310                         \'P\':\'P9999.XDCE\', \'PB\':\'PB9999.XSGE\', \'PM\':\'PM9999.XZCE\', \'PP\':\'PP9999.XDCE\', 
311                         \'RB\':\'RB9999.XSGE\', \'RI\':\'RI9999.XZCE\', \'RM\':\'RM9999.XZCE\', \'RO\':\'RO9999.XZCE\', 
312                         \'RS\':\'RS9999.XZCE\', \'RU\':\'RU9999.XSGE\', \'SF\':\'SF9999.XZCE\', \'SM\':\'SM9999.XZCE\', 
313                         \'SN\':\'SN9999.XSGE\', \'SR\':\'SR9999.XZCE\', \'T\':\'T9999.CCFX\', \'TA\':\'TA9999.XZCE\', 
314                         \'TC\':\'TC9999.XZCE\', \'TF\':\'TF9999.CCFX\', \'V\':\'V9999.XDCE\', \'WH\':\'WH9999.XZCE\', 
315                         \'WR\':\'WR9999.XSGE\', \'WS\':\'WS9999.XZCE\', \'WT\':\'WT9999.XZCE\', \'Y\':\'Y9999.XDCE\', 
316                         \'ZC\':\'ZC9999.XZCE\', \'ZN\':\'ZN9999.XSGE\'}
317     try:
318         return future_code_list[symbol]
319     except:
320         return \'WARNING: 无此合约\'
321 
322 
323 # 获取当天时间正在交易的股指期货合约
324 def get_stock_index_futrue_code(context,symbol,month=\'current_month\'):
325     \'\'\'
326     获取当天时间正在交易的股指期货合约。其中:
327     symbol:
328             \'IF\' #沪深300指数期货
329             \'IC\' #中证500股指期货
330             \'IH\' #上证50股指期货
331     month:
332             \'current_month\' #当月
333             \'next_month\'    #隔月
334             \'next_quarter\'  #下季
335             \'skip_quarter\'  #隔季
336     \'\'\'
337     display_name_dict = {\'IC\':\'中证500股指期货\',\'IF\':\'沪深300指数期货\',\'IH\':\'上证50股指期货\'}
338     month_dict = {\'current_month\':0, \'next_month\':1, \'next_quarter\':2, \'skip_quarter\':3}
339 
340     display_name = display_name_dict[symbol]
341     n = month_dict[month]
342     dt = context.current_dt.date()
343     a = get_all_securities(types=[\'futures\'], date=dt)
344     try:
345         df = a[(a.display_name == display_name) & (a.start_date <= dt) & (a.end_date >= dt)]
346         return df.index[n]
347     except:
348         return \'WARRING: 无此合约\'
349 
350 # 获取当天时间正在交易的国债期货合约
351 def get_treasury_futrue_code(context,symbol,month=\'current\'):
352     \'\'\'
353     获取当天时间正在交易的国债期货合约。其中:
354     symbol:
355             \'T\' #10年期国债期货
356             \'TF\' #5年期国债期货
357     month:
358             \'current\' #最近期
359             \'next\'    #次近期
360             \'skip\'    #最远期
361     \'\'\'
362     display_name_dict = {\'T\':\'10年期国债期货\',\'TF\':\'5年期国债期货\'}
363     month_dict = {\'current\':0, \'next\':1, \'skip\':2}
364 
365     display_name = display_name_dict[symbol]
366     n = month_dict[month]
367     dt = context.current_dt.date()
368     a = get_all_securities(types=[\'futures\'], date=dt)
369     try:
370         df = a[(a.display_name == display_name) & (a.start_date <= dt) & (a.end_date >= dt)]
371         return df.index[n]
372     except:
373         return \'WARRING: 无此合约\'
374 
375 # 获取金融期货合约到期日
376 def get_CCFX_end_date(fature_code):
377     # 获取金融期货合约到期日
378     return get_security_info(fature_code).end_date

发现有低级错误,是第189行中空头建仓后,建仓价格记录在last_prcie,而非last_price,导致后续的加仓、止损都会有判断问题

但回测帖子所给的时间段、资金量以及相同的期货品种,发现收益差了很多,原有代码是47%的年化收益,修改后只有18%了

于是觉得代码可能还是哪里有坑,拿不准那个才是正确,于是还是想原来的老路,改宋老师TB的代码,这样可以对照宋老师的回测结果(后面看也是不行,宋博的回测时间是2009年开始的,聚宽只能提供2010年以后的数据)。我将其简化版海龟策略(就是缺了加仓和反向头寸止损的操作)的TB的代码改成可以在聚宽上跑了。

  1 # 导入函数库
  2 from jqdata import *
  3 import pandas as pd
  4 import numpy as np
  5 
  6 ## 初始化函数,设定基准等等
  7 def initialize(context):
  8     set_params(context)
  9     # 设定所交易期货指数作为基准
 10     set_benchmark(get_future_code(g.future_index))
 11     # 开启动态复权模式(真实价格)
 12     set_option(\'use_real_price\', True)
 13     # 过滤掉order系列API产生的比error级别低的log
 14     # log.set_level(\'order\', \'error\')
 15     # 输出内容到日志 log.info()
 16     log.info(\'初始函数开始运行且全局只运行一次\')
 17 
 18     ### 期货相关设定 ###
 19     # 设定账户为金融账户
 20     set_subportfolios([SubPortfolioConfig(cash=context.portfolio.starting_cash, type=\'index_futures\')])
 21     # 期货类每笔交易时的手续费是:买入时万分之0.23,卖出时万分之0.23,平今仓为万分之23
 22     set_order_cost(OrderCost(open_commission=0.000023, close_commission=0.000023,close_today_commission=0.0023), type=\'index_futures\')
 23     # 设定保证金比例
 24     set_option(\'futures_margin_rate\', 0.15)
 25 
 26     # 设置期货交易的滑点
 27     set_slippage(FixedSlippage(0.2))
 28     # 运行函数(reference_security为运行时间的参考标的;传入的标的只做种类区分,因此传入\'IF1512.CCFX\'或\'IH1602.CCFX\'是一样的)
 29       # 开盘前运行
 30     run_daily( before_market_open, time=\'before_open\', reference_security=get_future_code(g.future_index))
 31       # 开盘时运行
 32     run_daily( market_open, time=\'open\', reference_security=get_future_code(g.future_index))
 33       # 收盘后运行
 34     run_daily( after_market_close, time=\'after_close\', reference_security=get_future_code(g.future_index))
 35 
 36 
 37 ## 开盘前运行函数
 38 def before_market_open(context):
 39     # 输出运行时间
 40     log.info(\'函数运行时间(before_market_open):\'+str(context.current_dt.time()))
 41 
 42     # 给微信发送消息(添加模拟交易,并绑定微信生效)
 43     #send_message(\'美好的一天~\')
 44 
 45     ## 获取要操作的股票(g.为全局变量)
 46       # 获取当月期货合约
 47     g.future = get_dominant_future(g.future_index)
 48 
 49 
 50 ## 开盘时运行函数
 51 def market_open(context):
 52     calc_window = int(3.45*(g.ATRLength + 1))
 53     price_list = attribute_history(g.future, calc_window + 1, \'1d\', [\'close\',\'high\',\'low\'])
 54     
 55     if len(price_list) == 0:
 56         return # 如果没有数据,返回
 57     
 58     AvgTR = XAverage(TrueRange(price_list, calc_window),g.ATRLength)
 59     N = AvgTR[-2]
 60     TurtleUnits = get_unit(context.portfolio.total_value, N, g.future_index, g.RiskRatio)
 61 
 62     DonchianHi = HighestFC(price_list[\'high\'], g.boLength)
 63     DonchianLo = LowestFC(price_list[\'low\'], g.boLength)
 64     
 65     ExitLowestPrice = LowestFC(price_list[\'low\'], g.teLength)
 66     ExitHighestPrice = HighestFC(price_list[\'high\'], g.teLength)
 67     
 68     High = price_list[\'high\'].iloc[-1]
 69     Low = price_list[\'low\'].iloc[-1]
 70     
 71     # 当不使用过滤条件,或者使用过滤条件并且条件为PreBreakoutFailure为True进行后续操作
 72     if g.MarketPosition == 0:
 73         log.info(context.current_dt.time(), \' High:\', High, \' DonchianHi:\', DonchianHi, \' Low:\', Low, \' DonchianLo:\', DonchianLo)
 74         # 突破开仓
 75         if High > DonchianHi and TurtleUnits >= 1:
 76             # 开仓价格取突破上轨+一个价位和最高价之间的较小值,这样能更接近真实情况,并能尽量保证成交
 77             # myEntryPrice = min(High, DonchianHi)# + MinPoint)
 78             # myEntryPrice = Open if myEntryPrice < Open else myEntryPrice # 大跳空的时候用开盘价代替
 79             order(g.future, TurtleUnits, side=\'long\')
 80             g.MarketPosition = 1
 81 
 82         if Low < DonchianLo and TurtleUnits >= 1:
 83             # 开仓价格取突破下轨-一个价位和最低价之间的较大值,这样能更接近真实情况,并能尽量保证成交
 84             # myEntryPrice = max(Low,DonchianLo)# - MinPoint)
 85             # myEntryPrice = Open if myEntryPrice > Open else myEntryPrice # 大跳空的时候用开盘价代替
 86             order(g.future, TurtleUnits, side=\'short\')
 87             g.MarketPosition = -1
 88 
 89     if g.MarketPosition == 1:
 90         # 有多仓的情况
 91         log.info(\'ExitLowestPrice=\', ExitLowestPrice)
 92         if Low < ExitLowestPrice:
 93             # myExitPrice = max(Low,ExitLowestPrice)# - MinPoint)
 94             # myExitPrice = Open if myExitPrice > Open else myExitPrice # 大跳空的时候用开盘价代替
 95             order_target(g.future, 0, side=\'long\') # 数量用0的情况下将全部平仓
 96             g.MarketPosition = 0
 97     elif g.MarketPosition == -1:
 98         # 有空仓的情况
 99         log.info(\'ExitHighestPrice=\', ExitHighestPrice)
100         if High > ExitHighestPrice:
101             # myExitPrice = Min(High,ExitHighestPrice)# + MinPoint)
102             # myExitPrice = Open if myExitPrice < Open else myExitPrice # 大跳空的时候用开盘价代替
103             order_target(g.future, 0, side=\'short\') # 数量用0的情况下将全部平仓
104             g.MarketPosition = 0
105 
106 ## 收盘后运行函数
107 def after_market_close(context):
108     log.info(\'函数运行时间(after_market_close):\', context.current_dt.time())
109     # 得到当天所有成交记录
110     trades = get_trades()
111     for _trade in trades.values():
112         log.info(\'成交记录:\'+str(_trade))
113     log.info(\'一天结束\')
114     log.info(\'##############################################################\')
115     
116 
117 ########################## 自定义函数 #################################
118 def set_params(context):
119     g.RiskRatio = 10 # % Risk Per N ( 0 - 100)
120     g.ATRLength = 6 # 平均波动周期 ATR Length
121     g.boLength = 0 # 短周期 BreakOut Length
122     g.teLength = 0 # 离市周期 Trailing Exit Length
123     g.future_index = \'RB\' # 合约
124     g.MarketPosition = 0
125     
126 # 求指数平均
127 def XAverage(Price, Length):
128     alpha = 2 / (Length + 1)
129     res = []
130     for i in range(0, len(Price)):
131         res.append(ema_calc(alpha, Price, i))
132     return res
133     
134 def ema_calc(alpha, price, t):
135     if (t == 0):
136         return price[t]
137     else:
138         return alpha*price[t] + (1-alpha) * ema_calc(alpha, price, t-1)
139         
140 def TrueRange(price_list, T):
141     return [max(price_list[\'high\'].iloc[i]-price_list[\'low\'].iloc[i], abs(price_list[\'high\'].iloc[i]-price_list[\'close\'].iloc[i-1]), abs(price_list[\'close\'].iloc[i-1]-price_list[\'low\'].iloc[i])) for i in range(1, T+1)]
142     
143 def get_unit(cash, ATR, symbol, RiskRatio):
144     # 各品种期货的交易单位(一手合约包含多少计量单位,如CU:5即铜合约交易单位为5吨/手)
145     future_contract_size = {\'A\':10, \'AG\':15, \'AL\':5, \'AU\':1000,
146                         \'B\':10, \'BB\':500, \'BU\':10, \'C\':10, 
147                         \'CF\':5, \'CS\':10, \'CU\':5, \'ER\':10, 
148                         \'FB\':500, \'FG\':20, \'FU\':50, \'GN\':10, 
149                         \'HC\':10, \'I\':100, \'IC\':200, \'IF\':300, 
150                         \'IH\':300, \'J\':100, \'JD\':5, \'JM\':60, 
151                         \'JR\':20, \'L\':5, \'LR\':10, \'M\':10, 
152                         \'MA\':10, \'ME\':10, \'NI\':1, \'OI\':10, 
153                         \'P\':10, \'PB\':5, \'PM\':50, \'PP\':5, 
154                         \'RB\':10, \'RI\':20, \'RM\':10, \'RO\':10, 
155                         \'RS\':10, \'RU\':10, \'SF\':5, \'SM\':5, 
156                         \'SN\':1, \'SR\':10, \'T\':10000, \'TA\':5, 
157                         \'TC\':100, \'TF\':10000, \'V\':5, \'WH\':20, 
158                         \'WR\':10, \'WS\':50, \'WT\':10, \'Y\':10, 
159                         \'ZC\':100, \'ZN\':5}
160     TurtleUnits = (cash*RiskRatio) / (100.0 * ATR * future_contract_size[symbol])
161     TurtleUnits = int(TurtleUnits) # 对小数取整
162     print(\'TurtleUnits: \', TurtleUnits)
163     return TurtleUnits
164     
165 def HighestFC(Prices, Length):
166     highest = Prices[-2]
167     for i in range(-2, -Length-2):
168         if highest < Prices[i]:
169             highest = Prices
170     return highest
171     
172 def LowestFC(Prices, Length):
173     lowest = Prices[-2]
174     for i in range(-2, -Length-2):
175         if lowest > Prices[i]:
176             lowest = Prices
177     return lowest
178 
179 ########################## 获取期货合约信息,请保留 #################################
180 # 获得当天时间正在交易的期货主力合约
181 def get_future_code(symbol):
182     future_code_list = {\'A\':\'A9999.XDCE\', \'AG\':\'AG9999.XSGE\', \'AL\':\'AL9999.XSGE\', \'AU\':\'AU9999.XSGE\',
183                         \'B\':\'B9999.XDCE\', \'BB\':\'BB9999.XDCE\', \'BU\':\'BU9999.XSGE\', \'C\':\'C9999.XDCE\', 
184                         \'CF\':\'CF9999.XZCE\', \'CS\':\'CS9999.XDCE\', \'CU\':\'CU9999.XSGE\', \'ER\':\'ER9999.XZCE\', 
185                         \'FB\':\'FB9999.XDCE\', \'FG\':\'FG9999.XZCE\', \'FU\':\'FU9999.XSGE\', \'GN\':\'GN9999.XZCE\', 
186                         \'HC\':\'HC9999.XSGE\', \'I\':\'I9999.XDCE\', \'IC\':\'IC9999.CCFX\', \'IF\':\'IF9999.CCFX\', 
187                         \'IH\':\'IH9999.CCFX\', \'J\':\'J9999.XDCE\', \'JD\':\'JD9999.XDCE\', \'JM\':\'JM9999.XDCE\', 
188                         \'JR\':\'JR9999.XZCE\', \'L\':\'L9999.XDCE\', \'LR\':\'LR9999.XZCE\', \'M\':\'M9999.XDCE\', 
189                         \'MA\':\'MA9999.XZCE\', \'ME\':\'ME9999.XZCE\', \'NI\':\'NI9999.XSGE\', \'OI\':\'OI9999.XZCE\', 
190                         \'P\':\'P9999.XDCE\', \'PB\':\'PB9999.XSGE\', \'PM\':\'PM9999.XZCE\', \'PP\':\'PP9999.XDCE\', 
191                         \'RB\':\'RB9999.XSGE\', \'RI\':\'RI9999.XZCE\', \'RM\':\'RM9999.XZCE\', \'RO\':\'RO9999.XZCE\', 
192                         \'RS\':\'RS9999.XZCE\', \'RU\':\'RU9999.XSGE\', \'SF\':\'SF9999.XZCE\', \'SM\':\'SM9999.XZCE\', 
193                         \'SN\':\'SN9999.XSGE\', \'SR\':\'SR9999.XZCE\', \'T\':\'T9999.CCFX\', \'TA\':\'TA9999.XZCE\', 
194                         \'TC\':\'TC9999.XZCE\', \'TF\':\'TF9999.CCFX\', \'V\':\'V9999.XDCE\', \'WH\':\'WH9999.XZCE\', 
195                         \'WR\':\'WR9999.XSGE\', \'WS\':\'WS9999.XZCE\', \'WT\':\'WT9999.XZCE\', \'Y\':\'Y9999.XDCE\', 
196                         \'ZC\':\'ZC9999.XZCE\', \'ZN\':\'ZN9999.XSGE\'}
197     try:
198         return future_code_list[symbol]
199     except:
200         return \'WARNING : 无此合约\'
201 
202 
203 # 获取金融期货合约到期日
204 def get_CCFX_end_date(fature_code):
205     # 获取金融期货合约到期日
206     return get_security_info(fature_code).end_date

在改代码的过程中遇到多个问题,包括:

1. TB提供一个XAverage的函数计算指数平均,也就是EMA,聚宽下需要我自行实现,关于其计算公式,我有疑问,也发到小象去问老师了:

想问问关于ema计算公式的问题,如果我要得到某个股票今天的ema(20)值,是不是要回溯到这个股票上市开始一直算这个ema(20)算到今天,还是说只需要回退到20天前就开始算这个ema值?

举个例子,就是价格序列是[0,1,2,3,4,5,6,7],对应第一天、第二天、...第八天,想问问求ema(3),其alpha是2 / (3+1) = 0.5,那么第六天的ema(3),应该是4.25,还是4.03125,还是说我两个计算方式都不对?

A. 只需往前倒2天:

ema(3)1=3

ema(3)2=0.5*4 + 0.5*3 = 3.5

ema(3)3=0.5*5+0.5*3.5=4.25

还是B. 从价格序列最开始算ema

ema(3)1=0

ema(3)2=0.5*1 + 0.5*0 = 0.5

ema(3)3=0.5*2+0.5*0.5=1.25

ema(3)4=0.5*3 + 0.5*1.25 = 2.125

ema(3)5=0.5*4+0.5*2.125 = 3.0625

ema(3)6=0.5*5+0.5*3.0625=4.03125

主要是我看这里https://www.zybuluo.com/Channelchan/note/1081375中的“2. Pandas递归函数”例子,里面算第10天的ema(6),我按只往前倒5天(第5天,数值为4)算,应该是6.4335948,而非页面上面算的(9*2/7)+(5.669401*5/7)=6.621001,所以比较疑惑。

不知道如果我要算某个时期,例如17年整年,某股票的ema(20),我在计算17年6月1号的ema(20)时应该是,将往前倒20天就用公式开始算,还是由17年1月1日这个我开始算ema的时期代入公式开始求,还是要追溯会股价第一天开始来代入计算公式?

网上搜索还看到,https://zh.wikipedia.org/wiki/%E7%A7%BB%E5%8B%95%E5%B9%B3%E5%9D%87,说ema(N)要往前算到3.45*(N+1),能包含99.9%的加权,那是应该这样么?

而且听老师的课,这个第10天的ema(6)应该是往前倒6天,由第4天(数值为3)那个开始算,那应该是5.56640515。我的理解有错么?

暂时没有回复,我自己的判断是应该往前算3.45*(N+1)即可,代码上也是这样实现的。

2. 现在的回测结果是收益-85%,觉得是代码有问题。碰到一个困难是,宋博的TB代码是算出交易的量和价格,但聚宽的交易接口只提供交易量,不能设置其交易价格,很奇怪。然后我也看到一些log,说一开始就全仓买进,甚至买到资金不够,估计是代码逻辑有问题,或者是TB跟聚宽用的单位不同。总之是这些导致策略收益是亏损。后面要去好好调试,将bug抓出来。

 

分类:

技术点:

相关文章: