VeighNa量化社区
你的开源社区量化交易平台
hxxjava's Avatar
Member
离线
419 帖子
声望: 155

从委托到接受、等待、部分成交、全部成交,需要一个过程,你以为象计算机指令一样C=A+B,这边执行,那边就可以得到C的结果吗?
在on_tick()中下单,每秒钟2次,怎么可能立即都有成交结果,没有成交结果,怎么self.pos会发生变化?当然会连续下单,“基本上判断pos废了”就是错误 的!

用Python的交易员 wrote:

这是给各种机构做市商双边报价用的,vn.py作为一套标准的底层框架,不是只有开源的功能嘛

谢谢答复!

很久没有升级了,今天升级了。发现很多新的东西,不知道有什么有,问问官方QuoteRequest有什么用?

  • list text here在vnpy>trader>object.py中增加了下面的代码:

    @dataclass
    class QuoteRequest:
      """
      Request sending to specific gateway for creating a new quote.
      """
    
      symbol: str
      exchange: Exchange
      bid_price: float
      bid_volume: int
      ask_price: float
      ask_volume: int
      bid_offset: Offset = Offset.NONE
      ask_offset: Offset = Offset.NONE
      reference: str = ""
    
      def __post_init__(self):
          """"""
          self.vt_symbol = f"{self.symbol}.{self.exchange.value}"
    
      def create_quote_data(self, quoteid: str, gateway_name: str) -> QuoteData:
          """
          Create quote data from request.
          """
          quote = QuoteData(
              symbol=self.symbol,
              exchange=self.exchange,
              quoteid=self.quoteid,
              bid_price=self.bid_price,
              bid_volume=self.bid_volume,
              ask_price=self.ask_price,
              ask_volume=self.ask_volume,
              bid_offset=self.bid_offset,
              ask_offset=self.ask_offset,
              reference=self.reference,
              gateway_name=gateway_name,
          )
          return quote
  • 在vnpy>trader>gateway.py中的BaseGateway类型总增加了下面的函数:

      def send_quote(self, req: QuoteRequest) -> str:
          """
          Send a new two-sided quote to server.
    
          implementation should finish the tasks blow:
          * create an QuoteData from req using QuoteRequest.create_quote_data
          * assign a unique(gateway instance scope) id to QuoteData.quoteid
          * send request to server
              * if request is sent, QuoteData.status should be set to Status.SUBMITTING
              * if request is failed to sent, QuoteData.status should be set to Status.REJECTED
          * response on_quote:
          * return vt_quoteid
    
          :return str vt_quoteid for created QuoteData
          """
          return ""   # 返回了空字符串,

    返回了空字符串,其实什么用也没有,一个接口类函数。貌似是让其他的派生的特定网关来实现这个函数。
    可是我查询了下,CTP、XTP等网关,没有一个实现了该函数,系统中也没有任何一个地方直接或者间接低调用过该send_quote()函数。

  • 从注释来看,好像是用来产生一个引用的作用?请问vnpy官方:这个东西有用吗?

WSC wrote:

请问这个功能加入到最新版的vnpy中了吗?
另外可以在本地储存手续费率和保证金率用于回测自动调用吗?

据我所知,应该还没有。

是的,保存到数据库也是可以的。不过还是比较复杂的。

1 集合竞价时段

股票、期货合约都有集合竞价时段,如国内期货合约为前一交易日的21:00前5分钟,股指期货合约为当前交易日的9:30前5分钟,股票合约的为当前交易日的9:30之前。
集合竞价完成之后通常在开市前1分钟提供CTP接口推送第一个tick,注意:这个tick的时间戳为开市前1分钟,而不在各个交易时间段内!
如:
国内期货合约如果第一个交易段为21:00,那么这个tick的时间戳为20:59
国内股指期货合约为当前交易日的9:30,那么这个tick的时间戳为9:29

2 vnpy当前的BarGenerator无法正确处理该tick

实盘中每个合约都会有集合竞价时段,这时候采用自带的BarGenerator来合成1分钟bar就会有问题,因为20:59:00的那个tick既不属于上一交易日的1分钟bar(15:59)的,也不属于21:00的那一个1分钟bar,当然就只能够孤独地自成一个1bar啦!由此带来的问题是21:00的那一个1分钟bar的开盘价和成交量(这个成交量可能是很大)都可能是错了。
当然由此导致的5分钟、10分钟、15分钟、30分钟乃至1日的bar都可能是有问题的,因为它们都是1分钟bar合成的。

3 解决方法:

  • 从合约信息中提前交易时间段信息入手,通常某个交易日的第一个交易时间段前1分钟收到的tick应该归入该交易日的第一个1分钟bar,
  • 如国内期货的为前一交易日的21:00的前1分钟收到的tick应该归入21:00的那一个1分钟bar,
  • 股指期货的为当前交易日的9:30的前1分钟收到的tick应该归入9:30的那一个1分钟bar。
  • 在正确处理了交易日首个1分钟bar合成的基础上,其他的n分钟bar的合成才可能是正确的。

4 顺便谈谈没有办法合成90分钟K线的问题

你现在用BarGenerator没有办法合成90分钟K线,不信你试试看!挺搞笑的一个问题!

在此呼吁vnpy官方,重视CTP接口中的合约信息的作用,重构BarGenerator,作出一个解决当前问题众多的bar合成器。

天下苦此BarGenerator久矣!

jingsiaosing wrote:

一个类似的问题:开盘第一个tick的时间戳是20:59:00,第二个tick的时间戳是21:00:00, 他俩的minute不一样,所以在收到第二个tick的时候就会推送bar,bar的时间戳是20:59:00,是这样吗?

这也是也个问题,实盘中每个合约都会有集合竞价时段,这时候采用自带的BarGenerator来合成1分钟bar就会有问题,因为20:59:00的那个tick既不属于上一交易日的1分钟bar(15:59)的,也不属于21:00的那一个1分钟bar,当然就只能够孤独地自成一个1bar啦!由此带来的问题是21:00的那一个1分钟bar的开盘价和成交量(这个成交量可能是很大)都可能是错了。
当然由此导致的5分钟、10分钟、15分钟、30分钟乃至1日的bar都可能是有问题的,因为它们都是1分钟bar合成的。
解决方法:

  • 从合约信息中提前交易时间段信息入手,通常某个交易日的第一个交易时间段前1分钟收到的tick应该归入该交易日的第一个1分钟bar,
  • 如国内期货的为前一交易日的21:00的前1分钟收到的tick应该归入21:00的那一个1分钟bar,
  • 股指期货的为当前交易日的9:30的前1分钟收到的tick应该归入9:30的那一个1分钟bar。
  • 在正确处理了交易日首个1分钟bar合成的基础上,其他的n分钟bar的合成才可能是正确的。

wangjiancc wrote:

老师您好!
我的版本是2.1.9, 在 类 OrderItem 中有一个引用错误, self.orders : Dict[int,Dict[str,Order]] = {} # {ix:{orderid:order}}
这个Order 是引用那个对象,谢谢!

好久没有升级,我还不知道,这两天我升级下,看看是什么问题。

其实临时K线是每个tick都会变化的,岂止是1分钟!
1、目前的BarGenerator,如果你生成N分钟的K线,是等到完整的window_bar生成之后才执行on_Nmin_bar()之类的。缺少执行临时K线的机制。
2、其实这样也有好处,那就是在on_Nmin_bar()里计算产生的交易信号是稳定的,因为K线已经走完,不会发生变化了。
3、可是坏处也很明显,有时候一根巨大的临时K线会让你的交易有浮盈变成浮亏,可是你的策略会无动于衷,不动作!
4、那么你会说临时K线好,其实也不然!如果你依据临时K线计算产生交易信号,会出现频繁的信号忽闪问题,就是临时K线刚K开始就出现开仓信号,于是你的策略立即开仓了,可是之后的行情使得开仓信号又消失了,怎么办?你还要考虑把已经开了的仓位平掉,如此反复,光是手续费你都受不了!

所以:对临时K线的使用要有利弊分析,通盘考虑,不是一个扩展那么简单的!

不需要修改ArrayManager,与它无关,需要扩展BarGenerator的update_bar(),使之,
应该是在策略里面增加一个def on_temp_bar(self,bar:BarData):这样的推送接口,
当每次执行on_tick执行合成bar,判断bar是是否已经完成,来决定是执行on_temp_bar()还是on_bar()。

小天下 wrote:

也就是说,我同事使用5min,15min,30min在同一个策略中的时候,比如在10:08分,其实我能看到5min中的最后价格是10:00-10:04:59的价格,而15分钟,只能看到9:45-9;59:59秒的价格,而30min只能看到9:30-9:59:59秒的价格,就是只出现不再变化的K线,而不会出现临时K线?这样理解对么?所以如果需要临时k,就需要自己去改这个BarGenerator,大神这样理解 对么?

非常正确!

呵呵,两个错误:
1、rb888是米筐构造的一个前复权的螺纹期货合约,实际是不存在的,所以无法获得它的合约信息,因此无法获取它的交易时间段信息。而我这个RBreaker策略是必须使用交易时间段信息,所以出错!
2、你的K线周期设置为d,那么没有分钟数据,每次只有一个完整的日K先数据,还谈什么日内的上下突破?下载的数据必须为1m 。

换成rb2105.SHFE,K线周期设置为1m,把开始和结束日期改短些,再试试。

chenyi wrote:

hxxjava wrote:

2.5 显示效果

description

请教楼主,最下方右侧图的,策略账户的代码方便发一下吗,学习一下,谢谢~!

好眼力!这个小小的窗口中可是包含了策略账户的完整功能,可以管理并且策略的出入金、委托记录查询和成交记录查询统计等复杂的更能!
只是涉及修改和增加代码的地方比较多,而且我很久没有升级代码,我的策略账户的一些关键代码被vnpy官方借用,可能会和目前的系统有冲突的地方,所以一直不好跟随升级。你的系统代码应该是最新的,公布了之后可能会有比较多的麻烦,也让你为难。
等我有时间了,备份起我目前的系统的代码,升级到最新,好好查询下兼容性的问题,再上传为宜。

谢谢管理员!
是的,这么设计非常合理,否则在初始化和启动之间就会出现K线数据的缺失。
明白道理就不会觉得奇怪,而且对CTA策略的运行机制理解的更加透彻!

一、现象描述

最近编写好了自己的CTA策略,上线运行,发现一个奇怪的现象:
1、设置好策略
2、初始化策略
3、运行策略
策略已经运行起来,一切都表现的正常——可以开仓、平仓。
可是当我想把策略停止下来,我发现交易停止了,可是on_bar()函数中的一些调试信息(为了观察策略的活动而增加的)仍然还在继续工作!
怪了,明明策略研究停止了的,为什么on_bar()函数仍然在执行?

二、原因分析

原来策略中涉及到的合约与CTA策略是被添加到在CtaEngine中的symbol_strategy_map字典中了,而消息EVENT_TICK和CtaEngine的process_tick_event()被注册到消息引擎中,这样子只要接口接受到tick数据就会调用CtaEngine的process_tick_event()。

class CtaEngine(BaseEngine):
    ... 
    ...

    def init_engine(self):
        self.init_rqdata()
        self.load_strategy_class()
        self.load_strategy_setting()
        self.load_strategy_data()
        self.register_event()
        self.write_log("CTA策略引擎初始化成功")

    def register_event(self):
        """"""
        self.event_engine.register(EVENT_TICK, self.process_tick_event)
        self.event_engine.register(EVENT_ORDER, self.process_order_event)
        self.event_engine.register(EVENT_TRADE, self.process_trade_event)
        self.event_engine.register(EVENT_POSITION, self.process_position_event)

    def process_tick_event(self, event: Event):
        """"""
        tick = event.data

        strategies = self.symbol_strategy_map[tick.vt_symbol]
        if not strategies:
            return

        self.check_stop_order(tick)

        for strategy in strategies:
            if strategy.inited:
                self.call_strategy_func(strategy, strategy.on_tick, tick)

而CtaEngine的process_tick_event()中使用tick的vt_symbol找到symbol_strategy_map字典中对应所有策略,然后把tick逐个推送给策略的on_tick()函数,而这里只是判断每个策略的状态是否为inited==True。

三、如果把已经运行的策略停止会怎样?

如果说策略已经初始化了,那么不管是否被主动停止(trading==False),策略的on_tick()函数都会被执行!进而策略的on_bar()也会被执行,只是所有的交易函数均不会执行而已。
这样对停止策略的处理是否有点文不对题?既然已经停止策略,就应该把它停止下来,可是实际的情况是策略处理交易动作被限制之外,其他的处理逻辑和流程仍然再执行,并没有停止下来!
下面是CtaTemplate类中的几个交易相关函数的代码,其中就有策略的trading状态的限制条件:

    def send_order(
        self,
        direction: Direction,
        offset: Offset,
        price: float,
        volume: float,
        stop: bool = False,
        lock: bool = False
    ):
        """
        Send a new order.
        """
        if self.trading:
            vt_orderids = self.cta_engine.send_order(
                self, direction, offset, price, volume, stop, lock
            )
            return vt_orderids
        else:
            return []

    def cancel_order(self, vt_orderid: str):
        """
        Cancel an existing order.
        """
        if self.trading:
            self.cta_engine.cancel_order(self, vt_orderid)

    def cancel_all(self):
        """
        Cancel all orders sent by strategy.
        """
        if self.trading:
            self.cta_engine.cancel_all(self)

没有那么多一劳永逸的事情。
不过还是有一些更好的方法的,联合rqdatac的一些接口,可以做到许多意想不到的功能的:https://www.vnpy.com/forum/topic/4064-ni-de-kxian-ying-gai-shi-que-ding-de-ke-shi-ji-shang-que-bu-shi

你的这个函数离的实现是什么?5分钟K线是任何创建的?不交代清楚无法判断问题的!

def init__ (
self,
cta
engine: Any ,
strategy- name: str ,
vt_ symboL: str ,
setting: dict,
):...

level999 wrote:

楼主,添加启动错误,请分析下什么原因啊

把这一句的

import vnpy.app.cta_strategy.base import EngineType     # hxxjava add

改成

from vnpy.app.cta_strategy.base import EngineType     # hxxjava add

就可以了。

黄裳 wrote:

感谢回复,我知道这个不难。只是有没有必要使用这种数据,如果使用的话,计算出来的指标或许会有反复,反而麻烦。

类比文华财经之类的软件,在on_bar()中使用1分钟bar,或者在on_5min_bar()中使用5分钟bar的话,这个叫收盘价模式。
而临时的bar则随tick而改变,属于非收盘价模式。
二者的区别是:收盘价模式下采用bar计算的指标信号是不会出现信号忽闪,而非收盘价模式采用bar计算的指标信号是会出现信号忽闪的,需要配合更高层的交易控制逻辑,必然信号出现多长时间算是信号确认。
例如:
非收盘价模式采用bar计算指标信号,确认入场信号10秒,确认离场信号5秒。
入场信号出现,策略下单了,可是3秒后又消失了,那么策略应该自带把之前下单的仓位平掉。
假如你持有仓位,离场场信号出现,策略立即平仓,可是2秒后又消失了,那么策略应该自带把之前平仓的仓位再拿回来。
由此可见非收盘价模式对价格的变化更为快速,但是要求对交易的控制更为复杂,不是实现了临时K线就万事大吉了!

黄裳 wrote:

也就是说,想要得到随时更新的5分钟线,30分钟线,就要从新写自己的BarGenerator,非常感谢

是的,就要重新写自己的BarGenerator。
你所说的随时更新的5分钟线,30分钟线其实是临时K线,而目前的BarGenerator没有直接提供你要的临时K线机制。
不过你可以扩展一个BarGenerator类,实现一个属性或者方法,如gen_temp_bar()和temp_bar(),具体办法:

def gen_temp_bar(self)
     self.temp_bar = self.window_bar与self.bar的合成

当然这只是伪代码,自己实现下,应该不难。

def temp_bar(self)
     return self.temp_bar

其中gen_temp_bar()需要在策略的on_tick()的函数中最后被执行,

    def on_tick(self, tick: TickData):
        """
        Callback of new tick data update.
        """
        self.bg.update_tick(tick)
        self.bg.gen_temp_bar()

这样你就可以得到window_bar的临时K线了。

© 2015-2022 微信 18391752892
备案服务号:沪ICP备18006526号

沪公网安备 31011502017034号

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