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