海龜交易法操做商品期貨

上了三個小象學院的量化交易網課,是時候寫點東西了。按照進階課的內容,先把宋戰江老師第一課針對商品期貨的海龜交易法寫一下,他是在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抓出來。

相關文章
相關標籤/搜索