def on_bar(self, bar: BarData) -> None: bar.datetime = str(bar) data = { "type": "bar", "data": bar._to_dict() } self.io.emit('bar', data)
def __call__(self, data): """ 你必须实现此方法以支持在此层进行中转 """ if data.local_symbol not in self.instrument_set: return if not self.active: return if isinstance(data, ContractData): self.on_contract(data) elif isinstance(data, OrderData): self.on_order(data) elif isinstance(data, TradeData): self.on_trade(data) elif isinstance(data, AccountData): self.on_account(data) elif isinstance(data, PositionData): self.on_position(data) elif data['type'] == "bar": self.on_bar(BarData(**data)) elif data['type'] == "tick": self.on_tick(TickData(**data)) else: raise ValueError("unsupported data")
def update_bar(self, xmin, bar: BarData): """ Update 1 minute bar into generator """ xmin_bar = getattr(self, f"min_{xmin}_bar", None) if not xmin_bar: xmin_bar = BarData(symbol=bar.symbol, exchange=bar.exchange, datetime=bar.datetime, gateway_name=bar.gateway_name, open_price=bar.open_price, high_price=bar.high_price, low_price=bar.low_price) setattr(self, f"min_{xmin}_bar", xmin_bar) else: xmin_bar.high_price = max(xmin_bar.high_price, bar.high_price) xmin_bar.low_price = min(xmin_bar.low_price, bar.low_price) xmin_bar.close_price = bar.close_price xmin_bar.volume += int(bar.volume) if not (bar.datetime.minute + 1) % xmin: xmin_bar.datetime = xmin_bar.datetime.replace(second=0, microsecond=0) xmin_bar.interval = xmin event = Event(type=EVENT_BAR, data=xmin_bar) common_signals.bar_signal.send(event) setattr(self, f"min_{xmin}_bar", None)
def update_tick(self, tick: TickData): """ Update new tick data into generator and new_shared time data. """ new_minute = False self.last_price = tick.last_price self.open_interest = tick.open_interest self.volume = tick.volume self.molecule = self.molecule + tick.last_price * tick.volume self.denominator = self.denominator + tick.volume try: self.average_price = self.molecule / self.denominator except ZeroDivisionError: self.average_price = tick.last_price if self.last_volume is None: self.last_volume = tick.volume if self.local_symbol is None: self.local_symbol = tick.local_symbol if not self.bar: new_minute = True elif self.bar.datetime.minute != tick.datetime.minute: self.bar.datetime = self.bar.datetime.replace( second=0, microsecond=0 ) self.bar.interval = 1 event = Event(type=EVENT_BAR, data=self.bar) self.rpo.put(event) [self.update_bar(x, getattr(self, "min_{}_bar".format(x)), self.bar) for x in self.XMIN] new_minute = True if new_minute: shared = SharedData(last_price=round(self.last_price, 2), datetime=tick.datetime, local_symbol=self.local_symbol, open_interest=self.open_interest, average_price=round(self.average_price, 2), volume=self.volume - self.last_volume, gateway_name=tick.gateway_name) self.last_volume = tick.volume event = Event(type=EVENT_SHARED, data=shared) self.rpo.put(event) self.bar = BarData( symbol=tick.symbol, exchange=tick.exchange, 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, ) else: self.bar.high_price = max(self.bar.high_price, tick.last_price) self.bar.low_price = min(self.bar.low_price, tick.last_price) self.bar.close_price = tick.last_price self.bar.datetime = tick.datetime if self.last_tick: volume_change = tick.volume - self.last_tick.volume self.bar.volume += max(volume_change, 0) self.last_tick = tick
def update_bar(self, xmin, xmin_bar: BarData, bar: BarData): """ Update 1 minute bar into generator """ if not xmin_bar: xmin_bar = BarData(symbol=bar.symbol, exchange=bar.exchange, datetime=bar.datetime, gateway_name=bar.gateway_name, open_price=bar.open_price, high_price=bar.high_price, low_price=bar.low_price) else: xmin_bar.high_price = max(xmin_bar.high_price, bar.high_price) xmin_bar.low_price = min(xmin_bar.low_price, bar.low_price) xmin_bar.close_price = bar.close_price xmin_bar.volume += int(bar.volume) if not (bar.datetime.minute + 1) % xmin: xmin_bar.datetime = xmin_bar.datetime.replace(second=0, microsecond=0) xmin_bar.interval = xmin event = Event(type=EVENT_BAR, data=xmin_bar) self.rpo.put(event) xmin_bar = None
def update_tick(self, tick: TickData): """ Update new tick data into generator and new_shared time data. """ new_minute = False """ 更新价位 """ self.last_price = tick.last_price self.open_interest = tick.open_interest self.volume = tick.volume if self.last_volume is None: self.last_volume = tick.volume if self.local_symbol is None: self.local_symbol = tick.local_symbol if not self.bar: new_minute = True elif self.bar.datetime.minute != tick.datetime.minute: self.bar.datetime = self.bar.datetime.replace(second=0, microsecond=0) self.bar.interval = 1 event = Event(type=EVENT_BAR, data=self.bar) common_signals.bar_signal.send(event) [self.update_bar(x, self.bar) for x in self.XMIN] new_minute = True if new_minute: self.last_volume = tick.volume gateway_name = tick.gateway_name if getattr( tick, "gateway_name", None) else "looper" self.bar = BarData( symbol=tick.symbol, exchange=tick.exchange, datetime=tick.datetime, gateway_name=gateway_name, open_price=tick.last_price, high_price=tick.last_price, low_price=tick.last_price, close_price=tick.last_price, ) else: self.bar.high_price = max(self.bar.high_price, tick.last_price) self.bar.low_price = min(self.bar.low_price, tick.last_price) self.bar.close_price = tick.last_price self.bar.datetime = tick.datetime if self.last_tick: """ 更新volume的改变 """ volume_change = tick.volume - self.last_tick.volume self.bar.volume += max(volume_change, 0) self.last_tick = tick
def resample(self, tick_data: TickData) -> BarData or None: data = [] for frq, last in self.last_entity.items(): if last is None: self.last_entity[frq] = BarData( datetime=tick_data.datetime, high_price=tick_data.last_price, low_price=tick_data.last_price, close_price=tick_data.last_price, open_price=tick_data.last_price, interval=frq, volume=0, first_volume=tick_data.volume, local_symbol=tick_data.local_symbol, ) self.last_datetime[frq] = tick_data.datetime else: if frq != 1 and tick_data.datetime.minute % frq == 0 and abs( (tick_data.datetime - self.last_datetime[frq]).seconds) >= 60: temp = deepcopy(last) if self.check_tick(tick_data): temp.high_price = max(temp.high_price, tick_data.last_price) temp.low_price = min(temp.low_price, tick_data.last_price) temp.close_price = tick_data.last_price temp.volume += max( tick_data.volume - temp.first_volume, 0) self.last_entity[frq] = BarData( datetime=tick_data.datetime, high_price=tick_data.last_price, low_price=tick_data.last_price, close_price=tick_data.last_price, open_price=tick_data.last_price, interval=frq, volume=tick_data.volume - temp.first_volume, first_volume=tick_data.volume, local_symbol=tick_data.local_symbol) self.last_datetime[frq] = tick_data.datetime data.append(temp) elif frq != 1: self.last_entity[frq].high_price = max( self.last_entity[frq].high_price, tick_data.last_price) self.last_entity[frq].low_price = min( self.last_entity[frq].low_price, tick_data.last_price) self.last_entity[frq].close_price = tick_data.last_price self.last_entity[frq].volume += max( tick_data.volume - self.last_entity[frq].first_volume, 0) self.last_entity[frq].first_volume = tick_data.volume # 处理一分钟的k线 if frq == 1 and tick_data.datetime.second == 0 and \ abs((tick_data.datetime - self.last_datetime[frq]).seconds) > 10: temp = deepcopy(last) if self.check_tick(tick_data): temp.high_price = max(temp.high_price, tick_data.last_price) temp.low_price = min(temp.low_price, tick_data.last_price) temp.close_price = tick_data.last_price temp.volume += max( tick_data.volume - temp.first_volume, 0) self.last_entity[frq] = BarData( datetime=tick_data.datetime, high_price=tick_data.last_price, low_price=tick_data.last_price, close_price=tick_data.last_price, open_price=tick_data.last_price, interval=frq, volume=tick_data.volume - temp.first_volume, first_volume=tick_data.volume, local_symbol=tick_data.local_symbol) self.last_datetime[frq] = tick_data.datetime data.append(temp) elif frq == 1: self.last_entity[frq].high_price = max( self.last_entity[frq].high_price, tick_data.last_price) self.last_entity[frq].low_price = min( self.last_entity[frq].low_price, tick_data.last_price) self.last_entity[frq].close_price = tick_data.last_price self.last_entity[frq].volume += max( tick_data.volume - self.last_entity[frq].first_volume, 0) self.last_entity[frq].first_volume = tick_data.volume return data
def resample(self, tick_data: TickData) -> BarData or None: data = [] for frq, last in self.last_entity.items(): if last is None: self.last_entity[frq] = BarData( datetime=tick_data.datetime, high_price=tick_data.last_price, low_price=tick_data.last_price, close_price=tick_data.last_price, open_price=tick_data.last_price, interval=frq, volume=0, first_volume=tick_data.volume, local_symbol=tick_data.local_symbol, ) self.last_datetime[frq] = tick_data.datetime else: if self.lock_free[frq] is False: if tick_data.datetime.hour == self.last_entity[frq].datetime.hour \ and tick_data.datetime.minute == self.last_entity[frq].datetime.minute \ and tick_data.datetime.second == self.last_entity[frq].datetime.second: self.lock_free[frq] = True if frq != 1 and tick_data.datetime.minute % frq == 0 and abs( (tick_data.datetime - self.last_datetime[frq]).seconds) >= 60 \ and self.lock_free[frq] is True: temp = deepcopy(last) check, tim = self.check_tick(tick_data) if check is True: temp.high_price = max(temp.high_price, tick_data.last_price) temp.low_price = min(temp.low_price, tick_data.last_price) temp.close_price = tick_data.last_price temp.volume += max( tick_data.volume - temp.first_volume, 0) self.last_entity[frq] = BarData( datetime=tim, high_price=tick_data.last_price, low_price=tick_data.last_price, close_price=tick_data.last_price, open_price=tick_data.last_price, interval=frq, volume=0, first_volume=tick_data.volume, local_symbol=tick_data.local_symbol) self.lock_free[frq] = False self.last_datetime[frq] = tim else: self.last_entity[frq] = BarData( datetime=tick_data.datetime, high_price=tick_data.last_price, low_price=tick_data.last_price, close_price=tick_data.last_price, open_price=tick_data.last_price, interval=frq, volume=tick_data.volume - temp.first_volume, first_volume=tick_data.volume, local_symbol=tick_data.local_symbol) self.last_datetime[frq] = tick_data.datetime data.append(temp) elif frq != 1 and self.lock_free[frq] is True: self.last_entity[frq].high_price = max( self.last_entity[frq].high_price, tick_data.last_price) self.last_entity[frq].low_price = min( self.last_entity[frq].low_price, tick_data.last_price) self.last_entity[frq].close_price = tick_data.last_price self.last_entity[frq].volume += max( tick_data.volume - self.last_entity[frq].first_volume, 0) self.last_entity[frq].first_volume = tick_data.volume """ 处理一分钟的k线数据 """ if frq == 1 and tick_data.datetime.second == 0 and \ abs((tick_data.datetime - self.last_datetime[frq]).seconds) > 10 \ and self.lock_free[frq] is True: temp = deepcopy(last) check, tim = self.check_tick(tick_data) if check is True: """ 特殊时间需要特殊有处理 """ temp.high_price = max(temp.high_price, tick_data.last_price) temp.low_price = min(temp.low_price, tick_data.last_price) temp.close_price = tick_data.last_price temp.volume += max( tick_data.volume - temp.first_volume, 0) self.last_entity[frq] = BarData( datetime=tim, high_price=tick_data.last_price, low_price=tick_data.last_price, close_price=tick_data.last_price, open_price=tick_data.last_price, interval=frq, volume=0, first_volume=tick_data.volume, local_symbol=tick_data.local_symbol) self.lock_free[frq] = False self.last_datetime[frq] = tim else: self.last_entity[frq] = BarData( datetime=tick_data.datetime, high_price=tick_data.last_price, low_price=tick_data.last_price, close_price=tick_data.last_price, open_price=tick_data.last_price, interval=frq, volume=tick_data.volume - temp.first_volume, first_volume=tick_data.volume, local_symbol=tick_data.local_symbol) self.last_datetime[frq] = tick_data.datetime data.append(temp) elif frq == 1 and self.lock_free[frq]: self.last_entity[frq].high_price = max( self.last_entity[frq].high_price, tick_data.last_price) self.last_entity[frq].low_price = min( self.last_entity[frq].low_price, tick_data.last_price) self.last_entity[frq].close_price = tick_data.last_price """ 累积成交量 """ self.last_entity[frq].volume += max( tick_data.volume - self.last_entity[frq].first_volume, 0) self.last_entity[frq].first_volume = tick_data.volume return data
def __call__(self, *args, **kwargs): """ 回测周期 """ entity = args[0] # 日期不相等时, 更新前日结算价格 if self.account.date is None: self.account.date = self.date if self.date is None: self.date = entity.datetime.date() if not self.auth_time(entity.datetime): return self.data_type = entity.type # 回测的时候自动更新策略的日期 try: seconds = (entity.datetime - self.datetime).seconds if seconds >= 60 * 60 * 4 and (entity.datetime.hour >= 21 or ( (14 <= self.datetime.hour <= 15) and entity.datetime.date() != self.datetime.date())): self.account.settle(entity.datetime.date()) # 针对于账户的实现 我们需要将昨仓转换为今仓 self.app.recorder.position_manager.covert_to_yesterday_holding( ) for local_symbol, price in self.price_mapping.items(): self.pre_close_price[local_symbol] = price # 结算完触发初始化函数 self.on_event(EVENT_INIT_FINISHED, True) except KeyError: pass except AttributeError: pass self.data_entity = entity self.change_month_record["".join( filter(str.isalpha, entity.local_symbol.split(".")[0]))] = entity # 维护一个最新的价格 self.price_mapping[self.data_entity.local_symbol] = self.data_entity.close_price if entity.type == "bar" \ else self.data_entity.last_price if self.pre_close_price.get(self.data_entity.local_symbol) is None: self.pre_close_price[ self.data_entity. local_symbol] = self.data_entity.last_price if entity.type == "tick" else self.data_entity.close_price self.datetime = entity.datetime self.match_deal() if entity.type == "tick": self.account.position_manager.update_tick( self.data_entity, self.pre_close_price[self.data_entity.local_symbol]) self.app.recorder.position_manager.update_tick( self.data_entity, self.pre_close_price[self.data_entity.local_symbol]) self.on_event(EVENT_TICK, TickData(**entity)) if entity.type == "bar": self.account.position_manager.update_bar( self.data_entity, self.pre_close_price[self.data_entity.local_symbol]) self.app.recorder.position_manager.update_bar( self.data_entity, self.pre_close_price[self.data_entity.local_symbol]) self.on_event(EVENT_BAR, BarData(**entity)) if entity.datetime.hour >= 21: """if hour > 21, switch to next trade day""" index = trade_dates.index(str(entity.datetime.date())) self.date = datetime.strptime(trade_dates[index + 1], "%Y-%m-%d").date() else: if str(entity.datetime.date()) not in trade_dates: last_day = entity.datetime + timedelta(days=-1) self.date = datetime.strptime( trade_dates[trade_dates.index(str(last_day.date())) + 1], "%Y-%m-%d").date() else: self.date = entity.datetime.date() # 穿过接口日期检查 self.account.via_aisle()