VeighNa量化社区
你的开源社区量化交易平台
Member
avatar
加入于:
帖子: 187
声望: 55

作者:张国平 ;来源:维恩的派论坛; vn,py版本:2018年7月版

VNPY中,大多策略都是基于bar分钟级别;国内tick是一秒两笔,频率不算太高。
这里尝试做了一个Tick基本准高频交易策略,只是为了实现思路。可以回测,不要直接用。。

 

回测设置


  • 回测模式改为TICK_MODE,
  • 数据库改为TICK_DB_NAME,
  • setStartDate时候initdays设为0,不需要回读历史天数,只需要当天数据;
  • TICK回测超过一天系统就报错内存不够, 所以最好一天就够。
  • 把currentTime改为开盘时间

 
 

交易信号


  • 入场: 每次读 Tick ,分析过去 10 个 tick 的的总计,如果买量大于卖量,开多单 ;反之空单。(下单价格是当前tick市价)
  • 止损:下单同时开反向2个价位的阻止单;
  • 离场:下次TICK读取时候,如果已经是买入价格正向3个点,再次判断买卖量比,如果已经不符合,市价卖出;如果还是符合原来量比就极小持有,清掉之前阻止单,改挂当前价位反向2个点阻止单。

 

代码如下

 

# encoding: UTF-8

"""


策略逻辑:
入场: 每两秒读一次,分析过去N1个tick的的总计,如果买量大于卖量K倍,且lastprice向上(最后一个值的lastprice大于或等于10个中的N2个tick的lastprice)
空单反之
下单价格是档期tick,bid or ask价格加一个点位的市价单,(止损)同时开反向2个点为的阻止单;
离场:如果已经是买入价格正向N3个点,再吃判断趋势,如果已经不符合,市价卖出。如何持有,清掉之前阻止单,改挂当前价位反向2个点阻止单。

"""

from __future__ import division
from vnpy.trader.vtGateway import *
from datetime import datetime, time
from vnpy.trader.vtObject import VtBarData
from vnpy.trader.vtConstant import EMPTY_STRING
import numpy as np
from vnpy.trader.app.ctaStrategy.ctaTemplate import (CtaTemplate,
                                                     BarGenerator,
                                                     ArrayManager)


########################################################################
class TickOneStrategy(CtaTemplate):
    """基于Tick的交易策略"""
    className = 'TickOneStrategy'
    author = u'BillyZhang'

    # 策略参数
    fixedSize = 1
    Ticksize = 10
    initDays = 0

    DAY_START = time(9, 00)  # 日盘启动和停止时间
    DAY_END = time(14, 58)
    NIGHT_START = time(21, 00)  # 夜盘启动和停止时间
    NIGHT_END = time(22, 58)

    # 策略变量
    posPrice = 0  # 持仓价格
    pos = 0       # 持仓数量


    # 参数列表,保存了参数的名称
    paramList = ['name',
                 'className',
                 'author',
                 'vtSymbol',
                 'initDays',
                 'Ticksize',
                 'fixedSize'
                 ]

    # 变量列表,保存了变量的名称
    varList = ['inited',
               'trading',
               'pos',
               'posPrice'
               ]

    # 同步列表,保存了需要保存到数据库的变量名称
    syncList = ['pos',
                'posPrice',
                'intraTradeHigh',
                'intraTradeLow']

    # ----------------------------------------------------------------------
    def __init__(self, ctaEngine, setting):
        """Constructor"""

        super(TickOneStrategy, self).__init__(ctaEngine, setting)

        #创建Array队列
        self.tickArray = TickArrayManager(self.Ticksize)

    # ----------------------------------------------------------------------
    def onminBarClose(self, bar):
        """"""

        # ----------------------------------------------------------------------

    def onInit(self):
        """初始化策略(必须由用户继承实现)"""
        self.writeCtaLog(u'%s策略初始化' % self.name)
        #tick级别交易,不需要过往历史数据


        self.putEvent()

    # ----------------------------------------------------------------------
    def onStart(self):
        """启动策略(必须由用户继承实现)"""
        self.writeCtaLog(u'%s策略启动' % self.name)
        self.putEvent()

    # ----------------------------------------------------------------------
    def onStop(self):
        """停止策略(必须由用户继承实现)"""
        self.writeCtaLog(u'%s策略停止' % self.name)
        self.putEvent()

    # ----------------------------------------------------------------------
    def onTick(self, tick):
        """收到行情TICK推送(必须由用户继承实现)"""
        # currentTime = datetime.now().time()
        currentTime = time(9,20)
        # 平当日仓位, 如果当前时间是结束前日盘15点28分钟,或者夜盘10点58分钟,如果有持仓,平仓。
        if ((currentTime >= self.DAY_START and currentTime <= self.DAY_END) or
            (currentTime >= self.NIGHT_START and currentTime <= self.NIGHT_END)):
            TA = self.tickArray
            TA.updateTick(tick)
            if not TA.inited:
                return
            if self.pos == 0:
                # 如果空仓,分析过去10个对比,ask卖方多下空单,bid买方多下多单,并防止两个差价阻止单
                if TA.askBidVolumeDif() > 0:
                    self.short(tick.lastPrice, self.fixedSize, False)
                    self.cover(tick.lastPrice + 2,self.fixedSize, True)
                elif TA.askBidVolumeDif() < 0:
                    self.buy(tick.lastPrice, self.fixedSize, False)
                    self.sell(tick.lastPrice - 2, self.fixedSize, True)

            elif self.pos > 0:
                # 如果持有多单,如果已经是买入价格正向N3个点,再次判断趋势,如果已经不符合,市价卖出。如何持有,清掉之前阻止单,改挂当前价位反向2个点阻止单。
                if  tick.lastPrice - self.posPrice >= 3:
                    if TA.askBidVolumeDif() < 0:
                        self.cancelAll()
                        self.sell(tick.lastPrice - 2, self.fixedSize, True)
                    else:
                        self.cancelAll()
                        self.sell(tick.lastPrice, self.fixedSize, False)

            elif self.pos < 0:
                # 如果持有空单,如果已经是买入价格反向N3个点,再次判断趋势,如果已经不符合,市价卖出。如何持有,清掉之前阻止单,改挂当前价位反向2个点阻止单。
                if  tick.lastPrice - self.posPrice <= -3:
                    if TA.askBidVolumeDif() > 0:
                        self.cancelAll()
                        self.cover(tick.lastPrice + 2, self.fixedSize, True)
                    else:
                        self.cancelAll()
                        self.cover(tick.lastPrice, self.fixedSize, False)
        else:
            if self.pos > 0:
                self.sell(tick.close, abs(self.pos),False)
            elif self.pos < 0:
                self.cover(tick.close, abs(self.pos),False)
            elif self.pos == 0:
                return





    # ----------------------------------------------------------------------
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""


    # ----------------------------------------------------------------------
    def onXminBar(self, bar):
        """收到X分钟K线"""



    # ----------------------------------------------------------------------
    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        pass

    # ----------------------------------------------------------------------
    def onTrade(self, trade):

        self.posPrice = trade.price
        # 同步数据到数据库
        self.saveSyncData()
        # 发出状态更新事件
        self.putEvent()

    # ----------------------------------------------------------------------
    def onStopOrder(self, so):
        """停止单推送"""
        pass

class TickArrayManager(object):
    """
    Tick序列管理工具,负责:
    1. Tick时间序列的维护
    2. 常用技术指标的计算
    """

    # ----------------------------------------------------------------------
    def __init__(self, size=10):
        """Constructor"""
        self.count = 0  # 缓存计数
        self.size = size  # 缓存大小
        self.inited = False  # True if count>=size

        self.TicklastPriceArray = np.zeros(self.size)
        self.TickaskVolume1Array = np.zeros(self.size)
        self.TickbidVolume1Array = np.zeros(self.size)
        self.TickaskPrice1Array = np.zeros(self.size)
        self.TickbidPrice1Array = np.zeros(self.size)
        self.TickopenInterestArray = np.zeros(self.size)
        self.TickvolumeArray = np.zeros(self.size)

    # ----------------------------------------------------------------------
    def updateTick(self, tick):
        """更新tick Array"""
        self.count += 1
        if not self.inited and self.count >= self.size:
            self.inited = True

        self.TicklastPriceArray[0:self.size - 1] = self.TicklastPriceArray[1:self.size]
        self.TickaskVolume1Array[0:self.size - 1] = self.TickaskVolume1Array[1:self.size]
        self.TickbidVolume1Array[0:self.size - 1] = self.TickbidVolume1Array[1:self.size]
        self.TickaskPrice1Array[0:self.size - 1] = self.TickaskPrice1Array[1:self.size]
        self.TickbidPrice1Array[0:self.size - 1] = self.TickbidPrice1Array[1:self.size]
        self.TickopenInterestArray[0:self.size - 1] = self.TickopenInterestArray[1:self.size]
        self.TickvolumeArray[0:self.size - 1] = self.TickvolumeArray[1:self.size]

        self.TicklastPriceArray[-1] = tick.lastPrice
        self.TickaskVolume1Array[-1] = tick.askVolume1
        self.TickbidVolume1Array[-1] = tick.bidVolume1
        self.TickaskPrice1Array[-1] = tick.askPrice1
        self.TickbidPrice1Array[-1] = tick.bidPrice1
        self.TickopenInterestArray[-1] = tick.openInterest
        self.TickvolumeArray[-1] = tick.volume

    def askBidVolumeDif(self):
        return (self.TickaskVolume1Array.sum() - self.TickbidVolume1Array.sum())
Member
avatar
加入于:
帖子: 16
声望: 3
            # 如果持有空单,如果已经是买入价格反向N3个点,再次判断趋势,如果已经不符合,市价卖出。如何持有,清掉之前阻止单,改挂当前价位反向2个点阻止单。
            if  tick.lastPrice - self.posPrice <= -3:
                if TA.askBidVolumeDif() > 0:
                    self.cancelAll()  
                    self.cover(tick.lastPrice + 2, self.fixedSize, True) // !!!!!!!!!!!!!!!!!!!!!!
                else:
                    self.cancelAll()
                    self.cover(tick.lastPrice, self.fixedSize, False)

!感叹号这里回测没有问题。但是实盘中应该是拿到前一个撤单命令成功的回报后,再发出新订单(无论是平仓开仓)吧。不然,不知道之前限价单是否撤单成功,就发单,会导致交易逻辑出错,比如由于某种原因撤单没有成功,可是新的单子就发出去了。
另外,下单同时开反向2个价位的阻止单,是不是在 onTrade中,收到成交回报马上发限价单更快。有点类似剥头皮的策略了。
想用这个框架,写一个一定时间内限价单不成交后,再发追单的功能。想损失一点时间,换回一点价格上的收益。可是,发现自己搞不定,会涉及到发送各种订单的管理。
不知是否会有官方支持功能。减少用户开发成本。
多谢!

Member
avatar
加入于:
帖子: 3
声望: 0

“setStartDate时候initdays设为0” 现在vnpy2.0之后在哪里设置呀

Member
avatar
加入于:
帖子: 337
声望: 27

这个策略是基于vnpy1.9版本的,现在已经停止维护了,想要基于tick数据回测可以参考此贴

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

沪公网安备 31011502017034号

【用户协议】
【隐私政策】
【免责条款】