Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
0
 def __init__(self,
              account=None,
              platform=None,
              strategy=None,
              order_no=None,
              symbol=None,
              action=None,
              price=0,
              quantity=0,
              remain=0,
              status=ORDER_STATUS_NONE,
              avg_price=0,
              order_type=ORDER_TYPE_LIMIT,
              trade_type=TRADE_TYPE_NONE,
              ctime=None,
              utime=None):
     self.platform = platform  # 交易平台
     self.account = account  # 交易账户
     self.strategy = strategy  # 策略名称
     self.order_no = order_no  # 委托单号
     self.action = action  # 买卖类型 SELL-卖,BUY-买
     self.order_type = order_type  # 委托单类型 MARKET-市价,LIMIT-限价
     self.symbol = symbol  # 交易对 如: ETH/BTC
     self.price = price  # 委托价格
     self.quantity = quantity  # 委托数量(限价单)
     self.remain = remain  # 剩余未成交数量
     self.status = status  # 委托单状态
     self.avg_price = avg_price  # 成交均价
     self.trade_type = trade_type  # 合约订单类型 开多/开空/平多/平空
     self.ctime = ctime if ctime else tools.get_cur_timestamp()  # 创建订单时间戳
     self.utime = utime if utime else tools.get_cur_timestamp()  # 交易所订单更新时间
Ejemplo n.º 3
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())
Ejemplo n.º 4
0
 async def find_one_and_update(self,
                               spec,
                               update_fields,
                               upsert=False,
                               return_document=False,
                               fields=None,
                               cursor=None):
     """ 查询一条指定数据,并修改这条数据
     @param spec 查询条件
     @param update_fields 更新字段
     @param upsert 如果不满足条件,是否插入新数据,默认False
     @param return_document 返回修改之前数据或修改之后数据,默认False为修改之前数据
     @param fields 需要返回的字段,默认None为返回全部数据
     @return result 修改之前或之后的数据
     @param cursor 查询游标,如不指定默认使用self._cursor
     """
     if not cursor:
         cursor = self._cursor
     spec[DELETE_FLAG] = {"$ne": True}
     if "_id" in spec:
         spec["_id"] = self._convert_id_object(spec["_id"])
     set_fields = update_fields.get("$set", {})
     set_fields["update_time"] = tools.get_cur_timestamp()
     update_fields["$set"] = set_fields
     result = await cursor.find_one_and_update(
         spec,
         update_fields,
         projection=fields,
         upsert=upsert,
         return_document=return_document)
     if result and "_id" in result:
         result["_id"] = str(result["_id"])
     return result
Ejemplo n.º 5
0
 async def update(self,
                  spec,
                  update_fields,
                  upsert=False,
                  multi=False,
                  cursor=None):
     """ 更新
     @param spec 更新条件
     @param update_fields 更新字段
     @param upsert 如果不满足条件,是否插入新数据
     @param multi 是否批量更新
     @return modified_count 更新数据条数
     @param cursor 查询游标,如不指定默认使用self._cursor
     """
     if not cursor:
         cursor = self._cursor
     update_fields = copy.deepcopy(update_fields)
     spec[DELETE_FLAG] = {"$ne": True}
     if "_id" in spec:
         spec["_id"] = self._convert_id_object(spec["_id"])
     set_fields = update_fields.get("$set", {})
     set_fields["update_time"] = tools.get_cur_timestamp()
     update_fields["$set"] = set_fields
     if not multi:
         result = await cursor.update_one(spec,
                                          update_fields,
                                          upsert=upsert)
         return result.modified_count
     else:
         result = await cursor.update_many(spec,
                                           update_fields,
                                           upsert=upsert)
         return result.modified_count
Ejemplo n.º 6
0
 async def insert(self, docs_data, cursor=None):
     """ 插入数据
     @param docs_data 插入数据 dict或list
     @param ret_ids 插入数据的id列表
     @param cursor 查询游标,如不指定默认使用self._cursor
     """
     if not cursor:
         cursor = self._cursor
     docs = copy.deepcopy(docs_data)
     ret_ids = []
     is_one = False
     create_time = tools.get_cur_timestamp()
     if not isinstance(docs, list):
         docs = [docs]
         is_one = True
     for doc in docs:
         doc["_id"] = ObjectId()
         doc["create_time"] = create_time
         doc["update_time"] = create_time
         ret_ids.append(str(doc["_id"]))
     cursor.insert_many(docs)
     if is_one:
         return ret_ids[0]
     else:
         return ret_ids
Ejemplo n.º 7
0
    async def find_one_and_update(self, spec, update_fields, upsert=False, return_document=False, fields=None,
                                  cursor=None):
        """ Find a document and update this document.

        Args:
            spec: Query params.
            update_fields: Fields to be updated.
            upsert: If server this document if not exist? True or False.
            return_document: If return new document? `True` return new document, False return old document.
            fields: The fields to be return.
            cursor: Query cursor, default is `self._cursor`.

        Return:
            result: Document.
        """
        if not cursor:
            cursor = self._cursor
        spec[DELETE_FLAG] = {"$ne": True}
        if "_id" in spec:
            spec["_id"] = self._convert_id_object(spec["_id"])
        set_fields = update_fields.get("$set", {})
        set_fields["update_time"] = tools.get_cur_timestamp()
        update_fields["$set"] = set_fields
        result = await cursor.find_one_and_update(spec, update_fields, projection=fields, upsert=upsert,
                                                  return_document=return_document)
        if result and "_id" in result:
            result["_id"] = str(result["_id"])
        return result
Ejemplo n.º 8
0
    async def request(self, method, uri, params=None, headers=None, body=None, auth=False):
        """ Do HTTP request.

        Args:
            method: HTTP request method. GET, POST, DELETE, PUT.
            uri: HTTP request uri.
            params: HTTP query params.
            headers: HTTP request header.
            body: HTTP request body.
            auth: If required signature.

        Returns:
            success: Success results, otherwise it's None.
            error: Error information, otherwise it's None.
        """
        url = urljoin(self._host, uri)
        if params:
            query = "&".join(["=".join([str(k), str(v)]) for k, v in params.items()])
            url += "?" + query
        else:
            query = ""
        if auth:
            signature = hmac.new(self._secret_key.encode(), query.encode(), hashlib.sha256).hexdigest()
            headers = {
                "ACCESS-TIMESTAMP": str(tools.get_cur_timestamp()),
                "ACCESS-KEY": self._access_key,
                "ACCESS-SIGN": signature
            }
        _, success, error = await AsyncHttpRequests.fetch(method, url, body=body, headers=headers, timeout=10)
        if error:
            return None, error
        if success.get("code") != 0:
            return None, success
        return success, None
Ejemplo n.º 9
0
 async def get_asset_snapshot(self,
                              platform,
                              account,
                              start=None,
                              end=None):
     """ 获取资产快照
     @param platform 交易平台
     @param account 账户
     @param start 开始时间戳(秒)
     @param end 结束时间戳(秒)
     """
     if not end:
         end = tools.get_cur_timestamp()  # 截止时间默认当前时间
     if not start:
         start = end - 60 * 60 * 24  # 开始时间默认一天前
     spec = {
         'platform': platform,
         'account': account,
         'create_time': {
             '$gte': start,
             '$lte': end
         }
     }
     fields = {'platform': 0, 'account': 0, 'update_time': 0}
     datas = await self.get_list(spec, fields=fields)
     return datas
Ejemplo n.º 10
0
    async def insert(self, docs, cursor=None):
        """ Insert (a) document(s).

        Args:
            docs: Dict or List to be inserted.
            cursor: DB cursor, default is `self._cursor`.

        Return:
            ret_ids: Document id(s) that already inserted, if insert a dict, `ret_ids` is a id string; if insert a list,
                `ret_ids` is a id list.
        """
        if not cursor:
            cursor = self._cursor
        docs_data = copy.deepcopy(docs)
        ret_ids = []
        is_one = False
        create_time = tools.get_cur_timestamp()
        if not isinstance(docs_data, list):
            docs_data = [docs_data]
            is_one = True
        for doc in docs_data:
            doc["_id"] = ObjectId()
            doc["create_time"] = create_time
            doc["update_time"] = create_time
            ret_ids.append(str(doc["_id"]))
        cursor.insert_many(docs_data)
        if is_one:
            return ret_ids[0]
        else:
            return ret_ids
Ejemplo n.º 11
0
    async def get_asset_snapshot(self,
                                 platform,
                                 account,
                                 start=None,
                                 end=None):
        """ Get asset snapshot data from db.

        Args:
            platform: Exchange platform name. e.g. binance/bitmex/okex
            account: Account name. e.g. [email protected]
            start: Start time, Millisecond timestamp, default is a day ago.
            end: End time, Millisecond timestamp, default is current timestamp.

        Returns:
            datas: Asset data list. e.g. [{"BTC": {"free": "1.1", "locked": "2.2", "total": "3.3"}, ... }, ... ]
        """
        if not end:
            end = tools.get_cur_timestamp()  # Current timestamp
        if not start:
            start = end - 60 * 60 * 24  # A day ago.
        spec = {
            "platform": platform,
            "account": account,
            "timestamp": {
                "$gte": start,
                "$lte": end
            }
        }
        fields = {"platform": 0, "account": 0, "update_time": 0}
        datas = await self._db.get_list(spec, fields=fields)
        return datas
Ejemplo n.º 12
0
 async def _update_heartbeat_msg(self, *args, **kwargs):
     """ Update heartbeat message to new request id.
     """
     self.heartbeat_msg = {
         "event": "ping",
         "reqid": tools.get_cur_timestamp()
     }
Ejemplo n.º 13
0
 async def request(self, uri, data):
     """ 发起请求
     """
     url = urljoin(self._host, uri)
     timestamp = tools.get_cur_timestamp()
     data["accesskey"] = self._access_key
     data["secretkey"] = self._secret_key
     data["timestamp"] = timestamp
     sign = "&".join(["{}={}".format(k, data[k]) for k in sorted(data.keys())])
     md5_str = hashlib.md5(sign.encode("utf8")).hexdigest()
     del data["secretkey"]
     del data["accesskey"]
     del data["timestamp"]
     body = {
         "common": {
             "accesskey": self._access_key,
             "timestamp": timestamp,
             "sign": md5_str
         },
         "data": data
     }
     trace_id = md5_str[:16]  # 16位的随机字符串
     headers = {
         "X-B3-Traceid": trace_id,
         "X-B3-Spanid": trace_id
     }
     _, success, error = await AsyncHttpRequests.fetch("POST", url, data=body, headers=headers, timeout=10)
     if error:
         return None, error
     if str(success.get("code")) != "1000":
         return None, success
     return success["data"]["result"], None
Ejemplo n.º 14
0
    async def update(self, spec, update_fields, upsert=False, multi=False, cursor=None):
        """ Update (a) document(s).

        Args:
            spec: Query params, optional. Specifies selection filter using query operators.
                To return all documents in a collection, omit this parameter or pass an empty document ({}).
            update_fields: Fields to be updated.
            upsert: If server this document if not exist? True or False.
            multi: Update multiple documents? True or False.
            cursor: Query cursor, default is `self._cursor`.

        Return:
            modified_count: How many documents has been modified.
        """
        if not cursor:
            cursor = self._cursor
        update_fields = copy.deepcopy(update_fields)
        spec[DELETE_FLAG] = {"$ne": True}
        if "_id" in spec:
            spec["_id"] = self._convert_id_object(spec["_id"])
        set_fields = update_fields.get("$set", {})
        set_fields["update_time"] = tools.get_cur_timestamp()
        update_fields["$set"] = set_fields
        if not multi:
            result = await cursor.update_one(spec, update_fields, upsert=upsert)
            return result.modified_count
        else:
            result = await cursor.update_many(spec, update_fields, upsert=upsert)
            return result.modified_count
Ejemplo n.º 15
0
 async def _check_connection(self, *args, **kwargs):
     """ 检查连接是否正常
     """
     now = tools.get_cur_timestamp()  #当前时间,单位:秒
     if self.last_timestamp > 0 and now - self.last_timestamp > self._check_conn_interval:  #最后接收数据包(包括pingpong包)时间间隔超过指定值
         if self.ws and not self.ws.closed:  #连接没有关闭
             await self.socket_close()  #关闭
Ejemplo n.º 16
0
 def encode(cls, user_id, username):
     info = {
         "user_id": user_id,
         "username": username,
         "timestamp": tools.get_cur_timestamp()
     }
     bdata = json.dumps(info).encode("ascii")
     token = base64.b64encode(bdata)
     return token.decode()
Ejemplo n.º 17
0
 async def connected_callback(self):
     """ 建立连接之后,鉴权、订阅频道
     """
     # 身份验证
     expires = tools.get_cur_timestamp() + 5
     signature = self._rest_api.generate_signature("GET", "/realtime", expires, None)
     data = {
         "op": "authKeyExpires",
         "args": [self._access_key, expires, signature]
     }
     await self.ws.send_json(data)
Ejemplo n.º 18
0
    def __init__(self, **kwargs):
        self._platform = kwargs["platform"]
        self._wss = kwargs.get("wss", "wss://hermes.deribit.com")
        self._symbols = list(set(kwargs.get("symbols")))
        self._channels = kwargs.get("channels")
        self._access_key = kwargs.get("access_key")
        self._secret_key = kwargs.get("secret_key")
        self._last_msg_ts = tools.get_cur_timestamp()  # 上次接收到消息的时间戳

        url = self._wss + "/ws/api/v1/"
        super(Deribit, self).__init__(url)
        self.heartbeat_msg = {"action": "/api/v1/public/ping"}
        self.initialize()
Ejemplo n.º 19
0
    def __init__(self):
        self._platform = DERIBIT
        self._url = config.platforms.get(self._platform).get("wss")
        self._symbols = list(
            set(config.platforms.get(self._platform).get("symbols")))
        self._access_key = config.platforms.get(
            self._platform).get("access_key")
        self._secret_key = config.platforms.get(
            self._platform).get("secret_key")
        self._last_msg_ts = tools.get_cur_timestamp()  # 上次接收到消息的时间戳

        super(Deribit, self).__init__(self._url)
        self.heartbeat_msg = {"action": "/api/v1/public/ping"}
        self.initialize()
Ejemplo n.º 20
0
 async def request(self, method, uri, params=None, body=None):
     """ 发起请求
     """
     if params:
         query = "&".join(["{}={}".format(k, params[k]) for k in sorted(params.keys())])
         url = uri + "?" + query
     else:
         url = uri
     ts = tools.get_cur_timestamp() + 5
     signature = self.generate_signature(method, url, ts, body)
     headers = {
         "api-expires": str(ts),
         "api-key": self.access_key,
         "api-signature": signature
     }
     url = urljoin(self.host, uri)
     _, success, error = await AsyncHttpRequests.fetch(method, url, headers=headers, data=body, timeout=10)
     return success, error
Ejemplo n.º 21
0
async def auth_middleware(request, handler):
    """ Authentication middleware.
    """
    ext_uri = config.http_server.get("ext_uri", [])
    if request.path not in ext_uri:
        token = request.headers.get("Token")
        if not token:
            token = request.query.get("Token")
            if not token:
                raise exceptions.AuthenticationFailed(msg="Token miss.")
        try:
            user_id, username, timestamp = AuthToken.decode(token)
        except:
            raise exceptions.AuthenticationFailed(msg="Token error.")
        if tools.get_cur_timestamp() - timestamp > 60 * 60 * 24:  # expire time.
            raise exceptions.AuthenticationFailed(msg="Token expired.")
        request.user_id = user_id
    response = await handler(request)
    return response
Ejemplo n.º 22
0
    async def request(self, uri, data):
        """ Do HTTP request.

        Args:
            uri: HTTP request uri.
            data:   HTTP request body.

        Returns:
            success: Success results, otherwise it's None.
            error: Error information, otherwise it's None.
        """
        url = urljoin(self._host, uri)
        timestamp = tools.get_cur_timestamp()
        data["accesskey"] = self._access_key
        data["secretkey"] = self._secret_key
        data["timestamp"] = timestamp
        sign = "&".join(
            ["{}={}".format(k, data[k]) for k in sorted(data.keys())])
        md5_str = hashlib.md5(sign.encode("utf8")).hexdigest()
        del data["secretkey"]
        del data["accesskey"]
        del data["timestamp"]
        body = {
            "common": {
                "accesskey": self._access_key,
                "timestamp": timestamp,
                "sign": md5_str
            },
            "data": data
        }
        trace_id = md5_str[:16]  # A 16th length of random string.
        headers = {"X-B3-Traceid": trace_id, "X-B3-Spanid": trace_id}
        _, success, error = await AsyncHttpRequests.fetch("POST",
                                                          url,
                                                          data=body,
                                                          headers=headers,
                                                          timeout=10)
        if error:
            return None, error
        if str(success.get("code")) != "1000":
            return None, success
        return success["data"]["result"], None
Ejemplo n.º 23
0
 async def receive(self):
     """ 接收消息
     """
     async for msg in self.ws:
         self._last_receive_ts = 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))
         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())
             return
         elif msg.type == aiohttp.WSMsgType.ERROR:
             logger.error('receive event ERROR:', msg, caller=self)
         else:
             logger.warn('unhandled msg:', msg, caller=self)
Ejemplo n.º 24
0
    async def connected_callback(self):
        """ 建立连接之后,订阅事件 ticker/deals
        """
        # 身份验证
        expires = tools.get_cur_timestamp() + 5
        signature = self._rest_api.generate_signature("GET", "/realtime", expires, None)
        data = {
            "op": "authKeyExpires",
            "args": [self._access_key, expires, signature]
        }
        await self.ws.send_json(data)
        logger.info("Websocket connection authorized successfully.", caller=self)

        # 订阅order和position
        ch_order = "order:{symbol}".format(symbol=self._symbol)
        ch_position = "position:{symbol}".format(symbol=self._symbol)
        data = {
            "op": "subscribe",
            "args": [ch_order, ch_position]
        }
        await self.ws.send_json(data)
        logger.info("subscribe account/order/position successfully.", caller=self)
Ejemplo n.º 25
0
 async def send_heartbeat_msg(self, *args, **kwargs):
     data = {"event": "ping", "reqid": tools.get_cur_timestamp()}
     if not self._ws:
         logger.error("Websocket connection not yeah!", caller=self)
         return
     await self._ws.send(data)