async def process(self, msg): """ 处理websocket上接收到的消息 """ # logger.debug("msg:", msg, caller=self) if not isinstance(msg, dict): return channel = msg.get("stream") if channel not in self._c_to_s: logger.warn("unkown channel, msg:", msg, caller=self) return symbol = self._c_to_s[channel] data = msg.get("data") e = data.get("e") # 事件名称 # 保存数据到数据库 if e == "kline": # K线 kline = { "platform": self._platform, "symbol": symbol, "open": data.get("k").get("o"), # 开盘价 "high": data.get("k").get("h"), # 最高价 "low": data.get("k").get("l"), # 最低价 "close": data.get("k").get("c"), # 收盘价 "volume": data.get("k").get("q"), # 交易量 "timestamp": data.get("k").get("t"), # 时间戳 "kline_type": const.MARKET_TYPE_KLINE } EventKline(**kline).publish() logger.info("symbol:", symbol, "kline:", kline, caller=self) elif channel.endswith("depth20"): # 订单薄 bids = [] asks = [] for bid in data.get("bids"): bids.append(bid[:2]) for ask in data.get("asks"): asks.append(ask[:2]) orderbook = { "platform": self._platform, "symbol": symbol, "asks": asks, "bids": bids, "timestamp": tools.get_cur_timestamp_ms() } EventOrderbook(**orderbook).publish() logger.info("symbol:", symbol, "orderbook:", orderbook, caller=self) elif e == "trade": # 实时成交信息 trade = { "platform": self._platform, "symbol": symbol, "action": ORDER_ACTION_SELL if data["m"] else ORDER_ACTION_BUY, "price": data.get("p"), "quantity": data.get("q"), "timestamp": data.get("T") } EventTrade(**trade).publish() logger.info("symbol:", symbol, "trade:", trade, caller=self) else: logger.error("event error! msg:", msg, caller=self)
async def process(self, msg): """ 处理websocket上接收到的消息 """ # logger.debug("msg:", msg, caller=self) if tools.get_cur_timestamp() <= self._last_msg_ts: return if not isinstance(msg, dict): return notifications = msg.get("notifications") if not notifications: return message = notifications[0].get("message") if message != "order_book_event": return symbol = notifications[0].get("result").get("instrument") bids = [] for item in notifications[0].get("result").get("bids")[:10]: b = [item.get("price"), item.get("quantity")] bids.append(b) asks = [] for item in notifications[0].get("result").get("asks")[:10]: a = [item.get("price"), item.get("quantity")] asks.append(a) self._last_msg_ts = tools.get_cur_timestamp() orderbook = { "platform": self._platform, "symbol": symbol, "asks": asks, "bids": bids, "timestamp": self._last_msg_ts } EventOrderbook(**orderbook).publish() logger.info("symbol:", symbol, "orderbook:", orderbook, caller=self)
async def publish_orderbook(self, symbol): """Publish OrderbookEvent.""" ob = copy.copy(self._orderbooks[symbol]) if not ob["asks"] or not ob["bids"]: logger.warn("symbol:", symbol, "asks:", ob["asks"], "bids:", ob["bids"], caller=self) return ask_keys = sorted(list(ob["asks"].keys())) bid_keys = sorted(list(ob["bids"].keys()), reverse=True) if ask_keys[0] <= bid_keys[0]: logger.warn("symbol:", symbol, "ask1:", ask_keys[0], "bid1:", bid_keys[0], caller=self) return asks = [] for k in ask_keys[:self._orderbook_length]: price = "%.8f" % k quantity = "%.8f" % ob["asks"].get(k) asks.append([price, quantity]) bids = [] for k in bid_keys[:self._orderbook_length]: price = "%.8f" % k quantity = "%.8f" % ob["bids"].get(k) bids.append([price, quantity]) orderbook = { "platform": self._platform, "symbol": symbol, "asks": asks, "bids": bids, "timestamp": ob["timestamp"] } EventOrderbook(**orderbook).publish() logger.debug("symbol:", symbol, "orderbook:", orderbook, caller=self)
async def process(self, msg): """ 处理websocket上接收到的消息 """ logger.debug("msg:", msg, caller=self) if not isinstance(msg, dict): return table = msg.get("table") if table == "orderBook10": # 订单薄数据 for item in msg["data"]: symbol = item.get("symbol") orderbook = { "platform": self._platform, "symbol": symbol, "asks": item.get("asks"), "bids": item.get("bids"), "timestamp": tools.utctime_str_to_mts(item["timestamp"]) } EventOrderbook(**orderbook).publish() logger.info("symbol:", symbol, "orderbook:", orderbook, caller=self) elif table == "trade": # 成交数据 for item in msg["data"]: symbol = item["symbol"] trade = { "platform": self._platform, "symbol": symbol, "action": ORDER_ACTION_BUY if item["side"] else ORDER_ACTION_SELL, "price": "%.1f" % item["price"], "quantity": str(item["size"]), "timestamp": tools.utctime_str_to_mts(item["timestamp"]) } EventTrade(**trade).publish() logger.info("symbol:", symbol, "trade:", trade, caller=self) elif table == "tradeBin1m": # 1分钟K线数据 for item in msg["data"]: symbol = item["symbol"] kline = { "platform": self._platform, "symbol": symbol, "open": "%.1f" % item["open"], # 开盘价 "high": "%.1f" % item["high"], # 最高价 "low": "%.1f" % item["low"], # 最低价 "close": "%.1f" % item["close"], # 收盘价 "volume": str(item["volume"]), # 交易量 "timestamp": tools.utctime_str_to_mts(item["timestamp"]), # 时间戳 "kline_type": MARKET_TYPE_KLINE } EventKline(**kline).publish() logger.info("symbol:", symbol, "kline:", kline, caller=self)
async def publish_orderbook(self, *args, **kwargs): """ 推送orderbook数据 """ for symbol, data in self._orderbooks.items(): ob = copy.copy(data) if not ob["asks"] or not ob["bids"]: logger.warn("symbol:", symbol, "asks:", ob["asks"], "bids:", ob["bids"], caller=self) continue ask_keys = sorted(list(ob["asks"].keys())) bid_keys = sorted(list(ob["bids"].keys()), reverse=True) if ask_keys[0] <= bid_keys[0]: logger.warn("symbol:", symbol, "ask1:", ask_keys[0], "bid1:", bid_keys[0], caller=self) continue # 卖 asks = [] for k in ask_keys[:self._length]: price = "%.8f" % k quantity = "%.8f" % ob["asks"].get(k) asks.append([price, quantity]) # 买 bids = [] for k in bid_keys[:self._length]: price = "%.8f" % k quantity = "%.8f" % ob["bids"].get(k) bids.append([price, quantity]) # 推送订单薄数据 orderbook = { "platform": self._platform, "symbol": symbol, "asks": asks, "bids": bids, "timestamp": ob["timestamp"] } EventOrderbook(**orderbook).publish() logger.info("symbol:", symbol, "orderbook:", orderbook, caller=self)
async def on_orderbook_update_callback(self, orderbook: Orderbook): """ 订单薄更新 """ logger.info("orderbook:", orderbook, caller=self) kwargs = { "platform": orderbook.platform, "symbol": orderbook.symbol, "asks": orderbook.asks, "bids": orderbook.bids, "timestamp": orderbook.timestamp } EventOrderbook(**kwargs).publish()
def __init__(self, platform, symbol): self._platform = platform # 平台 self._symbol = symbol # 交易对 self._asks = [] # 买单 self._bids = [] # 卖单 self._ask1 = None # 买一 self._bid1 = None # 卖一 self._timestamp = None # 更新时间戳(秒) self._callback_handlers = [] # 外盘行情有更新的时候,执行的回调函数 # 订阅事件回调 EventOrderbook(self._platform, self._symbol).subscribe(self.on_event_orderbook)
async def process_orderbook(self, data): """Process orderbook data and publish OrderbookEvent.""" for item in data: symbol = item.get("symbol") orderbook = { "platform": self._platform, "symbol": symbol, "asks": item.get("asks"), "bids": item.get("bids"), "timestamp": tools.utctime_str_to_mts(item["timestamp"]) } EventOrderbook(**orderbook).publish() logger.debug("symbol:", symbol, "orderbook:", orderbook, caller=self)
async def do_orderbook_update(self, *args, **kwargs): """ 执行订单薄数据更新 """ for symbol in self._symbols: result, error = await self._rest_api.get_orderbook( symbol, self._orderbook_fetch_count) if error: continue bids = [] asks = [] for item in result["asks"]: a = [item["limitPrice"], item["quantity"]] asks.append(a) for item in result["bids"]: b = [item["limitPrice"], item["quantity"]] bids.append(b) if not bids and not asks: logger.warn("no orderbook data", caller=self) continue # 判断买一是否小于卖一,防止异常数据 if len(bids) > 0 and len(asks) > 0 and float(bids[0][0]) >= float( asks[0][0]): logger.warn("symbol:", symbol, "bids one is grate than asks one! asks:", asks, "bids:", bids, caller=self) continue orderbook = { "platform": self._platform, "symbol": symbol, "asks": asks, "bids": bids, "timestamp": tools.get_cur_timestamp_ms() } EventOrderbook(**orderbook).publish() logger.info("symbol:", symbol, "orderbook:", orderbook, caller=self) # 间隔0.1秒发起下一次请求 await asyncio.sleep(0.1)
async def on_orderbook_update_callback(self, orderbook: Orderbook): """ 订单薄更新 """ logger.info("orderbook:", orderbook, caller=self) #行情保存进数据库 kwargs = {} i = 1 for ask in orderbook.asks: kwargs[f'askprice{i}'] = ask[0] kwargs[f'asksize{i}'] = ask[1] i = i + 1 if i > 20: break i = 1 for bid in orderbook.bids: kwargs[f'bidprice{i}'] = bid[0] kwargs[f'bidsize{i}'] = bid[1] i = i + 1 if i > 20: break kwargs["pubdt"] = orderbook.timestamp #交易所发布行情的时间 kwargs["dt"] = tools.get_cur_timestamp_ms() #本地采集行情的时间 async def save(kwargs): #一秒内会有多次通知,将一秒内的通知都收集在一起,一次性写入数据库,约一秒写一次,提高数据库性能 dlist = self.d_orderbook_map[orderbook.symbol] dlist.append(kwargs) if dlist[len(dlist) - 1]["dt"] - dlist[0]["dt"] > 1000: #每秒写一次数据库 #因为是异步并发,所以先清空列表,重新收集新的一秒内的所有通知,而不是等待数据库IO完成再清空(python的变量只是对象的引用) #xxx = copy.deepcopy(dlist) #dlist.clear() #insert xxx self.d_orderbook_map[orderbook.symbol] = [] #写数据库 t_orderbook = self.t_orderbook_map[orderbook.symbol] if t_orderbook: s, e = await t_orderbook.insert(dlist) if e: logger.error("insert orderbook:", e, caller=self) SingleTask.run(save, kwargs) #发布行情到消息队列 kwargs = { "platform": orderbook.platform, "symbol": orderbook.symbol, "asks": orderbook.asks, "bids": orderbook.bids, "timestamp": orderbook.timestamp } EventOrderbook(**kwargs).publish()
def __init__(self, market_type, platform, symbol, callback): """ 初始化 @param market_type 行情类型 @param platform 交易平台 @param symbol 交易对 @param callback 更新回调函数 """ if market_type == const.MARKET_TYPE_ORDERBOOK: from quant.event import EventOrderbook EventOrderbook(platform, symbol).subscribe(callback) elif market_type == const.MARKET_TYPE_TRADE: from quant.event import EventTrade EventTrade(platform, symbol).subscribe(callback) elif market_type == const.MARKET_TYPE_KLINE: from quant.event import EventKline EventKline(platform, symbol).subscribe(callback)
def __init__(self, market_type, platform, symbol, callback): """ 初始化 @param market_type 行情类型 @param platform 交易平台 @param symbol 交易对 @param callback 行情更新回调函数,必须是async异步函数,回调参数为行情对象,比如k线回调函数: async def on_event_kline_update(kline: Kline): pass """ if market_type == const.MARKET_TYPE_ORDERBOOK: from quant.event import EventOrderbook EventOrderbook(platform, symbol).subscribe(callback) elif market_type == const.MARKET_TYPE_TRADE: from quant.event import EventTrade EventTrade(platform, symbol).subscribe(callback) elif market_type == const.MARKET_TYPE_KLINE: from quant.event import EventKline EventKline(platform, symbol).subscribe(callback)
async def publish_orderbook(self, symbol, data): """ Publish orderbook message to EventCenter via OrderbookEvent. """ if not data["asks"] or not data["bids"]: logger.warn("symbol:", symbol, "asks:", data["asks"], "bids:", data["bids"], caller=self) return ask_keys = sorted(list(data["asks"].keys())) bid_keys = sorted(list(data["bids"].keys()), reverse=True) if ask_keys[0] <= bid_keys[0]: logger.warn("symbol:", symbol, "ask1:", ask_keys[0], "bid1:", bid_keys[0], caller=self) return asks = [] for k in ask_keys[:self._orderbook_length]: price = "%.8f" % k quantity = str(data["asks"].get(k)) asks.append([price, quantity]) bids = [] for k in bid_keys[:self._orderbook_length]: price = "%.8f" % k quantity = str(data["bids"].get(k)) bids.append([price, quantity]) orderbook = { "platform": self._platform, "symbol": symbol, "asks": asks, "bids": bids, "timestamp": data["timestamp"] } EventOrderbook(**orderbook).publish() logger.info("symbol:", symbol, "orderbook:", orderbook, caller=self)
def __init__(self, market_type, platform, symbol, callback): """ Initialize. """ if platform == "#" or symbol == "#": multi = True else: multi = False if market_type == const.MARKET_TYPE_ORDERBOOK: from quant.event import EventOrderbook EventOrderbook(platform, symbol).subscribe(callback, multi) elif market_type == const.MARKET_TYPE_TRADE: from quant.event import EventTrade EventTrade(platform, symbol).subscribe(callback, multi) elif market_type in [const.MARKET_TYPE_KLINE, const.MARKET_TYPE_KLINE_5M, const.MARKET_TYPE_KLINE_15M]: from quant.event import EventKline EventKline(platform, symbol, kline_type=market_type).subscribe(callback, multi) else: logger.error("market_type error:", market_type, caller=self)
async def on_event_orderbook(self, event): """ 事件回调 行情信息 """ orderbook = EventOrderbook().duplicate(event) if orderbook.platform != self._platform or orderbook.symbol != self._symbol: return self._asks = orderbook.asks self._bids = orderbook.bids self._bid1 = self._bids[0] if self._bids else None self._ask1 = self._asks[0] if self._asks else None self._timestamp = orderbook.timestamp for func in self._callback_handlers: asyncio.get_event_loop().create_task( func(self.platform, self.symbol, self.asks, self.bids, self.timestamp))
async def process_orderbook(self, symbol, data): """Process orderbook data and publish OrderbookEvent.""" bids = [] asks = [] for bid in data.get("bids")[:self._orderbook_length]: bids.append(bid[:2]) for ask in data.get("asks")[:self._orderbook_length]: asks.append(ask[:2]) orderbook = { "platform": self._platform, "symbol": symbol, "asks": asks, "bids": bids, "timestamp": tools.get_cur_timestamp_ms() } EventOrderbook(**orderbook).publish() logger.info("symbol:", symbol, "orderbook:", orderbook, caller=self)
async def get_newest_orderbook(self, symbol): """ Get the newest orderbook information. """ result, error = await self._rest_api.get_orderbook( symbol.replace("/", ""), self._orderbook_length) key = list(result.keys())[0] asks, bids = [], [] for item in result.get(key)["asks"]: asks.append(item[:2]) for item in result.get(key)["bids"]: bids.append(item[:2]) orderbook = { "platform": self._platform, "symbol": symbol, "asks": asks, "bids": bids, "timestamp": tools.get_cur_timestamp_ms() } EventOrderbook(**orderbook).publish() logger.info("symbol:", symbol, "orderbook:", orderbook, caller=self)
async def do_orderbook_update(self, *args, **kwargs): """ Fetch orderbook information.""" for symbol in self._symbols: result, error = await self._rest_api.get_orderbook( symbol.replace("/", "-"), self._orderbook_length) if error: continue orderbook = { "platform": self._platform, "symbol": symbol, "asks": result["asks"], "bids": result["bids"], "timestamp": result["time"] } EventOrderbook(**orderbook).publish() logger.info("symbol:", symbol, "orderbook:", orderbook, caller=self) # await 0.1 second before next request. await asyncio.sleep(0.1)
async def process_orderbook(self, data): """Process orderbook data and publish OrderbookEvent.""" symbol = data["instrument"] if symbol not in self._symbols: return bids = [] for item in data["bids"][:self._orderbook_length]: b = [item.get("price"), item.get("quantity")] bids.append(b) asks = [] for item in data["asks"][:self._orderbook_length]: a = [item.get("price"), item.get("quantity")] asks.append(a) self._last_msg_ts = tools.get_cur_timestamp_ms() orderbook = { "platform": self._platform, "symbol": symbol, "asks": asks, "bids": bids, "timestamp": self._last_msg_ts } EventOrderbook(**orderbook).publish() logger.debug("symbol:", symbol, "orderbook:", orderbook, caller=self)
async def process_binary(self, msg): """ Process binary message that received from Websocket connection. Args: msg: Binary message. """ data = json.loads(gzip.decompress(msg).decode()) # logger.debug("data:", json.dumps(data), caller=self) channel = data.get("ch") if not channel: if data.get("ping"): hb_msg = {"pong": data.get("ping")} await self._ws.send(hb_msg) return symbol = self._c_to_s[channel] if channel.find("kline") != -1: d = data.get("tick") kline = { "platform": self._platform, "symbol": symbol, "open": d["open"], "high": d["high"], "low": d["low"], "close": d["close"], "volume": d["amount"], "timestamp": data.get("ts"), "kline_type": MARKET_TYPE_KLINE } EventKline(**kline).publish() logger.debug("symbol:", symbol, "kline:", kline, caller=self) elif channel.find("depth") != -1: tick = data.get("tick") asks = tick.get("asks")[:self._orderbook_length] bids = tick.get("bids")[:self._orderbook_length] timestamp = tick.get("ts") orderbook = { "platform": self._platform, "symbol": symbol, "asks": asks, "bids": bids, "timestamp": timestamp } EventOrderbook(**orderbook).publish() logger.debug("symbol:", symbol, "orderbook:", orderbook, caller=self) elif channel.find("trade") != -1: tick = data.get("tick") direction = tick["data"][0].get("direction") price = tick["data"][0].get("price") quantity = tick["data"][0].get("amount") trade = { "platform": self._platform, "symbol": symbol, "action": ORDER_ACTION_BUY if direction == "buy" else ORDER_ACTION_SELL, "price": price, "quantity": quantity, "timestamp": tick.get("ts") } EventTrade(**trade).publish() logger.debug("symbol:", symbol, "trade:", trade, caller=self) else: logger.error("event error! msg:", msg, caller=self)
async def process_binary(self, msg): """ 处理websocket上接收到的消息 """ data = json.loads(gzip.decompress(msg).decode()) # logger.debug("data:", json.dumps(data), caller=self) channel = data.get("ch") if not channel: if data.get("ping"): self.heartbeat_msg = data return symbol = self._c_to_s[channel] if channel.find("kline") != -1: # K线 d = data.get("tick") kline = { "platform": self._platform, "symbol": symbol, "open": "%.8f" % d["open"], # 开盘价 "high": "%.8f" % d["high"], # 最高价 "low": "%.8f" % d["low"], # 最低价 "close": "%.8f" % d["close"], # 收盘价 "volume": "%.8f" % d["amount"], # 成交量 "timestamp": int(data.get("ts")), # 时间戳 "kline_type": MARKET_TYPE_KLINE } EventKline(**kline).publish() logger.info("symbol:", symbol, "kline:", kline, caller=self) elif channel.find("depth") != -1: # 订单薄 d = data.get("tick") asks, bids = [], [] for item in d.get("asks")[:10]: price = "%.8f" % item[0] quantity = "%.8f" % item[1] asks.append([price, quantity]) for item in d.get("bids")[:10]: price = "%.8f" % item[0] quantity = "%.8f" % item[1] bids.append([price, quantity]) orderbook = { "platform": self._platform, "symbol": symbol, "asks": asks, "bids": bids, "timestamp": d.get("ts") } EventOrderbook(**orderbook).publish() logger.info("symbol:", symbol, "orderbook:", orderbook, caller=self) elif channel.find("trade") != -1: # 实时交易数据 tick = data.get("tick") direction = tick["data"][0].get("direction") price = tick["data"][0].get("price") quantity = tick["data"][0].get("amount") trade = { "platform": self._platform, "symbol": symbol, "action": ORDER_ACTION_BUY if direction == "buy" else ORDER_ACTION_SELL, "price": "%.8f" % price, "quantity": "%.8f" % quantity, "timestamp": tick.get("ts") } EventTrade(**trade).publish() logger.info("symbol:", symbol, "trade:", trade, caller=self) else: logger.error("event error! msg:", msg, caller=self)