上了三個小象學院的量化交易網課,是時候寫點東西了。按照進階課的內容,先把宋戰江老師第一課針對商品期貨的海龜交易法寫一下,他是在TB上寫的,我想將代碼改到聚寬上。ios
先上聚寬搜商品期貨數據的信息,看到有個帖子直接給出了海龜交易法,因爲第一次用聚寬,先逐字敲一下代碼api
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%了app
因而以爲代碼可能仍是哪裏有坑,拿不許那個纔是正確,因而仍是想原來的老路,改宋老師TB的代碼,這樣能夠對照宋老師的回測結果(後面看也是不行,宋博的回測時間是2009年開始的,聚寬只能提供2010年之後的數據)。我將其簡化版海龜策略(就是缺了加倉和反向頭寸止損的操做)的TB的代碼改爲能夠在聚寬上跑了。dom
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
在改代碼的過程當中遇到多個問題,包括:ide
1. TB提供一個XAverage的函數計算指數平均,也就是EMA,聚寬下須要我自行實現,關於其計算公式,我有疑問,也發到小象去問老師了:函數
想問問關於ema計算公式的問題,若是我要獲得某個股票今天的ema(20)值,是否是要回溯到這個股票上市開始一直算這個ema(20)算到今天,仍是說只須要回退到20天前就開始算這個ema值?post
舉個例子,就是價格序列是[0,1,2,3,4,5,6,7],對應第一天、次日、...第八天,想問問求ema(3),其alpha是2 / (3+1) = 0.5,那麼第六天的ema(3),應該是4.25,仍是4.03125,仍是說我兩個計算方式都不對?spa
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抓出來。