Exemple #1
0
    async def check_asset_update(self, *args, **kwargs):
        """Fetch asset information."""
        result, error = await self._rest_api.get_user_account()
        if error:
            logger.warn("platform:", self._platform, "account:", self._account, "get asset info failed!", caller=self)
            return

        assets = {}
        for item in result["info"]:
            symbol = item["instrument_id"].split("-")[0]
            total = float(item["equity"])
            locked = float(item["margin"])
            if total > 0:
                assets[symbol] = {
                    "total": "%.8f" % total,
                    "free": "%.8f" % (total - locked),
                    "locked": "%.8f" % locked
                }

        if assets == self._assets:
            update = False
        else:
            update = True
        self._assets = assets

        # Publish AssetEvent.
        timestamp = tools.get_cur_timestamp_ms()
        EventAsset(self._platform, self._account, self._assets, timestamp, update).publish()
        logger.info("platform:", self._platform, "account:", self._account, "asset:", self._assets, caller=self)
Exemple #2
0
    async def process_binary(self, raw):
        """ 处理websocket上接收到的消息
        @param raw 原始的压缩数据
        """
        decompress = zlib.decompressobj(-zlib.MAX_WBITS)
        msg = decompress.decompress(raw)
        msg += decompress.flush()
        msg = msg.decode()
        if msg == "pong":  # 心跳返回
            return
        msg = json.loads(msg)
        # logger.debug("msg:", msg, caller=self)

        table = msg.get("table")
        if table == "spot/depth":  # 订单薄
            if msg.get("action") == "partial":  # 首次返回全量数据
                for d in msg["data"]:
                    await self.deal_orderbook_partial(d)
            elif msg.get("action") == "update":  # 返回增量数据
                for d in msg["data"]:
                    await self.deal_orderbook_update(d)
            else:
                logger.warn("unhandle msg:", msg, caller=self)
        elif table == "spot/trade":
            for d in msg["data"]:
                await self.deal_trade_update(d)
        elif table == "spot/candle60s":
            for d in msg["data"]:
                await self.deal_kline_update(d)
        else:
            logger.warn("unhandle msg:", msg, caller=self)
Exemple #3
0
    async def connected_callback(self):
        """After create connection to Websocket server successfully, we will subscribe orderbook/trade/kline event."""
        if not self._symbols:
            logger.warn("symbols not found in config file.", caller=self)
            return
        events = []
        for channel in self._channels:
            if channel == "orderbook":
                events.append("order_book")
            elif channel == "trade":
                events.append("trade")
        if not events:
            logger.warn("channels not found in config file.", caller=self)
            return

        nonce = tools.get_cur_timestamp_ms()
        uri = "/api/v1/private/subscribe"
        params = {"instrument": self._symbols, "event": events}
        sign = self.deribit_signature(nonce, uri, params, self._access_key,
                                      self._secret_key)
        data = {
            "id": "thenextquant",
            "action": uri,
            "arguments": params,
            "sig": sign
        }
        await self._ws.send(data)
        logger.info("subscribe orderbook success.", caller=self)
Exemple #4
0
    async def check_asset_update(self, *args, **kwargs):
        """Fetch asset information."""
        result, error = await self._rest_api.get_user_account()
        if error:
            logger.warn("platform:", self._platform, "account:", self._account, "get asset info failed!", caller=self)
            return

        assets = {}
        for item in result:
            symbol = item["currency"]
            total = float(item["balance"])
            free = float(item["available"])
            locked = float(item["frozen"])
            if total > 0:
                assets[symbol] = {
                    "total": "%.8f" % total,
                    "free": "%.8f" % free,
                    "locked": "%.8f" % locked
                }

        if assets == self._assets:
            update = False
        else:
            update = True
        self._assets = assets

        # Publish AssetEvent.
        timestamp = tools.get_cur_timestamp_ms()
        EventAsset(self._platform, self._account, self._assets, timestamp, update).publish()
        logger.info("platform:", self._platform, "account:", self._account, "asset:", self._assets, caller=self)
Exemple #5
0
 async def connected_callback(self):
     """After create Websocket connection successfully, we will subscribing orderbook/trade/kline events."""
     if not self._symbols:
         logger.warn("symbols not found in config file.", caller=self)
         return
     if not self._channels:
         logger.warn("channels not found in config file.", caller=self)
         return
     for ch in self._channels:
         if ch == "trade":
             params = []
             for s in self._symbols:
                 params.append(s.replace("/", "_"))
             request_id = await self._generate_request_id()
             d = {"id": request_id, "method": "trades.subscribe", "params": params}
             await self._ws.send(d)
             logger.info("subscribe trade success.", caller=self)
         elif ch == "orderbook":
             await self.subscribe_orderbook()
         elif ch == "kline":
             for s in self._symbols:
                 params = [s.replace("/", "_"), 60]
                 request_id = await self._generate_request_id()
                 d = {"id": request_id, "method": "kline.subscribe", "params": params}
                 await self._ws.send(d)
                 logger.info("subscribe kline success.", caller=self)
         else:
             logger.error("channel error:", ch, caller=self)
             continue
Exemple #6
0
    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)
Exemple #7
0
    async def connected_callback(self):
        """ After create Websocket connection successfully, we will subscribing orderbook/trade events.
        """
        symbols = []
        for s in self._symbols:
            t = s.replace("/", "-")
            symbols.append(t)
            self._symbols_map[t] = s

        if not symbols:
            logger.warn("symbols not found in config file.", caller=self)
            return
        if not self._channels:
            logger.warn("channels not found in config file.", caller=self)
            return

        channels = []
        for ch in self._channels:
            if ch == "orderbook":
                sub = {"name": "level2", "product_ids": symbols}
                channels.append(sub)
            elif ch == "trade":
                sub = {"name": "ticker", "product_ids": symbols}
                channels.append(sub)
            else:
                logger.error("channel error! channel:", ch, caller=self)
        if channels:
            msg = {"type": "subscribe", "channels": channels}
            await self._ws.send(msg)
            logger.info("subscribe orderbook/trade success.", caller=self)
Exemple #8
0
    async def process_binary(self, raw):
        """ Process binary message that received from Websocket connection.

        Args:
            raw: Raw message that received from Websocket connection.
        """
        decompress = zlib.decompressobj(-zlib.MAX_WBITS)
        msg = decompress.decompress(raw)
        msg += decompress.flush()
        msg = msg.decode()
        # logger.debug("msg:", msg, caller=self)
        if msg == "pong":
            return
        msg = json.loads(msg)

        table = msg.get("table")
        if table == "spot/depth":
            if msg.get("action") == "partial":
                for d in msg["data"]:
                    await self.process_orderbook_partial(d)
            elif msg.get("action") == "update":
                for d in msg["data"]:
                    await self.deal_orderbook_update(d)
            else:
                logger.warn("unhandle msg:", msg, caller=self)
        elif table == "spot/trade":
            for d in msg["data"]:
                await self.process_trade(d)
        elif table == "spot/candle60s":
            for d in msg["data"]:
                await self.process_kline(d)
Exemple #9
0
    async def check_asset_update(self, *args, **kwargs):
        """ 检查账户资金是否更新
        """
        result, error = await self._rest_api.get_user_account()
        if error:
            logger.warn("platform:", self._platform, "account:", self._account, "get asset info failed!", caller=self)
            return

        assets = {}
        for name, item in result["info"].items():
            symbol = name.upper()
            total = float(item["equity"])
            locked = float(item["margin"])
            if total > 0:
                assets[symbol] = {
                    "total": "%.8f" % total,
                    "free": "%.8f" % (total - locked),
                    "locked": "%.8f" % locked
                }

        if assets == self._assets:
            update = False
        else:
            update = True
        self._assets = assets

        # 推送当前资产
        timestamp = tools.get_cur_timestamp_ms()
        EventAsset(self._platform, self._account, self._assets, timestamp, update).publish()
        logger.info("platform:", self._platform, "account:", self._account, "asset:", self._assets, caller=self)
Exemple #10
0
 async def _check_connection(self, *args, **kwargs):
     """Check Websocket connection, if connection closed, re-connect immediately."""
     if not self.ws:
         logger.warn("Websocket connection not connected yet!", caller=self)
         return
     if self.ws.closed:
         SingleTask.run(self._reconnect)
    async def revoke_orders(self, instrument_id, order_ids):
        """ Cancelling multiple open orders with order_id,Maximum 10 orders can be cancelled at a time for each
            trading pair.

        Args:
            instrument_id: Contract ID, e.g. BTC-USD-180213.
            order_ids: order ID list.

        Returns:
            success: Success results, otherwise it's None.
            error: Error information, otherwise it's None.
        """
        assert isinstance(order_ids, list)
        if len(order_ids) > 10:
            logger.warn("order id list too long! no more than 10!",
                        caller=self)
        uri = "/api/futures/v3/cancel_batch_orders/{instrument_id}".format(
            instrument_id=instrument_id)
        body = {"order_ids": order_ids}
        success, error = await self.request("POST", uri, body=body, auth=True)
        if error:
            return None, error
        if not success["result"]:
            return None, success
        return success, None
Exemple #12
0
    async def process(self, msg):
        """Process message that received from Websocket connection.

        Args:
            msg: Message received from Websocket connection.
        """
        # 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":
            await self.process_kline(symbol, data)
        elif channel.endswith("depth20"):
            await self.process_orderbook(symbol, data)
        elif e == "trade":
            await self.process_trade(symbol, data)
Exemple #13
0
    async def connected_callback(self):
        """ After create Websocket connection successfully, we will subscribing orderbook/trade/kline.
        """
        if not self._symbols:
            logger.warn("symbols not found in config file.", caller=self)
            return
        if not self._channels:
            logger.warn("channels not found in config file.", caller=self)
            return
        for ch in self._channels:
            if ch == "orderbook":
                # subscription = {"name": "book"}
                LoopRunTask.register(self.on_event_update_orderbook, 2)
                continue
            elif ch == "trade":
                subscription = {"name": "trade"}
            # elif ch == "kline":  # TODO: something wrong from exchange server? subscribe ohlc-1 but receive ohlc-5 ?
            #     subscription = {"name": "ohlc", "interval": 1}
            else:
                logger.error("channel error:", ch, caller=self)
                continue

            d = {
                "event": "subscribe",
                "pair": self._symbols,
                "subscription": subscription
            }
            await self.ws.send_json(d)
            logger.info("subscribe", ch, "success.", caller=self)
Exemple #14
0
    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 connected_callback(self):
        """ 建立连接之后,获取当前所有未完全成交的订单
        """
        order_infos, error = await self._rest_api.get_open_orders(
            self._raw_symbol)
        if error:
            return
        for order_info in order_infos:
            order_no = "{}_{}".format(order_info["orderId"],
                                      order_info["clientOrderId"])
            if order_info["status"] == "NEW":  # 部分成交
                status = ORDER_STATUS_SUBMITTED
            elif order_info["status"] == "PARTIALLY_FILLED":  # 部分成交
                status = ORDER_STATUS_PARTIAL_FILLED
            elif order_info["status"] == "FILLED":  # 完全成交
                status = ORDER_STATUS_FILLED
            elif order_info["status"] == "CANCELED":  # 取消
                status = ORDER_STATUS_CANCELED
            elif order_info["status"] == "REJECTED":  # 拒绝
                status = ORDER_STATUS_FAILED
            elif order_info["status"] == "EXPIRED":  # 过期
                status = ORDER_STATUS_FAILED
            else:
                logger.warn("unknown status:", order_info, caller=self)
                return

            info = {
                "platform":
                self._platform,
                "account":
                self._account,
                "strategy":
                self._strategy,
                "order_no":
                order_no,
                "action":
                order_info["side"],
                "order_type":
                order_info["type"],
                "symbol":
                self._symbol,
                "price":
                order_info["price"],
                "quantity":
                order_info["origQty"],
                "remain":
                float(order_info["origQty"]) -
                float(order_info["executedQty"]),
                "status":
                status,
                "ctime":
                order_info["time"],
                "utime":
                order_info["updateTime"]
            }
            order = Order(**info)
            self._orders[order_no] = order
            if self._order_update_callback:
                SingleTask.run(self._order_update_callback, order)
Exemple #16
0
 async def publish(self, event):
     """ 发布消息
     @param event 发布的事件对象
     """
     if not self._connected:
         logger.warn("RabbitMQ not ready right now!", caller=self)
         return
     data = event.dumps()
     await self._channel.basic_publish(payload=data, exchange_name=event.exchange, routing_key=event.routing_key)
Exemple #17
0
 async def _check_connection(self, *args, **kwargs):
     """ 检查连接是否正常
     """
     # 检查websocket连接是否关闭,如果关闭,那么立即重连
     if not self.ws:
         logger.warn("websocket connection not connected yet!", caller=self)
         return
     if self.ws.closed:
         await asyncio.get_event_loop().create_task(self._reconnect())
         return
Exemple #18
0
    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)
Exemple #19
0
 async def receive(self):
     """ 接收消息
     """
     """
     See: client_ws.py
     
     async def __anext__(self):
         msg = await self.receive()
         if msg.type in (WSMsgType.CLOSE,
                         WSMsgType.CLOSING,
                         WSMsgType.CLOSED):
             raise StopAsyncIteration  # NOQA
         return msg
     """
     self.last_timestamp = tools.get_cur_timestamp()  #单位:秒,连接检测时间初始化
     async for msg in self.ws:  #参考aiohttp的源码,当ws连接被关闭后,本循环将退出
         self.last_timestamp = tools.get_cur_timestamp(
         )  #单位:秒,每收到一个消息就更新一下此变量,用于判断网络是否出问题,是否需要重连
         if msg.type == aiohttp.WSMsgType.TEXT:
             try:
                 data = json.loads(msg.data)
             except:
                 data = msg.data
             #await asyncio.get_event_loop().create_task(self.process(data)) #这样写的好处是如果里面这个函数发生异常不会影响本循环,因为它在单独任务里面执行
             try:
                 await self.process(data)
             except Exception as e:
                 logger.error("process ERROR:", e, caller=self)
                 await self.socket_close()  #关闭
                 break  #退出循环
         elif msg.type == aiohttp.WSMsgType.BINARY:
             #await asyncio.get_event_loop().create_task(self.process_binary(msg.data)) #好处同上
             try:
                 await self.process_binary(msg.data)
             except Exception as e:
                 logger.error("process_binary ERROR:", e, caller=self)
                 await self.socket_close()  #关闭
                 break  #退出循环
         elif msg.type == aiohttp.WSMsgType.ERROR:
             logger.error("receive event ERROR:", msg, caller=self)
             break  #退出循环
         else:
             #aiohttp.WSMsgType.CONTINUATION
             #aiohttp.WSMsgType.PING
             #aiohttp.WSMsgType.PONG
             logger.warn("unhandled msg:", msg, caller=self)
     #当代码执行到这里的时候ws已经是关闭状态,所以不需要再调用close去关闭ws了.
     #当ws连接被关闭或者出现任何错误,将重新连接
     state = State(self._platform, self._account,
                   "connection lost! url: {}".format(self._url),
                   State.STATE_CODE_DISCONNECT)
     SingleTask.run(self.cb.on_state_update_callback, state)
     self.last_timestamp = 0  #先置0,相当于关闭连接检测
     asyncio.get_event_loop().create_task(self._reconnect())
Exemple #20
0
 async def _reconnect(self, delay=5):
     """ 重新建立websocket连接
     """
     if delay > 0:
         await asyncio.sleep(delay)  #等待一段时间再重连
     logger.warn("reconnecting websocket right now!", caller=self)
     state = State(
         self._platform, self._account,
         "reconnecting websocket right now! url: {}".format(self._url),
         State.STATE_CODE_RECONNECTING)
     SingleTask.run(self.cb.on_state_update_callback, state)
     await self._connect()
Exemple #21
0
    async def check_asset_update(self, *args, **kwargs):
        """Fetch asset information."""
        result, error = await self._rest_api.get_account_balance()
        if error:
            logger.warn("platform:",
                        self._platform,
                        "account:",
                        self._account,
                        "get asset info failed!",
                        caller=self)
            return

        temps = {}
        for item in result.get("list"):
            name = item.get("currency").upper()
            t = item.get("type")
            b = float(item.get("balance"))
            if name not in temps:
                temps[name] = {}
            if t == "trade":
                temps[name]["free"] = b
            else:
                temps[name]["locked"] = b

        assets = {}
        for name, item in temps.items():
            total = item["free"] + item["locked"]
            if total <= 0:
                continue
            assets[name] = {
                "free": "%.8f" % item["free"],
                "locked": "%.8f" % item["locked"],
                "total": "%.8f" % total
            }

        if assets == self._assets:
            update = False
        else:
            update = True
        self._assets = assets

        # Publish AssetEvent.
        timestamp = tools.get_cur_timestamp_ms()
        EventAsset(self._platform, self._account, self._assets, timestamp,
                   update).publish()
        logger.info("platform:",
                    self._platform,
                    "account:",
                    self._account,
                    "asset:",
                    self._assets,
                    caller=self)
    async def revoke_order(self, *order_nos):
        """ Revoke (an) order(s).

        Args:
            order_nos: Order id list, you can set this param to 0 or multiple items. If you set 0 param, you can cancel
                all orders for this symbol(initialized in Trade object). If you set 1 param, you can cancel an order.
                If you set multiple param, you can cancel multiple orders. Do not set param length more than 100.

        Returns:
            Success or error, see bellow.

        NOTEs:
            DO NOT INPUT MORE THAT 10 ORDER NOs, you can invoke many times.
        """
        # If len(order_nos) == 0, you will cancel all orders for this symbol(initialized in Trade object).
        if len(order_nos) == 0:
            result, error = await self._rest_api.get_order_list(
                self._symbol, 6)
            if error:
                return False, error
            if len(result) > 100:
                logger.warn("order length too long! (more than 100)",
                            caller=self)
            for order_info in result["order_info"]:
                order_no = order_info["order_id"]
                _, error = await self._rest_api.revoke_order(
                    self._symbol, order_no)
                if error:
                    return False, error
            return True, None

        # If len(order_nos) == 1, you will cancel an order.
        if len(order_nos) == 1:
            success, error = await self._rest_api.revoke_order(
                self._symbol, order_nos[0])
            if error:
                return order_nos[0], error
            else:
                return order_nos[0], None

        # If len(order_nos) > 1, you will cancel multiple orders.
        if len(order_nos) > 1:
            success, error = [], []
            for order_no in order_nos:
                _, e = await self._rest_api.revoke_order(
                    self._symbol, order_no)
                if e:
                    error.append((order_no, e))
                else:
                    success.append(order_no)
            return success, error
Exemple #23
0
    async def publish(self, event):
        """ Publish a event.

        Args:
            event: A event to publish.
        """
        if not self._connected:
            logger.warn("RabbitMQ not ready right now!", caller=self)
            return
        data = event.dumps()
        await self._channel.basic_publish(payload=data,
                                          exchange_name=event.exchange,
                                          routing_key=event.routing_key)
        logger.debug("Publish to RabbitMQ: ", event, caller=self)
Exemple #24
0
 async def revoke_orders(self, symbol, order_nos):
     """ 批量撤销委托单
     @param symbol 交易对
     @param order_nos 订单列表
     * NOTE: 单次不超过4个订单id
     """
     if len(order_nos) > 4:
         logger.warn("only revoke 4 orders per request!", caller=self)
     body = [{"instrument_id": symbol, "order_ids": order_nos[:4]}]
     result, error = await self.request("POST",
                                        "/api/spot/v3/cancel_batch_orders",
                                        body=body,
                                        auth=True)
     return result, error
Exemple #25
0
 async def _send_heartbeat_msg(self, *args, **kwargs):
     """Send heartbeat message to Websocket server."""
     if not self.ws:
         logger.warn("Websocket connection not connected yet!", caller=self)
         return
     if self._heartbeat_msg:
         if isinstance(self._heartbeat_msg, dict):
             await self.ws.send_json(self._heartbeat_msg)
         elif isinstance(self._heartbeat_msg, str):
             await self.ws.send_str(self._heartbeat_msg)
         else:
             logger.error("send heartbeat message failed:", self._heartbeat_msg, caller=self)
             return
         logger.debug("send heartbeat message:", self._heartbeat_msg, caller=self)
Exemple #26
0
    async def connected_callback(self):
        """ After websocket connection created successfully, pull back all open order information.
        """
        logger.info("Websocket connection authorized successfully.", caller=self)
        order_infos, error = await self._rest_api.get_open_orders(self._raw_symbol)
        if error:
            e = Error("get open orders error: {}".format(error))
            if self._init_success_callback:
                SingleTask.run(self._init_success_callback, False, e)
            return
        for order_info in order_infos:
            order_no = "{}_{}".format(order_info["orderId"], order_info["clientOrderId"])
            if order_info["status"] == "NEW":
                status = ORDER_STATUS_SUBMITTED
            elif order_info["status"] == "PARTIALLY_FILLED":
                status = ORDER_STATUS_PARTIAL_FILLED
            elif order_info["status"] == "FILLED":
                status = ORDER_STATUS_FILLED
            elif order_info["status"] == "CANCELED":
                status = ORDER_STATUS_CANCELED
            elif order_info["status"] == "REJECTED":
                status = ORDER_STATUS_FAILED
            elif order_info["status"] == "EXPIRED":
                status = ORDER_STATUS_FAILED
            else:
                logger.warn("unknown status:", order_info, caller=self)
                continue

            info = {
                "platform": self._platform,
                "account": self._account,
                "strategy": self._strategy,
                "order_no": order_no,
                "action": order_info["side"],
                "order_type": order_info["type"],
                "symbol": self._symbol,
                "price": order_info["price"],
                "quantity": order_info["origQty"],
                "remain": float(order_info["origQty"]) - float(order_info["executedQty"]),
                "status": status,
                "ctime": order_info["time"],
                "utime": order_info["updateTime"]
            }
            order = Order(**info)
            self._orders[order_no] = order
            if self._order_update_callback:
                SingleTask.run(self._order_update_callback, copy.copy(order))

        if self._init_success_callback:
            SingleTask.run(self._init_success_callback, True, None)
Exemple #27
0
 async def receive(self):
     """ 接收消息
     """
     async for msg in self.ws:
         if msg.type == aiohttp.WSMsgType.TEXT:
             try:
                 data = json.loads(msg.data)
             except:
                 data = msg.data
             await asyncio.get_event_loop().create_task(self.process(data))
         elif msg.type == aiohttp.WSMsgType.BINARY:
             await asyncio.get_event_loop().create_task(
                 self.process_binary(msg.data))
         elif msg.type == aiohttp.WSMsgType.CLOSED:
             logger.warn("receive event CLOSED:", msg, caller=self)
             await asyncio.get_event_loop().create_task(self._reconnect())
         elif msg.type == aiohttp.WSMsgType.CLOSE:
             logger.warn("receive event CLOSE:", msg, caller=self)
             await asyncio.get_event_loop().create_task(self._reconnect())
         elif msg.type == aiohttp.WSMsgType.CLOSING:
             logger.warn("receive event CLOSING:", msg, caller=self)
             await asyncio.get_event_loop().create_task(self._reconnect())
         elif msg.type == aiohttp.WSMsgType.ERROR:
             logger.error("receive event ERROR:", msg, caller=self)
             await asyncio.get_event_loop().create_task(self._reconnect())
         else:
             logger.warn("unhandled msg:", msg, caller=self)
Exemple #28
0
    async def process(self, msg):
        """ Process message that received from Websocket connection.

        Args:
            msg: message received from Websocket connection.
        """
        logger.debug("msg:", json.dumps(msg), caller=self)
        e = msg.get("e")
        if e == "executionReport":  # Order update.
            if msg["s"] != self._raw_symbol:
                return
            order_no = "{}_{}".format(msg["i"], msg["c"])
            if msg["X"] == "NEW":
                status = ORDER_STATUS_SUBMITTED
            elif msg["X"] == "PARTIALLY_FILLED":
                status = ORDER_STATUS_PARTIAL_FILLED
            elif msg["X"] == "FILLED":
                status = ORDER_STATUS_FILLED
            elif msg["X"] == "CANCELED":
                status = ORDER_STATUS_CANCELED
            elif msg["X"] == "REJECTED":
                status = ORDER_STATUS_FAILED
            elif msg["X"] == "EXPIRED":
                status = ORDER_STATUS_FAILED
            else:
                logger.warn("unknown status:", msg, caller=self)
                return
            order = self._orders.get(order_no)
            if not order:
                info = {
                    "platform": self._platform,
                    "account": self._account,
                    "strategy": self._strategy,
                    "order_no": order_no,
                    "client_order_id": msg["c"],
                    "action": msg["S"],
                    "order_type": msg["o"],
                    "symbol": self._symbol,
                    "price": msg["p"],
                    "quantity": msg["q"],
                    "ctime": msg["O"]
                }
                order = Order(**info)
                self._orders[order_no] = order
            order.remain = float(msg["q"]) - float(msg["z"])
            order.status = status
            order.utime = msg["T"]
            if self._order_update_callback:
                SingleTask.run(self._order_update_callback, copy.copy(order))
Exemple #29
0
    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)
Exemple #30
0
 async def fetch(cls, method, url, params=None, body=None, data=None, headers=None, timeout=30, **kwargs):
     """ 发起HTTP请求
     @param method 请求方法 GET/POST/PUT/DELETE
     @param url 请求的url
     @param params 请求的uri参数
     @param body 请求的body参数
     @param data json格式的数据
     @param headers 请求的headers
     @param timeout 超时时间(秒)
     @return (code, success, error) 如果成功,error为None,失败success为None,error为失败信息
     """
     session = cls._get_session(url)
     if not kwargs.get("proxy"):
         kwargs["proxy"] = config.proxy  # HTTP代理配置
     try:
         if method == "GET":
             response = await session.get(url, params=params, headers=headers, timeout=timeout, **kwargs)
         elif method == "POST":
             response = await session.post(url, params=params, data=body, json=data, headers=headers,
                                           timeout=timeout, **kwargs)
         elif method == "PUT":
             response = await session.put(url, params=params, data=body, json=data, headers=headers,
                                          timeout=timeout, **kwargs)
         elif method == "DELETE":
             response = await session.delete(url, params=params, data=body, json=data, headers=headers,
                                             timeout=timeout, **kwargs)
         else:
             error = "http method error!"
             return None, None, error
     except Exception as e:
         logger.error("method:", method, "url:", url, "params:", params, "body:", body, "data:", data, "Error:", e,
                      caller=cls)
         return None, None, e
     code = response.status
     if code not in (200, 201, 202, 203, 204, 205, 206):
         text = await response.text()
         logger.error("method:", method, "url:", url, "params:", params, "body:", body, "headers:", headers,
                      "code:", code, "result:", text, caller=cls)
         return code, None, text
     try:
         result = await response.json()
     except:
         logger.warn("response data is not json format!", "method:", method, "url:", url, "params:", params,
                     caller=cls)
         result = await response.text()
     logger.debug("method:", method, "url:", url, "params:", params, "body:", body, "data:", data,
                  "code:", code, "result:", result, caller=cls)
     return code, result, None