vn.py量化社区
By Traders, For Traders.
Administrator
avatar
加入于:
帖子: 158
声望: 17

海龟策略7大要素分别是品种选择、头寸规模、单位头寸限制、入场信号、逐步建仓、止损、止盈。由于品种选择无法通过不属于交易策略内容,故只对后面5大要素的进行代码解析。
 

1.头寸规模


头寸规模=(1%账户资金)/(ATR 合约规模),其代码如下

class TurtlePortfolio(object):
......
    #----------------------------------------------------------------------
    def newSignal(self, signal, direction, offset, price, volume):
......
            riskValue = self.portfolioValue * 0.01
            multiplier = riskValue / (signal.atrVolatility * size)
            multiplier = int(round(multiplier, 0))   # multiplier即为头寸规模
            self.multiplierDict[signal.vtSymbol] = multiplier
......
    #----------------------------------------------------------------------
    def sendOrder(self, vtSymbol, direction, offset, price, volume, multiplier):
        """"""
        # 计算合约持仓
        if direction == DIRECTION_LONG:
            self.unitDict[vtSymbol] += volume         # volume即为单位头寸
            self.posDict[vtSymbol] += volume * multiplier
        else:
            self.unitDict[vtSymbol] -= volume
            self.posDict[vtSymbol] -= volume * multiplier  # 实际持仓=单位头寸 * 头寸规模

 
 

2.单位头寸限制


原版海龟策略规定了4个维度的单位头寸限制,分别是

  • 单个市场:头寸上限是4个
  • 高度关联的多个市场:单个方向头寸单位不超过6个
  • 松散关联的多个市场:某一个方向上的头寸单位不超过10个
  • 单个方向:最多12个
     

基于高度关联市场和松散关联市场判断起来都非常主观,并无统一标准。在客观上的层面只能实现单个市场和单个方向的头寸限制。
在开仓交易前,需要检查上一笔交易是否盈利,若是盈利则直接返回,不进行买卖操作(仅仅适用于短周期版本的入场策略,即profitCheck=True;长周期版本对应的是profitCheck=False)

 

MAX_PRODUCT_POS = 4         # 单品种最大持仓
MAX_DIRECTION_POS = 12      # 单方向最大持仓
......
class TurtlePortfolio(object):
......
    #----------------------------------------------------------------------
    def newSignal(self, signal, direction, offset, price, volume):
......
        # 开仓
        if offset == OFFSET_OPEN:
            # 检查上一次是否为盈利
            if signal.profitCheck:
                pnl = signal.getLastPnl()
                if pnl > 0:
                    return

            # 买入
            if direction == DIRECTION_LONG:
                # 组合持仓不能超过上限
                if self.totalLong >= MAX_DIRECTION_POS:
                    return

                # 单品种持仓不能超过上限
                if self.unitDict[signal.vtSymbol] >= MAX_PRODUCT_POS:
                    return
            # 卖出
            else:
                if self.totalShort <= -MAX_DIRECTION_POS:
                    return

                if self.unitDict[signal.vtSymbol] <= -MAX_PRODUCT_POS:
                    return

 
 

3.入场信号、逐步建仓、止损、止盈


原版海龟策略提供2个版本的入场和止盈信号,分别是长周期版本和短周期版本的唐奇安通道突破。

  • 短周期信号:入场用是20日唐奇安通道,止盈用是10日唐奇安通道,用20日周期计算ATR值,有上一笔盈利当前信号无效的过滤条件。
  • 短周期信号:入场用是55日唐奇安通道,止盈用是20日唐奇安通道,用20日周期计算ATR值,无上一笔盈利当前信号无效的过滤条件。

逐步建仓的规则是每隔0.5*ATR幅度慢慢加满至4个单位头寸,止损也相应根据0.5*ATR的步进移动。
 

class TurtleSignal(object):
    #----------------------------------------------------------------------
    def __init__(self, portfolio, vtSymbol, 
                 entryWindow, exitWindow, atrWindow,
                 profitCheck=False):
......
    #----------------------------------------------------------------------
    def onBar(self, bar):
        self.bar = bar
        self.am.bar
        if not self.am.inited:
            return

        self.generateSignal(bar)
        self.calculateIndicator()       
    #----------------------------------------------------------------------
    def generateSignal(self, bar):
        """        
        判断交易信号
        """
        # 如果指标尚未初始化,则忽略
        if not self.longEntry1:
            return

        # 优先检查平仓
        if self.unit > 0:
            longExit = max(self.longStop, self.exitDown)

            if bar.low <= longExit:
                self.sell(longExit)
                return
        elif self.unit < 0:
            shortExit = min(self.shortStop, self.exitUp)
            if bar.high >= shortExit:
                self.cover(shortExit)
                return

        # 没有仓位或者持有多头仓位的时候,可以做多(加仓)
        if self.unit >= 0:
            trade = False

            if bar.high >= self.longEntry1 and self.unit < 1:
                self.buy(self.longEntry1, 1)
                trade = True

            if bar.high >= self.longEntry2 and self.unit < 2:
                self.buy(self.longEntry2, 1)
                trade = True

            if bar.high >= self.longEntry3 and self.unit < 3:
                self.buy(self.longEntry3, 1)
                trade = True

            if bar.high >= self.longEntry4 and self.unit < 4:
                self.buy(self.longEntry4, 1)
                trade = True

            if trade:
                return

        # 没有仓位或者持有空头仓位的时候,可以做空(加仓)
        if self.unit <= 0:
            if bar.low <= self.shortEntry1 and self.unit > -1:
                self.short(self.shortEntry1, 1)

            if bar.low <= self.shortEntry2 and self.unit > -2:
                self.short(self.shortEntry2, 1)

            if bar.low <= self.shortEntry3 and self.unit > -3:
                self.short(self.shortEntry3, 1)

            if bar.low <= self.shortEntry4 and self.unit > -4:
                self.short(self.shortEntry4, 1)

    #----------------------------------------------------------------------
    def calculateIndicator(self):
        """计算技术指标"""
        self.entryUp, self.entryDown = self.am.donchian(self.entryWindow)
        self.exitUp, self.exitDown = self.am.donchian(self.exitWindow)

        # 有持仓后,ATR波动率和入场位等都不再变化
        if not self.unit:
            self.atrVolatility = self.am.atr(self.atrWindow)

            self.longEntry1 = self.entryUp
            self.longEntry2 = self.entryUp + self.atrVolatility * 0.5
            self.longEntry3 = self.entryUp + self.atrVolatility * 1
            self.longEntry4 = self.entryUp + self.atrVolatility * 1.5
            self.longStop = 0

            self.shortEntry1 = self.entryDown
            self.shortEntry2 = self.entryDown - self.atrVolatility * 0.5
            self.shortEntry3 = self.entryDown - self.atrVolatility * 1
            self.shortEntry4 = self.entryDown - self.atrVolatility * 1.5
            self.shortStop = 0

......
class TurtlePortfolio(object):
......
    #----------------------------------------------------------------------
    def init(self, portfolioValue, vtSymbolList, sizeDict):
        """"""
        self.portfolioValue = portfolioValue
        self.sizeDict = sizeDict

        for vtSymbol in vtSymbolList:
            signal1 = TurtleSignal(self, vtSymbol, 20, 10, 20, True)
            signal2 = TurtleSignal(self, vtSymbol, 55, 20, 20, False)

            l = self.signalDict[vtSymbol]
            l.append(signal1)
            l.append(signal2) 
            self.unitDict[vtSymbol] = 0
            self.posDict[vtSymbol] = 0

    #----------------------------------------------------------------------
    def onBar(self, bar):
        """"""
        for signal in self.signalDict[bar.vtSymbol]:
            signal.onBar(bar)
Administrator
avatar
加入于:
帖子: 1468
声望: 68

海龟的头寸规模计算看着简单,回测却是个很麻烦的事情,但确实有效,本质其实和VaR风险管理有些类似

© 2015-2019 上海韦纳软件科技有限公司
备案服务号:沪ICP备18006526号-3