美文网首页刺猬教你量化投资投资量化交易
刺猬教你量化投资(二十五):如何用Python实现海龟交易法则

刺猬教你量化投资(二十五):如何用Python实现海龟交易法则

作者: 刺猬偷腥 | 来源:发表于2019-01-26 20:30 被阅读4次

    交易史上最著名的实验

    使用海龟交易法则之前,需要先了解注明的海龟实验。1983年年中,著名的商品投机家理查德.丹尼斯与他的老友比尔.埃克哈特进行了一场辩论,这场辩论是关于伟大的交易员是天生造就还是后天培养的。理查德相信,他可以教会人们成为伟大的交易员。比尔则认为遗传和天性才是决定因素。

    为了解决这一问题,理查德建议招募并培训一些交易员,给他们提供真实的帐户进行交易,看看两个人中谁是正确的。理查德或许是当时世界上最著名的交易员,所以,有1000多位申请人前来投奔他。他会见了其中的80位,并在这群人精选出10个人。后来这个名单变成13个人,所增加的3个人理查德以前就认识。

    理查德在开始这项计划之前,刚从亚洲回来。他在新加坡的海龟农场曾说过:“我们要培养交易者,就像新加坡人养海龟一样。”于是,这13名学员日后便被称作‘海龟’。最终,这项计划成为交易史上最著名的实验,在随后的四年中,海龟们取得了年均复利80%的收益。

    理查德也证明了交易可以被传授。他用一套简单的法则,就可以使仅有很少或根本没有交易经验的人成为优秀的交易员。这套法则便是著名的海龟交易法则。

    海龟交易法则的原理

    海龟交易法则有四大模块,分别是入市、资金管理、止损及退出。这四大模块分别解决了在哪个市场买卖、买卖什么、如何设定头寸规模、什么时候买卖、什么时候止损、什么时候退出市场等问题,是一套完整的交易体系。

    入市部分

    我们需要构建唐奇安通道来生成交易的指令。唐奇安通道的使用方式类似于布林线,但构建时并不使用标准差,而是捕捉趋势信号。上线为过去20天的最高价,下线为过去10天的最低价,中线是上线加下线除以2。当股价上破时买入,当股价下坡时卖出。

    资金管理部分

    需要计算N值。N值与平均真实波幅ATR相似,我们通过N值来确定仓位的大小。原则是波动大的市场买少一点,波动小的市场买多一点,最终使得在不同市场中承受的风险相似。

    N值的含义是,过去20天股价最大波动范围的平均幅度。TrueRange=Max(High−Low,abs(High−PreClose),abs(PreClose−Low))
    N=(PreN∗19+TrueRange20) / 20
    Unit = 1/N

    计算Unit公式的背后含义是,UnitN=Capital1%。在股票市场中计算的Unit就是多少股。当股价在上一次买入的基础上上涨了0.5N,则加仓一个Unit。

    止损部分

    当股价比最后一次买入的价格下跌2N,则立即清仓止损。

    用Python实现

    下面我们以中国平安的个股为例,根据海龟交易法则进行操作:

    import numpy as np
    import pandas as pd
    from CAL.PyCAL import *
    
    start = '2013-01-01'                       # 回测起始时间
    end = '2019-01-01'                         # 回测结束时间
    benchmark = '601318.XSHG'                        
    universe = ['601318.XSHG']
    capital_base = 100000                      # 起始资金
    freq = 'd'                              
    refresh_rate = 1        
    
    accounts = {
        'fantasy_account': AccountConfig(account_type='security', capital_base=100000)
    }
    
    def initialize(context):       #初始化环境
        context.last_buy_prcie = 0  #上一次买入价
        context.hold_flag = False   # 是否持有头寸标志
        context.limit_unit = 10      # 限制最多买入的单元数 
        context.unit = 0
        context.add_time = 0        # 买入次数
    
    def CalcATR(data):
        TR_List = []
        for i in range(1,21):
            TR = max(data['highPrice'].iloc[i]-data['lowPrice'].iloc[i],abs(data['highPrice'].iloc[i]-data['closePrice'].iloc[i-1]),abs(data['closePrice'].iloc[i-1]-data['lowPrice'].iloc[i]))
            TR_List.append(TR)
        ATR = np.array(TR_List).mean()
        return ATR
    
    def CalcUnit(perValue,ATR):
        return round((perValue/ATR)/100)*100
    
    def SellComplete(hold_flag,security_position):
        if len(security_position)>0 and hold_flag==False:
            return True
        else:
            return False
    
    def IN_OR_OUT(data,price,T):
        up = max(data['highPrice'].iloc[-T:-1])
        down = min(data['lowPrice'].iloc[-int(T/2):-1])  # 这里是10日唐奇安下沿
        if price>up:
            return 1
        elif price<down:
            return -1
        else:
            return 0 
    
    def Add_OR_Stop(price,lastprice,ATR):
        if price >= lastprice + 0.5*ATR:
            return 1
        elif price <= lastprice - 2*ATR:
            return -1
        else:
            return 0
    
    
    def handle_data(context): 
        T = 20
        stock_account = context.get_account('fantasy_account')
        data = context.history(['601318.XSHG'], attribute=['openPrice', 'highPrice', 'lowPrice', 'closePrice'], time_range=T+1, freq='1d', style='sat', rtype='frame')
        stk = universe[0]
        data = data[stk]
        data = pd.DataFrame(data)
        prices = context.current_price(stk) #获得最近价格
        today = Date.fromDateTime(context.current_date) 
        today = today.toISO() #转换为标准日期格式
    
        #剔除停牌的股票
        if np.isnan(prices) or prices == 0:  # 停牌或是还没有上市等原因不能交易
            return 
    
        # 计算ATR和unit
        ATR = CalcATR(data)
        value = stock_account.portfolio_value * 0.01
        context.unit = CalcUnit(value,ATR)
    
        #判断是否处于空仓的状态
        if SellComplete(context.hold_flag,stock_account.get_positions()): 
            for stk in stock_account.get_positions():
                stock_account.order_to(stk,0)
    
        #判断买卖时机
        out = IN_OR_OUT(data,prices,T)
        if out ==1 and context.hold_flag==False:  
            stock_account.order_to(stk,context.unit)
            context.add_time = 1 #入场之后持仓就+1
            context.hold_flag = True
            context.last_buy_prcie = prices             
        elif out==-1 and context.hold_flag ==True: #离场
            stock_account.order_to(stk,0)
            initialize(context)   # 重新初始化参数
         
        #判断加仓或止损
        if context.hold_flag==True and len(stock_account.get_positions())>0:   
            temp = Add_OR_Stop(prices,context.last_buy_prcie,ATR)
            if temp ==1 and context.add_time<=context.limit_unit:  # 加仓
                order_num = min(context.unit,int((stock_account.cash/prices)/100)*100)      
                stock_account.order(stk,order_num)
                context.last_buy_prcie = prices
                context.add_time += 1
            elif temp== -1:      # 止损
                stock_account.order_to(stk,0)
                initialize(context)  
    
        return
    

    写完代码后运行,结果如下:

    image.png

    综上所述,海龟交易法则的应用效果还不错。


    刺猬偷腥
    2019年1月26日

    相关文章

      网友评论

        本文标题:刺猬教你量化投资(二十五):如何用Python实现海龟交易法则

        本文链接:https://www.haomeiwen.com/subject/rxfijqtx.html