海龟交易法操作商品期货

上了三个小象学院的量化交易网课,是时候写点东西了。按照进阶课的内容,先把宋战江老师第一课针对商品期货的海龟交易法写一下,他是在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抓出来。

 

posted @ 2018-08-19 23:57  斌伯  阅读(2094)  评论(0编辑  收藏  举报