def product(self): """ 从数据库中取出数据 """ conn = MySql().get_connection() # 得到连接 # 构造查询条件 query_params = " where ctime >= '%s'" % (self.__start_time,) query_params += " and ctime < '%s'" % (self.__end_time,) coll = "%s_%s" % (self.__symbol, self.__config.time_frame) cur = conn.cursor(pymysql.cursors.DictCursor) cur.execute("select * from %s " % coll + query_params + " limit %d " % self.__maxsize) # print(cur.fetchall()) for row in cur.fetchall(): bar = Bar(self.__symbol) bar.close = row["close"] bar.timestamp = int(row["ctime"]) bar.high = row["high"] bar.low = row["low"] bar.open = row["open"] bar.volume = row["volume"] bar.time_frame = self.__config.time_frame self.__dq.put(bar) self.__start_time = bar.timestamp + tf2s(self.__config.time_frame) cur.close() # 如果开始时间距结束时间的距离不超过当前时间尺度,证明数据查询完成 if (cur.rownumber == 0) or self.__end_time - self.__start_time <= tf2s(self.__config.time_frame): self._finished = True
class Bar(DictLike): """K线数据对象(开高低收成交量时间)""" __slots__ = [ "symbol", "open", "high", "low", "close", "volume", "timestamp", "time_frame" ] __keys__ = __slots__ + ['datetime', "close_time"] datetime = property(lambda self: datetime.fromtimestamp(self.timestamp)) close_time = property(lambda self: self.timestamp + tf2s(self.time_frame)) def __init__(self, symbol): self.symbol = symbol self.time_frame = None self.open = 0 self.high = 0 self.low = 0 self.close = 0 self.volume = 0 self.timestamp = 0 def to_event(self): event = Event(EVENT_SYMBOL_BAR_RAW[self.symbol][self.time_frame], data=self) return event @classmethod def get_keys(cls): """ :return: field names in print order use for create dataframe """ return cls.__keys__
def float_pnl_frequency(self): if not self._is_backtest: return 1 if self.min_time_frame in ['M1', 'M5']: return 1 time = tf2s(self.min_time_frame) result = 2 * 60 * 60 // time # 统计频率为2H一次 if result == 0: return 1 else: return result
def float_pnl_frequency(self): if self.config.running_mode == RunningMode.runtime: return 1 if self.min_time_frame in ['M1', 'M5']: return 1 time = tf2s(self.min_time_frame) result = 2 * 60 * 60 // time # 统计频率为2H一次 if result == 0: return 1 else: return result
def product(self): """ 从数据库中取出数据 """ try: conn = MySql().get_connection() # 得到连接 # 构造查询条件 query_params = " where ctime >= '%s'" % (self.__start_time, ) query_params += " and ctime < '%s'" % (self.__end_time, ) coll = "%s_%s" % (self.__symbol, self.config.time_frame) cur = conn.cursor(pymysql.cursors.DictCursor) cur.execute("select * from %s " % coll + query_params + " limit %d " % self.__maxsize) # print(cur.fetchall()) for row in cur.fetchall(): bar = Bar(self.__symbol) bar.close = row["close"] bar.timestamp = int(row["ctime"]) bar.high = row["high"] bar.low = row["low"] bar.open = row["open"] bar.volume = row["volume"] # volume maybe None in mysql if bar.volume is None: bar.volume = 0 bar.time_frame = self.config.time_frame self.__dq.put(bar) self.__start_time = bar.timestamp + tf2s( self.config.time_frame) cur.close() # 如果开始时间距结束时间的距离不超过当前时间尺度,证明数据查询完成 if (cur.rownumber == 0) or self.__end_time - self.__start_time <= tf2s( self.config.time_frame): self.stop() except: self.logger.error('\n' + traceback.format_exc()) self.stop()
def update_bar(self, bar): symbol = bar.symbol time_frame = bar.time_frame self.current_time = bar.close_time if not self.current_time else max(self.current_time, bar.close_time) last_time = self._data[time_frame]['timestamp'][symbol][0] \ if self._data[time_frame]['timestamp'][symbol] else 0 if bar.timestamp - last_time >= tf2s(time_frame): # 当last_time = 0时,该条件显然成立 for field in ['open', 'high', 'low', 'close', 'datetime', 'timestamp', 'volume']: self._data[time_frame][field][symbol].appendleft(getattr(bar, field)) self._engine.put_event(Event(EVENT_SYMBOL_BAR_COMPLETED[symbol][time_frame])) else: for field in ['open', 'high', 'low', 'close', 'datetime', 'timestamp', 'volume']: self._data[time_frame][field][symbol][0] = getattr(bar, field) self._engine.put_event(Event(EVENT_SYMBOL_BAR_UPDATE[symbol][time_frame]))
def on_bar(self, event): if self._running: bar = event.content['data'] symbol = bar.symbol time_frame = bar.time_frame self.current_time = bar.close_time if not self.current_time else max(self.current_time, bar.close_time) last_time = self._data[time_frame]['timestamp'][symbol][0] \ if self._data[time_frame]['timestamp'][symbol] else 0 if bar.timestamp - last_time >= tf2s(time_frame): # 当last_time = 0时,该条件显然成立 for field in ['open', 'high', 'low', 'close', 'datetime', 'timestamp', 'volume']: self._data[time_frame][field][symbol].appendleft(getattr(bar, field)) self._engine.put_event(Event(EVENT_SYMBOL_BAR_COMPLETED[symbol][time_frame])) else: for field in ['open', 'high', 'low', 'close', 'datetime', 'timestamp', 'volume']: self._data[time_frame][field][symbol][0] = getattr(bar, field) self._engine.put_event(Event(EVENT_SYMBOL_BAR_UPDATE[symbol][time_frame]))
def update_bar(self, bar: Bar): symbol = bar.symbol time_frame = bar.time_frame quotation = self._data_view.find(symbol, time_frame) self.current_time = bar.close_time if not self.current_time else max(self.current_time, bar.close_time) last_time = quotation.timestamp[0] if quotation.timestamp else 0 if self.config.trading_mode == TradingMode.on_tick: quotation.tick_open = bar.open if bar.timestamp - last_time >= tf2s(time_frame): # 当last_time = 0时,该条件显然成立 for field in ['open', 'high', 'low', 'close', 'datetime', 'timestamp', 'volume']: getattr(quotation, field).appendleft(getattr(bar, field)) self._engine.put_event(Event(EVENT_SYMBOL_BAR_COMPLETED[symbol][time_frame])) else: quotation.high[0] = max(quotation.high[0], bar.high) quotation.low[0] = min(quotation.low[0], bar.low) quotation.volume[0] += bar.volume for field in ["datetime", "timestamp", "close"]: getattr(quotation, field)[0] = getattr(bar, field) self._engine.put_event(Event(EVENT_SYMBOL_BAR_UPDATE[symbol][time_frame]))
def __send_order_to_broker(self, order): if self.__is_backtest: time_frame = self.engine.strategys[order.strategy].signals[order.signal].get_time_frame() time_ = self.engine.data[time_frame]["timestamp"][order.symbol][0] + tf2s(time_frame) order.time_done = int(time_) order.time_done_msc = int((time_ - int(time_)) * (10 ** 6)) order.volume_current = order.volume_initial deal = self.__deal_factory(order.symbol, order.strategy, order.signal) deal.volume = order.volume_current deal.time = order.time_done deal.time_msc = order.time_done_msc deal.type = 1 - ((order.type & 1) << 1) # 参见ENUM_ORDER_TYPE和ENUM_DEAL_TYPE的定义 deal.price = self.engine.data[time_frame]["close"][order.symbol][0] # TODO加入手续费等 order.deal = deal.get_id() deal.order = order.get_id() return [deal], {} # TODO 市价单成交 else: pass
def on_tick(self, event: Event): if self._running: tick = event.content['data'] symbol = tick.symbol for time_frame in {item[1] for item in self._data_view.get_keys() if item[0] == symbol}: bar_interval = tf2s(time_frame) if symbol not in self._tick_cache: self._tick_cache[symbol] = {} if time_frame not in self._tick_cache[symbol]: self._tick_cache[symbol][time_frame] = { 'open': tick.openPrice, 'high': tick.highPrice, 'low': tick.lastPrice, 'close': tick.lastPrice, 'volume': tick.volume, 'timestamp': tick.time // self.TICK_INTERVAL * self.TICK_INTERVAL, } else: dict_ = self._tick_cache[symbol][time_frame] if tick.time - dict_['timestamp'] >= self.TICK_INTERVAL: # bar_interval 能被TICK_INTERVAL整除 bar = Bar(symbol) bar.time_frame = time_frame bar.timestamp = dict_['timestamp'] // bar_interval * bar_interval bar.open = dict_['open'] bar.high = dict_['high'] bar.low = dict_['low'] bar.close = dict_['close'] self.update_bar(bar) dict_["open"] = tick.openPrice dict_["high"] = tick.highPrice dict_["low"] = tick.lowPrice dict_["close"] = tick.lastPrice dict_["volume"] = tick.volume dict_["timestamp"] = tick.time // self.TICK_INTERVAL * self.TICK_INTERVAL else: dict_['low'] = min(dict_['low'], tick.lowPrice) dict_['high'] = max(dict_['high'], tick.highPrice) dict_['close'] = tick.lastPrice dict_["volume"] += tick.volume dict_['timestamp'] = tick.time // self.TICK_INTERVAL * self.TICK_INTERVAL
def __send_order_to_broker(self, order): # if order.volume_initial == 0: # return if order.volume_initial <= 0: return -1 if self.__is_backtest: time_frame = self.engine.strategys[order.strategy].signals[order.signal].get_time_frame() position = self.engine.current_positions[order.symbol] symbol = self.engine.symbol_pool[order.symbol] volume = order.volume_initial margin = 0 if position.type * (1 - (order.type << 1)) < 0: if symbol.code.startswith('USD'): # 间接报价 base_price = 1 elif symbol.code.endswith('USD'): # 直接报价 base_price = position.price_current margin -= symbol.margin(min(position.volume, volume), commission=self.__config['commission'], base_price=base_price) volume -= position.volume if volume > 0: margin += symbol.margin(volume, commission=self.__config['commission'], base_price=self.engine.get_base_price(order.symbol, time_frame)) if self.engine.capital_available - margin >= 0: time_ = self.engine.data[time_frame]["timestamp"][order.symbol][0] + tf2s(time_frame) order.time_done = int(time_) order.time_done_msc = int((time_ - int(time_)) * (10 ** 6)) order.volume_current = order.volume_initial deal = self.__deal_factory(order.symbol, order.strategy, order.signal) deal.volume = order.volume_current deal.time = order.time_done deal.time_msc = order.time_done_msc deal.type = 1 - ((order.type & 1) << 1) # 参见ENUM_ORDER_TYPE和ENUM_DEAL_TYPE的定义 deal.price = self.engine.data[time_frame]["close"][order.symbol][0] # TODO加入手续费等 order.deal = deal.get_id() deal.order = order.get_id() order_id = order.get_id() else: print('下单失败,保证金不足') return -1 else: cash_old = self.engine.capital_cash order_id = self.engine.send_order_to_broker(order) if order_id != -1: res = self.engine.order_status() if res['ok']: order_status = res.get('orders', []) for state in order_status: if state['id'] == order_id: deal = self.__deal_factory(order.symbol, order.strategy, order.signal) deal.type = 1 - ((order.type & 1) << 1) deal.volume = round(state['quantity'] / 100000, 2) # 换算成手,精确到mini手 deal.time = parse(state['created']).timestamp() deal.price = state['avgPx'] deal.symbol = order.symbol deal.order = order.get_id() cash_now = self.engine.capital_cash deal.profit = cash_now - cash_old break if order_id != -1: self.__update_position(deal) # TODO 加入事件引擎,支持异步 self.__orders_done[order.get_id()] = order return order.get_id() else: return -1
def set_min_time_frame(self, time_frame): if not self._min_time_frame or tf2s(time_frame) < tf2s(self._min_time_frame): self._min_time_frame = time_frame
def min_time_frame(self, time_frame): if not self._min_time_frame or tf2s(time_frame) < tf2s(self._min_time_frame): self._min_time_frame = time_frame