def update_bars_backward(self, n): if self.data_source == 'HK': with self.chart.updating() as chart: symbol = self.symbol_line.text() start = chart._manager.get_bar(chart.last_ix).datetime data = self._querier[start:n:symbol] for d in data: b = BarData('KRData', symbol, Exchange.HKFE, d.datetime, None, d.volume, 0, d.open, d.high, d.low, d.close) chart.update_bar(b) elif self.data_source == 'IB': with self.chart.updating() as chart: symbol = self.symbol_line.text() barType = {'1min': '1 min', '5min': '5 mins', '15min': '15 mins', '30min': '30 mins', '60min': '60 mins', '1day': '1 day'}.get(self.period,'1 min') minutes = {'1min': 1, '5min': 5, '15min': 15, '30min': 30, '60min': 60, '1day': 1440}.get(self.period, 1) start = chart._manager.get_bar(chart.last_ix).datetime per_bar_period = dt.timedelta(minutes=minutes) if dt.datetime.now() - start <= per_bar_period: return n = min(60, n) contract = self._querier.verifyContract(symbol) data = self._querier.get_bars_from_ib(contract, barType=barType, start=start, end=start + per_bar_period * n) for _, d in data.iterrows(): b = BarData('KRData', symbol, Exchange.HKFE, d.datetime, None, d.volume, 0, d.open, d.high, d.low, d.close) chart.update_bar(b)
def on_tick(self, tick: TickData): """收到行情TICK推送(必须由用户继承实现)""" # 聚合为1分钟K线 tickMinute = tick.datetime.minute if tickMinute != self.barMinute: if self.bar: self.on_bar(self.bar) bar = BarData(datetime=tick.datetime, exchange=tick.exchange, gateway_name=tick.gateway_name, symbol=tick.symbol) # bar.vt_symbol = tick.vt_symbol # bar.symbol = tick.symbol # bar.exchange = tick.exchange bar.open_price = tick.last_price bar.high_price = tick.last_price bar.low_price = tick.last_price bar.close_price = tick.last_price # bar.date = tick.date # bar.time = tick.time bar.datetime = tick.datetime # K线的时间设为第一个Tick的时间 self.bar = bar # 这种写法为了减少一层访问,加快速度 self.barMinute = tickMinute # 更新当前的分钟 else: # 否则继续累加新的K线 bar = self.bar # 写法同样为了加快速度 bar.high_price = max(bar.high_price, tick.last_price) bar.low_price = min(bar.low_price, tick.last_price) bar.close_price = tick.last_price
def load_bar_data( spread: SpreadData, interval: Interval, start: datetime, end: datetime, pricetick: float = 0 ): """""" # Load bar data of each spread leg leg_bars: Dict[str, Dict] = {} for vt_symbol in spread.legs.keys(): symbol, exchange = extract_vt_symbol(vt_symbol) bar_data: List[BarData] = database_manager.load_bar_data( symbol, exchange, interval, start, end ) bars: Dict[datetime, BarData] = {bar.datetime: bar for bar in bar_data} leg_bars[vt_symbol] = bars # Calculate spread bar data spread_bars: List[BarData] = [] for dt in bars.keys(): spread_price = 0 spread_value = 0 spread_available = True for leg in spread.legs.values(): leg_bar = leg_bars[leg.vt_symbol].get(dt, None) if leg_bar: price_multiplier = spread.price_multipliers[leg.vt_symbol] spread_price += price_multiplier * leg_bar.close_price spread_value += abs(price_multiplier) * leg_bar.close_price else: spread_available = False if spread_available: if pricetick: spread_price = round_to(spread_price, pricetick) spread_bar = BarData( symbol=spread.name, exchange=exchange.LOCAL, datetime=dt, interval=interval, open_price=spread_price, high_price=spread_price, low_price=spread_price, close_price=spread_price, gateway_name="SPREAD", ) spread_bar.value = spread_value spread_bars.append(spread_bar) return spread_bars
def query_history(self, req: HistoryRequest): """""" self.write_log("FUTU Gateway:开始下载") print(f"FUTU download{req.symbol}") print(f"req.startdate:{req.start} - {req.end}") code = convert_symbol_vt2futu(req.symbol, req.exchange) start = req.start.strftime("%Y-%m-%d") end = req.end.strftime("%Y-%m-%d") ret, data, self.page_req_key = self.quote_ctx.request_history_kline( code, start=start, end=end, ktype=INTERVAL_KLINE_VT2FUTU[req.interval], max_count=1) dt = datetime.strptime(data.ix[0].time_key, "%Y-%m-%d %H:%M:%S") data_bar = BarData(gateway_name=self.gateway_name, symbol=req.symbol, exchange=req.exchange, datetime=dt, interval=req.interval, volume=float(data.volume), open_price=data.open, high_price=data.high, low_price=data.low, close_price=data.close) self.history_list.append(data_bar) while self.page_req_key is not None: ret, data, self.page_req_key = self.quote_ctx.request_history_kline( code, start=start, end=end, ktype=INTERVAL_KLINE_VT2FUTU[req.interval], max_count=1000, page_req_key=self.page_req_key) # data append for index, df in data.iterrows(): print(index, " df", df.time_key) dt = datetime.strptime(df.time_key, "%Y-%m-%d %H:%M:%S") data_bar = BarData(gateway_name=self.gateway_name, symbol=req.symbol, exchange=req.exchange, datetime=dt, interval=req.interval, volume=float(df.volume), open_price=df.open, high_price=df.high, low_price=df.low, close_price=df.close) self.history_list.append(data_bar) history = self.history_list self.history_list = [] return history
def query_history(self, req: HistoryRequest) -> Optional[List[BarData]]: symbol = req.symbol exchange = req.exchange interval = req.interval start = req.start end = req.end if exchange not in self.ex: print('不是Tushare支持的交易所') return None if interval == Interval.DAILY: if exchange in [ Exchange.SHFE, Exchange.CZCE, Exchange.CFFEX, Exchange.DCE, Exchange.INE ]: df = self.pro.fut_daily(ts_code=self.to_ts_symbol( symbol, exchange), asset='FT', start_date=start.strftime('%Y%m%d'), end_date=end.strftime('%Y%m%d')) elif exchange in [Exchange.SSE, Exchange.SZSE]: df = self.pro.daily(ts_code=self.to_ts_symbol( symbol, exchange), start_date=start.strftime('%Y%m%d'), end_date=end.strftime('%Y%m%d')) else: df = self.pro.pro_bar( ts_code=self.to_ts_symbol(symbol, exchange), asset='FT' if exchange in [ Exchange.SHFE, Exchange.CZCE, Exchange.CFFEX, Exchange.DCE, Exchange.INE ] else ('E' if exchange in [Exchange.SSE, Exchange.SZSE] else None), start_date=start.strftime('%Y%m%d'), end_date=end.strftime('%Y%m%d'), freq='60min' if interval == Interval.HOUR else ('1min' if interval == Interval.MINUTE else None)) df = df.sort_index() data: List[BarData] = [] if df is not None: for ix, row in df.iterrows(): date = datetime.strptime(row.trade_date, '%Y%m%d') bar = BarData( symbol=symbol, exchange=exchange, interval=interval, datetime=date, open_price=row['open'], high_price=row['high'], low_price=row['low'], close_price=row['close'], volume=row['amount'], gateway_name='TS', ) data.append(bar) return data
def load_bar_data( self, symbol: str, exchange: Exchange, interval: Interval, start: datetime, end: datetime ) -> List[BarData]: """读取K线数据""" filter = { "symbol": symbol, "exchange": exchange.value, "interval": interval.value, "datetime": { "$gte": start, "$lte": end } } c: Cursor = self.bar_collection.find(filter) bars = [] for d in c: d["exchange"] = Exchange(d["exchange"]) d["interval"] = Interval(d["interval"]) d["gateway_name"] = "DB" d.pop("_id") bar = BarData(**d) bars.append(bar) return bars
def query_history(self, req: HistoryRequest, frequency: int) -> Optional[List[BarData]]: """ Query history bar data from TqSdk. """ if self.symbols is None: return None symbol = req.symbol exchange = req.exchange interval = req.interval start = req.start end = req.end tq_symbol = self.to_tq_symbol(symbol, exchange) if tq_symbol not in self.symbols: return None # 若未从上层load_bar传入frequency,则返回空值 if not frequency: return None # For querying night trading period data end += timedelta(minutes=1) # 获取最新的数据,无法指定日期 df = self.api.get_kline_serial(tq_symbol, frequency, 10000).sort_values(by=["datetime"]) # 转换为东八区时间 df["datetime"] = pd.to_datetime(df["datetime"] + TIME_UTC8) data: List[BarData] = [] if frequency == 60: frequency = "1m" else: frequency = f"{frequency}s" if df is not None: for ix, row in df.iterrows(): dt = CHINA_TZ.localize( row.datetime.to_pydatetime().replace(tzinfo=None)) bar = BarData( symbol=symbol, exchange=exchange, interval=frequency, datetime=dt, open_price=row["open"], high_price=row["high"], low_price=row["low"], close_price=row["close"], volume=row["volume"], open_interest=row.get("open_oi", 0), gateway_name="TQ", ) data.append(bar) return data
def historicalData(self, reqId: int, ib_bar: IbBarData): """ Callback of history data update. """ # When requesting daily and weekly history data, the date format is "%Y%m%d" if len(ib_bar.date) > 8: dt = datetime.strptime(ib_bar.date, "%Y%m%d %H:%M:%S") else: dt = datetime.strptime(ib_bar.date, "%Y%m%d") dt = self.local_tz.localize(dt) bar = BarData( symbol=self.history_req.symbol, exchange=self.history_req.exchange, datetime=dt, interval=self.history_req.interval, volume=ib_bar.volume, open_price=ib_bar.open, high_price=ib_bar.high, low_price=ib_bar.low, close_price=ib_bar.close, gateway_name=self.gateway_name ) self.history_buf.append(bar)
def new_bars(self, dt: datetime) -> None: """""" self.datetime = dt bars: Dict[str, BarData] = {} for vt_symbol in self.vt_symbols: bar = self.history_data.get((dt, vt_symbol), None) # If bar data of vt_symbol at dt exists if bar: # Update bar data for crossing order self.bars[vt_symbol] = bar # Put bar into dict for strategy.on_bars update bars[vt_symbol] = bar # Otherwise, use previous close to backfill elif vt_symbol in self.bars: old_bar = self.bars[vt_symbol] bar = BarData(symbol=old_bar.symbol, exchange=old_bar.exchange, datetime=dt, open_price=old_bar.close_price, high_price=old_bar.close_price, low_price=old_bar.close_price, close_price=old_bar.close_price, gateway_name=old_bar.gateway_name) self.bars[vt_symbol] = bar self.cross_limit_order() self.strategy.on_bars(bars) if self.strategy.inited: self.update_daily_close(self.bars, dt)
def importDataToVnpyDB(df: pd.DataFrame, stkid: str) -> None: bar_data = [] TW_TZ = pytz.timezone("Asia/Taipei") if df is None: return print("資料不存在") for index, row in df.iterrows(): bar = BarData(symbol=stkid, exchange=Exchange.LOCAL, datetime=TW_TZ.localize(row['ts'].to_pydatetime()) - timedelta(minutes=1), interval=Interval.MINUTE, volume=row.Volume, open_price=row.Open, high_price=row.High, low_price=row.Low, close_price=row.Close, gateway_name="Sinopac") bar_data.append(bar) database = get_database() database.save_bar_data(bar_data) print( f"股票代號:{stkid}|{bar_data[0].datetime}-{bar_data[-1].datetime} 歷史數據匯入成功,總共{len(bar_data)}筆資料" )
def move_df_to_sql(imported_data: pd.DataFrame): bars = [] start = None count = 0 for row in imported_data.itertuples(): bar = BarData( symbol=row.symbol, exchange=row.exchange, datetime=row.dtime, interval=row.interval, volume=row.volume, open_price=row.open, high_price=row.high, low_price=row.low, close_price=row.close, open_interest=row.o_interest, gateway_name="DB", ) bars.append(bar) # do some statistics count += 1 if not start: start = bar.datetime end = bar.datetime # insert into database database_manager.save_bar_data(bars) print(f'Insert Bar: {count} from {start} - {end}')
def load_bar_data(self, filter: dict) -> List[BarData]: """加载历史数据""" if self.bar_collection.count_documents(filter) == 0: self.output("无符合条件的历史数据") return else: bars = [] c: Cursor = self.bar_collection.find(filter) for d in c: d["exchange"] = Exchange(d["exchange"]) d["interval"] = Interval(d["interval"]) d["gateway_name"] = "DB" d.pop("_id") bar = BarData(**d) bars.append(bar) bars = sorted(bars, key=lambda bar: bar.datetime) self.output( f"已从{self.history_db.name}库{self.bar_collection.name}集合加载{bars[0].datetime}至{bars[-1].datetime}K线数据{len(bars)}条" ) return bars
def query_bar_from_rq(self, vt_symbol: str, interval: Interval, start: datetime, end: datetime): """ Query bar data from RQData. """ symbol, exchange_str = vt_symbol.split(".") if symbol.upper() not in self.rq_symbols: return None df = self.rq_client.get_price( symbol.upper(), frequency=interval.value, fields=["open", "high", "low", "close", "volume"], start_date=start, end_date=end) data = [] for ix, row in df.iterrows(): bar = BarData(symbol=symbol, exchange=Exchange(exchange_str), interval=interval, datetime=row.name.to_pydatetime(), open_price=row["open"], high_price=row["high"], low_price=row["low"], close_price=row["close"], volume=row["volume"], gateway_name="RQ") data.append(bar) return data
def run_backtesting_load_data_df(self): # Use the first [days] of history data for initializing strategy self.load_bar_end_timestamp = self.history_data_df['datetime'].min() + Day(self.days) load_bar_df = self.history_data_df[self.history_data_df['datetime'] <= self.load_bar_end_timestamp] for ix in range(len(load_bar_df)): x = load_bar_df.iloc[ix, :] bar = BarData( symbol=x.loc['symbol'], exchange=Exchange(x.loc['exchange']), datetime=self.datetime_set_timezone(x.loc['datetime'].to_pydatetime()), interval=Interval(x.loc['interval']), volume=x.loc['volume'], open_price=x.loc['open_price'], high_price=x.loc['high_price'], open_interest=x.loc['open_interest'], low_price=x.loc['low_price'], close_price=x.loc['close_price'], gateway_name="DB", ) self.datetime = bar.datetime # fangyang self.callback 是 strategyTemplate里面的 on_bar # self.callback 是在下面的 load_bar(self)函数中赋值的,去策略模板中掉的load_bar/tick # 这里将数据推送进我们的策略 try: self.callback(bar) except Exception: self.output("触发异常,回测终止") self.output(traceback.format_exc()) return
def arrangePrice(bars:['BarData'],basePrice:float)->['BarData']: barList = [] new_open_price = basePrice for bar in bars: open_price = bar.open_price close_price = bar.close_price high_price = bar.high_price low_price = bar.low_price close_price = close_price * new_open_price / open_price high_price = high_price * new_open_price / open_price low_price = low_price * new_open_price / open_price open_price = new_open_price barList.append( BarData( symbol=bar.symbol, exchange=Exchange.SSE, datetime=bar.datetime, interval=Interval.WEEKLY, volume=bar.volume, open_price=open_price, high_price=high_price, low_price=low_price, close_price=close_price, gateway_name='arrangePrice' )) new_open_price = close_price return barList
def new_bars(self, dt: datetime) -> None: """""" self.datetime = dt # self.bars.clear() for vt_symbol in self.vt_symbols: bar = self.history_data.get((dt, vt_symbol), None) # If bar data of vt_symbol at dt exists if bar: self.bars[vt_symbol] = bar # Otherwise, use previous data to backfill elif vt_symbol in self.bars: old_bar = self.bars[vt_symbol] bar = BarData(symbol=old_bar.symbol, exchange=old_bar.exchange, datetime=dt, open_price=old_bar.close_price, high_price=old_bar.close_price, low_price=old_bar.close_price, close_price=old_bar.close_price, gateway_name=old_bar.gateway_name) self.bars[vt_symbol] = bar self.cross_limit_order() self.strategy.on_bars(self.bars) self.update_daily_close(self.bars, dt)
def to_bar_data(self, item, symbol: str, exchange: Exchange, interval: Interval, datetime_head: str, open_head: str, high_head: str, low_head: str, close_head: str, volume_head: str, open_interest_head: str ): bar = BarData( symbol=symbol, exchange=exchange, datetime=item[datetime_head].to_pydatetime(), interval=interval, volume=item[volume_head], open_interest=item[open_interest_head], open_price=item[open_head], high_price=item[high_head], low_price=item[low_head], close_price=item[close_head], gateway_name="DB" ) return bar
def get_oldest_bar_data(self, symbol: str, exchange: "Exchange", interval: "Interval") -> Optional["BarData"]: query = ("select first(close_price), * from bar_data" " where vt_symbol=$vt_symbol" " and interval=$interval") bind_params = { "vt_symbol": generate_vt_symbol(symbol, exchange), "interval": interval.value } result = influx_client.query(query, bind_params=bind_params) points = result.get_points() bar = None for d in points: dt = datetime.strptime(d["time"], "%Y-%m-%dT%H:%M:%SZ") bar = BarData(symbol=symbol, exchange=exchange, interval=interval, datetime=dt.replace(tzinfo=DB_TZ), open_price=d["open_price"], high_price=d["high_price"], low_price=d["low_price"], close_price=d["close_price"], volume=d["volume"], open_interest=d["open_interest"], gateway_name="DB") return bar
def save_to_database(data: List[dict], vt_symbol: str, rq_interval: str): interval = INTERVAL_RQ2VT.get(rq_interval) if not rq_interval: return None symbol, exchange = extract_vt_symbol(vt_symbol) exchange = Exchange(exchange) dt_format = "%Y-%m-%d %H:%M:%S" res_list: List[BarData] = [] if data is not None: for row in data: bar = BarData(symbol=symbol, exchange=exchange, interval=interval, datetime=datetime.strptime( row['datetime'], dt_format), open_price=row["open"], high_price=row["high"], low_price=row["low"], close_price=row["close"], volume=row["volume"], gateway_name="RQ_WEB") res_list.append(bar) database_manager.save_bar_data(res_list)
def query_history(self, req: HistoryRequest): """""" buf = {} end_time = None for i in range(10): path = f"/api/spot/v3/instruments/{req.symbol}/candles" # Create query params params = {"granularity": INTERVAL_VT2OKEX[req.interval]} if end_time: end = datetime.strptime(end_time, "%Y-%m-%dT%H:%M:%S.%fZ") start = end - TIMEDELTA_MAP[req.interval] * 200 params["start"] = start.strftime("%Y-%m-%dT%H:%M:%S.%fZ") params["end"] = end.strftime("%Y-%m-%dT%H:%M:%S.%fZ") # Get response from server resp = self.request("GET", path, params=params) # Break if request failed with other status code if resp.status_code // 100 != 2: msg = f"获取历史数据失败,状态码:{resp.status_code},信息:{resp.text}" self.gateway.write_log(msg) break else: data = resp.json() if not data: msg = f"获取历史数据为空" break for l in data: ts, o, h, l, c, v = l dt = datetime.strptime(ts, "%Y-%m-%dT%H:%M:%S.%fZ") bar = BarData(symbol=req.symbol, exchange=req.exchange, datetime=dt, interval=req.interval, volume=float(v), open_price=float(o), high_price=float(h), low_price=float(l), close_price=float(c), gateway_name=self.gateway_name) buf[bar.datetime] = bar begin = data[-1][0] end = data[0][0] msg = f"获取历史数据成功,{req.symbol} - {req.interval.value},{begin} - {end}" self.gateway.write_log(msg) # Update start time end_time = begin index = list(buf.keys()) index.sort() history = [buf[i] for i in index] return history
def move_df_to_sql(data_df:pd.DataFrame): bars = [] start = None count = 0 for row in data_df.itertuples(): bar = BarData( symbol=row.symbol.upper(), exchange=exchange_dict[row.exchange], datetime=row.datetime, interval=interval_dict[row.interval], volume=float(row.volume), open_price=float(row.open), high_price=float(row.high), low_price=float(row.low), close_price=float(row.close), open_interest=float(row.open_interest), gateway_name="DB", ) bars.append(bar) # do some statistics count += 1 if not start: start = bar.datetime end = bar.datetime # insert into database print(bars) sql_manager.save_bar_data(bars) print(f'插入{count} 根bar 从 {start} 到 {end}')
def load_bar_data(self, symbol: str, exchange: Exchange, interval: Interval, start: datetime, end: datetime) -> List[BarData]: """""" s: ModelSelect = ( DbBarData.select().where((DbBarData.symbol == symbol) & (DbBarData.exchange == exchange.value) & (DbBarData.interval == interval.value) & (DbBarData.datetime >= start) & (DbBarData.datetime <= end)).order_by( DbBarData.datetime)) bars: List[BarData] = [] for db_bar in s: bar = BarData(symbol=db_bar.symbol, exchange=Exchange(db_bar.exchange), datetime=db_bar.datetime.astimezone(DB_TZ), interval=Interval(db_bar.interval), volume=db_bar.volume, turnover=db_bar.turnover, open_interest=db_bar.open_interest, open_price=db_bar.open_price, high_price=db_bar.high_price, low_price=db_bar.low_price, close_price=db_bar.close_price, gateway_name="DB") bars.append(bar) return bars
def query_history(self, req: HistoryRequest): """""" # Convert symbol contract_type = symbol_type_map.get(req.symbol, "") buf = [i for i in req.symbol if not i.isdigit()] symbol = "".join(buf) ws_contract_type = CONTRACT_TYPE_MAP[contract_type] ws_symbol = f"{symbol}_{ws_contract_type}" # Create query params params = { "symbol": ws_symbol, "period": INTERVAL_VT2HBDM[req.interval], "size": 2000 } # Get response from server resp = self.request( "GET", "/market/history/kline", params=params ) # Break if request failed with other status code history = [] if resp.status_code // 100 != 2: msg = f"获取历史数据失败,状态码:{resp.status_code},信息:{resp.text}" self.gateway.write_log(msg) else: data = resp.json() if not data: msg = f"获取历史数据为空" self.gateway.write_log(msg) else: for d in data["data"]: dt = datetime.fromtimestamp(d["id"]) bar = BarData( symbol=req.symbol, exchange=req.exchange, datetime=dt, interval=req.interval, volume=d["vol"], open_price=d["open"], high_price=d["high"], low_price=d["low"], close_price=d["close"], gateway_name=self.gateway_name ) history.append(bar) begin = history[0].datetime end = history[-1].datetime msg = f"获取历史数据成功,{req.symbol} - {req.interval.value},{begin} - {end}" self.gateway.write_log(msg) return history
def import_data_from_csv( self, file_path: str, symbol: str, exchange: Exchange, interval: Interval, datetime_head: str, open_head: str, high_head: str, low_head: str, close_head: str, volume_head: str, open_interest_head: str, datetime_format: str ) -> Tuple: """""" with open(file_path, "rt") as f: buf = [line.replace("\0", "") for line in f] reader = csv.DictReader(buf, delimiter=",") bars = [] start = None count = 0 for item in reader: if datetime_format: dt = datetime.strptime(item[datetime_head], datetime_format) else: dt = datetime.fromisoformat(item[datetime_head]) open_interest = item.get(open_interest_head, 0) bar = BarData( symbol=symbol, exchange=exchange, datetime=dt, interval=interval, volume=float(item[volume_head]), open_price=float(item[open_head]), high_price=float(item[high_head]), low_price=float(item[low_head]), close_price=float(item[close_head]), open_interest=float(open_interest), gateway_name="DB", ) bars.append(bar) # do some statistics count += 1 if not start: start = bar.datetime # insert into database database_manager.save_bar_data(bars) end = bar.datetime return start, end, count
def update_bar(self, 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, 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 if self.last_bar and bar.datetime.minute != self.last_bar.datetime.minute: self.interval_count += 1 if not self.interval_count % self.window: finished = True self.interval_count = 0 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 on_bar(self, bar: BarData): """收到Bar推送(必须由用户继承实现)""" # 如果当前是一个5分钟走完 # ZL: 通过改变 +1 可以实现非标时间bar if (bar.datetime.minute + 1) % 5 == 0: # 如果已经有聚合5分钟K线 if self.fiveBar: # 将最新分钟的数据更新到目前5分钟线中 fiveBar = self.fiveBar fiveBar.high_price = max(fiveBar.high_price, bar.high_price) fiveBar.low_price = min(fiveBar.low_price, bar.low_price) fiveBar.close_price = bar.close_price # 推送5分钟线数据 self.onFiveBar(fiveBar) # 清空5分钟线数据缓存 self.fiveBar = None else: # 如果没有缓存则新建 if not self.fiveBar: # fiveBar = BarData() fiveBar = BarData(datetime=bar.datetime, exchange=bar.exchange, gateway_name=bar.gateway_name, symbol=bar.symbol) # fiveBar.vtSymbol = bar.vtSymbol # fiveBar.symbol = bar.symbol # fiveBar.exchange = bar.exchange fiveBar.open_price = bar.open_price fiveBar.high_price = bar.high_price fiveBar.low_price = bar.low_price fiveBar.close_price = bar.close_price # fiveBar.date = bar.datetime # fiveBar.time = bar.time fiveBar.datetime = bar.datetime self.fiveBar = fiveBar else: fiveBar = self.fiveBar fiveBar.high_price = max(fiveBar.high_price, bar.high_price) fiveBar.low_price = min(fiveBar.low_price, bar.low_price) fiveBar.close_price = bar.close_price
def query_data(self): # self.clearData() self.chart.clear_all() start = self.datetime_from.dateTime().toPyDateTime() end = self.datetime_to.dateTime().toPyDateTime() symbol = self.symbol_line.text() if self.data_source == 'HK': query_set1 = self._querier[120:start:symbol] query_set2 = self._querier[start:end:symbol] query_set3 = self._querier[end:120:symbol] data1 = self._querier.to_df(query_set1) data2 = self._querier.to_df(query_set2) data3 = self._querier.to_df(query_set3) datas = pd.concat([data1, data2, data3]) elif self.data_source == 'IB': contract = self._querier.verifyContract(symbol) barType = {'1min': '1 min', '5min': '5 mins', '15min': '15 mins', '30min': '30 mins', '60min': '60 mins', '1day': '1 day'}.get(self.period,'1 min') datas = self._querier.get_bars_from_ib(contract, barType=barType, start=start, end=end) if self.review_mode == 'backtest': executions = self.executions elif self.review_mode == 'live': acc_id = self.account_line.text() if acc_id: fills = IBTrade(acc_id)[start:end:symbol] fills = fills.order_by('execution.time') executions = [{'datetime': f.execution.time + dt.timedelta(hours=8), 'price': f.execution.price, 'size': f.execution.shares, 'direction': 'long' if f.execution.side == 'BOT' else 'short'} for f in fills] else: executions = [] if executions: datas = _concat_executions(datas, executions) self.datas = datas barList = [] tradeList = [] for _, d in datas.iterrows(): b = BarData('KRData', symbol, Exchange.HKFE, d.datetime, None, d.volume, 0, d.open, d.high, d.low, d.close) barList.append(b) for e in executions: t = TradeData('KRData', symbol, Exchange.HKFE, '', '', Direction.LONG if e['direction'] == 'long' else Direction.SHORT, Offset.NONE, e['price'], e['size'], e['datetime'] if isinstance(e['datetime'], dt.datetime) else parser.parse(e['datetime']) ) tradeList.append(t) self.chart.update_all(barList, tradeList, [])
def __fill_bardatas(self, symbol, exchange, interval, bars): """ 填充 BarData 结构体 :param bars: :return: BarData 列表 """ if not bars: return None tu = TimeUtils() bardatas = [] for bar in bars: dt = tu.convert_datetime(bar[0] // 1000) _bar = BarData(symbol=symbol, exchange=exchange, datetime=dt, interval=interval, gateway_name="OKEX") _bar.open_price = bar[1] _bar.high_price = bar[2] _bar.low_price = bar[3] _bar.close_price = bar[4] _bar.volume = bar[5] bardatas.append(_bar) return bardatas
def update_tick(self, tick: TickData): """ Update new tick data into generator. 把新的tick数据更新到生成器 """ # flag 是否是新的一分钟 new_minute = False # Filter tick data with 0 last price # 过滤掉 最新价格为0的数据 if not tick.last_price: return if not self.bar: # bar里为空,那么是新的min new_minute = True # elif self.bar.datetime.minute != tick.datetime.minute: # 调整 时间窗口,避开高峰时间 蒋越希 修改 2019年9月11日11:03:31 elif (tick.datetime.second >= 50) and (self.last_tick.datetime.second < 50): # 判断是否走完当前分钟 self.bar.datetime = self.bar.datetime.replace(second=0, microsecond=0) # 把老的bar更新一下,开启新的一分钟 self.on_bar(self.bar) new_minute = True if new_minute: # 如果是新的分钟,则生成新的bar self.bar = BarData(symbol=tick.symbol, exchange=tick.exchange, interval=Interval.MINUTE, datetime=tick.datetime, gateway_name=tick.gateway_name, open_price=tick.last_price, high_price=tick.last_price, low_price=tick.last_price, close_price=tick.last_price, open_interest=tick.open_interest) else: # 高 price self.bar.high_price = max(self.bar.high_price, tick.last_price) # 低 price self.bar.low_price = min(self.bar.low_price, tick.last_price) # 收 price self.bar.close_price = tick.last_price # 当前持仓量 self.bar.open_interest = tick.open_interest self.bar.datetime = tick.datetime if self.last_tick: # 统计出bar里的成交量 volume_change = tick.volume - self.last_tick.volume self.bar.volume += max(volume_change, 0) self.last_tick = tick
def query_history(self, req: HistoryRequest): """ Query history bar data from JQData. """ symbol = req.symbol exchange = req.exchange interval = req.interval start = req.start end = req.end jq_symbol = self.to_jq_symbol(symbol, exchange) # if jq_symbol not in self.symbols: # return None jq_interval = INTERVAL_VT2JQ.get(interval) if not jq_interval: return None # For adjust timestamp from bar close point (RQData) to open point (VN Trader) adjustment = INTERVAL_ADJUSTMENT_MAP_JQ.get(interval) # For querying night trading period data # end += timedelta(1) now = datetime.now() if end >= now: end = now elif end.year == now.year and end.month == now.month and end.day == now.day: end = now df = jq.get_price( jq_symbol, frequency=jq_interval, fields=["open", "high", "low", "close", "volume"], start_date=start, end_date=end, skip_paused=True ) data: List[BarData] = [] if df is not None: for ix, row in df.iterrows(): bar = BarData( symbol=symbol, exchange=exchange, interval=interval, datetime=row.name.to_pydatetime() - adjustment, open_price=row["open"], high_price=row["high"], low_price=row["low"], close_price=row["close"], volume=row["volume"], gateway_name="JQ" ) data.append(bar) return data