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

VNPY中的BarGenerator的构造函数是这样的:

class BarGenerator:
    ......
    def __init__(self,on_bar: Callable,window: int = 0,on_window_bar: Callable = None,interval: Interval = Interval.MINUTE ):
    ... ...

    def update_bar(self, bar: BarData) -> None:
        """
        Update 1 minute bar into generator
        """
        # If not inited, creaate window bar object
        if not self.window_bar:
            # Generate timestamp for bar data
            if self.interval == Interval.MINUTE:
                dt = bar.datetime.replace(second=0, microsecond=0)
            else:
                dt = bar.datetime.replace(minute=0, second=0, microsecond=0)

            self.window_bar = BarData(
                symbol=bar.symbol,
                exchange=bar.exchange,
                datetime=dt,
                gateway_name=bar.gateway_name,
                open_price=bar.open_price,
                high_price=bar.high_price,
                low_price=bar.low_price
            )
        # Otherwise, update high/low price into window bar
        else:
            self.window_bar.high_price = max(
                self.window_bar.high_price, bar.high_price)
            self.window_bar.low_price = min(
                self.window_bar.low_price, bar.low_price)

        # Update close price/volume into window bar
        self.window_bar.close_price = bar.close_price
        self.window_bar.volume += int(bar.volume)
        self.window_bar.open_interest = bar.open_interest

        # Check if window bar completed
        finished = False

        if self.interval == Interval.MINUTE:
            # x-minute bar
            if not (bar.datetime.minute + 1) % self.window:
                finished = True
        elif self.interval == Interval.HOUR:
            if self.last_bar and bar.datetime.hour != self.last_bar.datetime.hour:
                # 1-hour bar
                if self.window == 1:
                    finished = True
                # x-hour bar
                else:
                    self.interval_count += 1

                    if not self.interval_count % self.window:
                        finished = True
                        self.interval_count = 0

        if finished:
            self.on_window_bar(self.window_bar)
            self.window_bar = None

        # Cache last bar object
        self.last_bar = bar

而Interval类型是这样的:

class Interval(Enum):
    """
    Interval of bar data.
    """
    MINUTE = "1m"
    HOUR = "1h"
    DAILY = "d"
    WEEKLY = "w"

结论:

BarGenerator虽然传入的Interval类型,但是它只考虑的Interval.MINUTE和Interval.HOUR两个单位,而它合成N分钟和N小时的K线是没有问题的。
也就是说,你不可以是Interval.DAILY和Interval.WEEKLY做单位,因为它使用的米筐接口的1分钟历史数据,没有使用米筐的1h和1d数据。

因此你不可以这么创建月K线

1) self.bgm = BarGenerator(self.on_bar, 4, self.on_month_bar,interval=Interval.WEEKLY)
2) self.bgm = BarGenerator(self.on_bar,20, self.on_month_bar,interval=Interval.DAILY)
因为BarGenerator没有考虑 Interval.DAILY和Interval.WEEKLY时间间隔

创建日线以上周期K线必须考虑合约交易时间段:

交易时间段决定日K线小时数

使用Interval.MINUTE作为参数时,window不可以超过59,它表示合成不了成功1小时的K线,而Interval.HOUR作为参数时,是对1小时K线进行计数,然后把的self.interval_count % self.window作为条件来判断是否查询window小时K线是否结束的,它可以用来表达日线以上周期K线。
所以创建日线以上周期K线,你最大只可以使用Interval.HOUR为单位,而且它又是参考自然时间的生成机制:

举例:
rb2010的交易时间段 :21:00-23:30(4根小时K线)09:00-10:15 10:30-11:30(3根小时K线) 13:30-15:00(2根小时K线),因此需要9根1小时K线合成
ag2012的交易时间段 :21:00-02:30 (6根小时K线)09:00-10:15 10:30-11:30 (3根小时K线)13:30-15:00(2根小时K线),因此需要11根1小时K线合成
IF88 沪深主力连续 交易时间段:09:30-11:30(3根小时K线),13:00-15:00(2根小时K线),每日时长:5小时,因此需要6根1小时K线合成
T2009 10年期国债2009 交易时间段:09:30-11:30(3根小时K线),13:00-15:15(3根小时K线),因此需要6根1小时K线合成
TS2103 2年期国债2103 交易时间段:09:30-11:30(3根小时K线),13:00-15:15(3根小时K线),因此需要6根1小时K线合成

如果看不明白上面的叙述,就静下心来慢慢想一些吧,想不明白就看看BarGenerator的update_bar()函数代码就明白了。

下面仅以rb2010和ag2012合约为例来说明,其他周期的类似。

日K线产生器

rb2010的日K线产生器:
self.bgm = BarGenerator(self.on_bar, 9, self.on_day_bar,interval=Interval.HOUR)
ag2012的日K线产生器:
self.bgm = BarGenerator(self.on_bar, 11, self.on_day_bar,interval=Interval.HOUR)

5日K线合成周K线

rb2010的周K线产生器:
self.bgm = BarGenerator(self.on_bar, 45, self.on_week_bar,interval=Interval.HOUR)
ag2012的周K线产生器:
self.bgm = BarGenerator(self.on_bar, 55, self.on_week_bar,interval=Interval.HOUR)

4周K线合成月K线

rb2010的月K线产生器:
self.bgm = BarGenerator(self.on_bar, 180, self.on_month_bar,interval=Interval.HOUR)
ag2012的月K线产生器:
self.bgm = BarGenerator(self.on_bar, 220, self.on_month_bar,interval=Interval.HOUR)

注意:

这些合成的日K能够保证是日内对齐的,但周K和月K线并不能够保证是周内和月内对齐的,它取决你什么时候启动你的策略。

更好的创建方法:

更好的创建方法先对BarGenerator进行扩展,实现考虑交易时间段的日K、周K的生成机制,当然创建时需要传入交易时间段参数。这里就不在说了,以后可以专门讨论。

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

不错,
直接在BarGenerator添加Interval.DAILY不加处理的...夜盘的21:00-23:30 这个时间段是给了前一天的K线吧....

Member
avatar
加入于:
帖子: 419
声望: 170

大王 wrote:

不错,
直接在BarGenerator添加Interval.DAILY不加处理的...夜盘的21:00-23:30 这个时间段是给了前一天的K线吧....

不是这个逻辑,当遇上节假日,尤其是长假你就知道不可以这样了。参考下这个:https://www.vnpy.com/forum/topic/4064-ni-de-kxian-ying-gai-shi-que-ding-de-ke-shi-ji-shang-que-bu-shi

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

mark

Member
avatar
加入于:
帖子: 93
声望: 14

请教一个问题,在盘中实时行情之下,行情每跳一下,相应的一分钟线,以及基于一分钟线合成的五分钟,30分钟,以及小时线会跟着跳动吗??也就是随着每一个tick的到来,会自动更新1分钟线。但五分钟以及以后的周期,是不是也是同步更新的??
或者只是一分钟线完成以后,才更新五分钟线?也就是五分钟线每个bar,只更新五次。每一分钟更新一次??

Member
avatar
加入于:
帖子: 4618
声望: 284

不会,要走完才更新

Member
avatar
加入于:
帖子: 419
声望: 170

黄裳 wrote:

请教一个问题,在盘中实时行情之下,行情每跳一下,相应的一分钟线,以及基于一分钟线合成的五分钟,30分钟,以及小时线会跟着跳动吗??也就是随着每一个tick的到来,会自动更新1分钟线。但五分钟以及以后的周期,是不是也是同步更新的??
或者只是一分钟线完成以后,才更新五分钟线?也就是五分钟线每个bar,只更新五次。每一分钟更新一次??

用户CTA策略使用vnpy系统自带的BarGenerator时,假如你创建K线生成器的方法是:

self.bg1 = BarGenerator(self.on_bar,5,self.on_5min_bar)
self.bg2 = BarGenerator(self.on_bar,30,self.on_30min_bar)

那么对tick数据的处理节奏是:

1、用户策略的on_tick()每个tick都会被执行,on_tick()接受tick推送数据,产生1分钟bar,tick数据的时间的分钟数与1分钟bar的分钟数不相同时结束1分钟bar,然后执行on_bar
2、在交易时段内每1分钟都会执行on_tick(),on_bar()接受1分钟bar,利用这些1分钟bar合成出5分钟bar,然后执行on_5min_bar(),利用这些1分钟bar合成出30分钟bar,然后执行on_30min_bar()
3、在交易时段内每5分钟都会执行on_5min_bar(),on_5min_bar()接受5分钟bar,你的策略就可以利用这些5分钟bar进行交易的入场和离场信号。
4、在交易时段内每30分钟都会执行on_30min_bar(),on_30min_bar()接受30分钟bar,你的策略就可以利用这些30分钟bar进行交易的入场和离场信号。
因此,在不是整5分钟的时候,5分钟bar是不会被更新的;在不是整30分钟的时候,30分钟bar是不会被更新的.

Member
avatar
加入于:
帖子: 93
声望: 14

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

Member
avatar
加入于:
帖子: 4618
声望: 284

self.bg.bar,就是正在合成中的那一根K线了,
self.bg.window_bar,就是正在合成中的那一根多周期K线了

Member
avatar
加入于:
帖子: 419
声望: 170

黄裳 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线了。

Member
avatar
加入于:
帖子: 93
声望: 14

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

Member
avatar
加入于:
帖子: 419
声望: 170

黄裳 wrote:

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

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

Member
avatar
加入于:
帖子: 17
声望: 1

能不能不用分钟K的数量来生成日线?
直接用时间把分钟K分割开(大于上一个交易日15:00,小于等于当日交易日15:00)这段时间分钟K合成一根日K。

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

用于已知交易时段的实盘是可以的...

回测时,需要注意下,比如RB需要9根1小时K线合成
BarGenerator(self.on_bar, 9, self.on_day_bar,interval=Interval.HOUR)

假如RB是2015年才开启夜盘,2015年以前的日线是7根,,,,,如果不区分开....就又乱了...

Member
avatar
加入于:
帖子: 419
声望: 170

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

Member
avatar
加入于:
帖子: 14
声望: 1

不如直接数据库里添加日线数据不是更简单粗暴,而且日线数据基本免费的也不会像1min那种错误百出

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

也就是说,我同事使用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,大神这样理解 对么?

Member
avatar
加入于:
帖子: 419
声望: 170

小天下 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,大神这样理解 对么?

非常正确!

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

我也遇到这个困难,具体怎么改,哪位老师可以指点吗?

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

hxxjava wrote:

黄裳 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线了。

大神,这样需不需要同时改进class ArrayManager(object)或者重新 定制一个全新的或者扩展的ArrayManager函数来配套使用,因为每次推出新的bar,它也将新的close,high等数据存储进去了!

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

沪公网安备 31011502017034号

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