Merge pull request #1660 from vnpy/hour_bar

[Add]support hour bar generation
This commit is contained in:
vn.py 2019-05-05 14:33:49 +08:00 committed by GitHub
commit 768e24368c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -10,7 +10,7 @@ import numpy as np
import talib import talib
from .object import BarData, TickData from .object import BarData, TickData
from .constant import Exchange from .constant import Exchange, Interval
def extract_vt_symbol(vt_symbol: str): def extract_vt_symbol(vt_symbol: str):
@ -113,21 +113,33 @@ class BarGenerator:
""" """
For: For:
1. generating 1 minute bar data from tick data 1. generating 1 minute bar data from tick data
2. generateing x minute bar data from 1 minute data 2. generateing x minute bar/x hour bar data from 1 minute data
Notice:
1. for x minute bar, x must be able to divide 60: 2, 3, 5, 6, 10, 15, 20, 30
2. for x hour bar, x can be any number
""" """
def __init__( def __init__(
self, on_bar: Callable, xmin: int = 0, on_xmin_bar: Callable = None self,
on_bar: Callable,
window: int = 0,
on_window_bar: Callable = None,
interval: Interval = Interval.MINUTE
): ):
"""Constructor""" """Constructor"""
self.bar = None self.bar = None
self.on_bar = on_bar self.on_bar = on_bar
self.xmin = xmin self.interval = interval
self.xmin_bar = None self.interval_count = 0
self.on_xmin_bar = on_xmin_bar
self.window = window
self.window_bar = None
self.on_window_bar = on_window_bar
self.last_tick = None self.last_tick = None
self.last_bar = None
def update_tick(self, tick: TickData): def update_tick(self, tick: TickData):
""" """
@ -172,32 +184,60 @@ class BarGenerator:
""" """
Update 1 minute bar into generator Update 1 minute bar into generator
""" """
if not self.xmin_bar: # If not inited, creaate window bar object
self.xmin_bar = BarData( 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, symbol=bar.symbol,
exchange=bar.exchange, exchange=bar.exchange,
datetime=bar.datetime, datetime=dt,
gateway_name=bar.gateway_name, gateway_name=bar.gateway_name,
open_price=bar.open_price, open_price=bar.open_price,
high_price=bar.high_price, high_price=bar.high_price,
low_price=bar.low_price low_price=bar.low_price
) )
# Otherwise, update high/low price into window bar
else: else:
self.xmin_bar.high_price = max( self.window_bar.high_price = max(
self.xmin_bar.high_price, bar.high_price) self.window_bar.high_price, bar.high_price)
self.xmin_bar.low_price = min( self.window_bar.low_price = min(
self.xmin_bar.low_price, bar.low_price) self.window_bar.low_price, bar.low_price)
self.xmin_bar.close_price = bar.close_price # Update close price/volume into window bar
self.xmin_bar.volume += int(bar.volume) self.window_bar.close_price = bar.close_price
self.window_bar.volume += int(bar.volume)
if not (bar.datetime.minute + 1) % self.xmin: # Check if window bar completed
self.xmin_bar.datetime = self.xmin_bar.datetime.replace( finished = False
second=0, microsecond=0
)
self.on_xmin_bar(self.xmin_bar)
self.xmin_bar = None 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
def generate(self): def generate(self):
""" """