• 海龟交易法操作商品期货


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

  • 相关阅读:
    追随自己的价值观:用研经理 Anne Diaz 职业探索之路
    语义化版本(SemVer)的范围
    git如何放弃所有本地修改
    将本地已有的一个项目上传到新建的git仓库的方法
    using supervisord to run lsyncd script
    sersync下载安装及配置(有演示示例)
    sersync+rsync原理及部署
    Rsync+sersync 实现数据实时同步
    在分屏浏览中并排使用两个 Mac App
    MacOS 安装 Astah Professional 7.2
  • 原文地址:https://www.cnblogs.com/alonecat06/p/9503331.html
Copyright © 2020-2023  润新知