Пример #1
0
 async def _connect(self):
     logger.info("url:", self._url, caller=self)
     proxy = config.proxy
     if not self.session:
         self.session = aiohttp.ClientSession()
     try:
         self._ws = await self.session.ws_connect(self._url, proxy=proxy)
     except (aiohttp.client_exceptions.ClientConnectorError,
             aiohttp.client_exceptions.ClientHttpProxyError,
             aiohttp.client_exceptions.ServerDisconnectedError,
             aiohttp.client_exceptions.WSServerHandshakeError,
             asyncio.TimeoutError) as e:
         logger.error("connect to server error! url:",
                      self._url,
                      caller=self)
         state = State(
             self._platform, self._account,
             "connect to server error! url: {}, error: {}".format(
                 self._url, e), State.STATE_CODE_CONNECT_FAILED)
         SingleTask.run(self.cb.on_state_update_callback, state)
         asyncio.get_event_loop().create_task(
             self._reconnect())  #如果连接出错就重新连接
         return
     state = State(self._platform, self._account,
                   "connect to server success! url: {}".format(self._url),
                   State.STATE_CODE_CONNECT_SUCCESS)
     SingleTask.run(self.cb.on_state_update_callback, state)
     asyncio.get_event_loop().create_task(self.connected_callback())
     asyncio.get_event_loop().create_task(self.receive())
Пример #2
0
 async def _task():
     if indicate_type == INDICATE_ORDER and self.cb.on_order_update_callback:
         success, error = await self.get_orders(symbol)
         if error:
             state = State(self._platform, self._account,
                           "get_orders error: {}".format(error),
                           State.STATE_CODE_GENERAL_ERROR)
             SingleTask.run(self.cb.on_state_update_callback, state)
             return
         for order in success:
             SingleTask.run(self.cb.on_order_update_callback, order)
     elif indicate_type == INDICATE_ASSET and self.cb.on_asset_update_callback:
         success, error = await self.get_assets()
         if error:
             state = State(self._platform, self._account,
                           "get_assets error: {}".format(error),
                           State.STATE_CODE_GENERAL_ERROR)
             SingleTask.run(self.cb.on_state_update_callback, state)
             return
         SingleTask.run(self.cb.on_asset_update_callback, success)
     elif indicate_type == INDICATE_POSITION and self.cb.on_position_update_callback:
         success, error = await self.get_position(symbol)
         if error:
             state = State(self._platform, self._account,
                           "get_position error: {}".format(error),
                           State.STATE_CODE_GENERAL_ERROR)
             SingleTask.run(self.cb.on_state_update_callback, state)
             return
         SingleTask.run(self.cb.on_position_update_callback, success)
Пример #3
0
 async def launch(self):
     """ 模拟交易接口连接初始化成功
     """
     state = State(self._platform, self._account, "connect to server success", State.STATE_CODE_CONNECT_SUCCESS)
     await self.cb.on_state_update_callback(state)
     await self.init_asset()
     state = State(self._platform, self._account, "Environment ready", State.STATE_CODE_READY)
     await self.cb.on_state_update_callback(state)
Пример #4
0
    async def process(self, msg):
        """ Process message that received from websocket.

        Args:
            msg: message received from websocket.

        Returns:
            None.
        """
        if not isinstance(msg, dict):
            return
        logger.debug("msg:", json.dumps(msg), caller=self)
        #{"type": "error", "code": 400, "msg": "Invalid login credentials"}
        if msg["type"] == "error":
            state = State(self._platform, self._account,
                          "Websocket connection failed: {}".format(msg),
                          State.STATE_CODE_GENERAL_ERROR)
            logger.error(state, caller=self)
            SingleTask.run(self.cb.on_state_update_callback, state)
        elif msg["type"] == "pong":
            return
        elif msg["type"] == "info":
            if msg["code"] == 20001:
                #交易所重启了,我们就断开连接,websocket会自动重连
                @async_method_locker("FTXTrader._ws_close.locker")
                async def _ws_close():
                    await self.socket_close()

                SingleTask.run(_ws_close)
        elif msg["type"] == "unsubscribed":
            return
        #{'type': 'subscribed', 'channel': 'trades', 'market': 'BTC-PERP'}
        elif msg["type"] == "subscribed":
            self._subscribe_response_count = self._subscribe_response_count + 1  #每来一次订阅响应计数就加一
            if self._subscribe_response_count == 2:  #所有的订阅都成功了,通知上层接口都准备好了
                state = State(self._platform, self._account,
                              "Environment ready", State.STATE_CODE_READY)
                SingleTask.run(self.cb.on_state_update_callback, state)
        elif msg["type"] == "update":
            channel = msg['channel']
            if channel == 'orders':
                self._update_order(msg)
            elif channel == 'fills':
                self._update_fill(msg)
Пример #5
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())
Пример #6
0
    def __init__(self, **kwargs):
        """Initialize."""
        self.cb = kwargs["cb"]

        self._platform = kwargs.get("databind")
        self._symbols = kwargs.get("symbols")
        self._strategy = kwargs.get("strategy")
        self._account = kwargs.get("account")

        state = None
        if not self._platform:
            state = State(self._platform, self._account, "param platform miss")
        elif not self._symbols:
            state = State(self._platform, self._account, "param symbols miss")
        elif not self._strategy:
            state = State(self._platform, self._account, "param strategy miss")
        if state:
            logger.error(state, caller=self)
            return

        super(VirtualTrader, self).__init__(**kwargs)
Пример #7
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()
Пример #8
0
 async def _check_connection(cls, *args, **kwargs):
     try:
         ns = await cls._mongo_client.list_database_names()
         if ns and isinstance(ns, list) and "admin" in ns:
             cls._connected = True
     except Exception as e:
         cls._connected = False
         logger.error("mongodb connection ERROR:", e)
     finally:
         SingleTask.call_later(cls._check_connection, 2)  #开启下一轮检测
         #数据库连接状态通知上层策略
         if cls._last_state != cls.is_connected():  #状态发生变化
             cls._last_state = cls.is_connected()
             if cls._last_state:
                 state = State(None, None, "mongodb connection SUCCESS",
                               State.STATE_CODE_DB_SUCCESS)
             else:
                 state = State(None, None, "mongodb connection ERROR",
                               State.STATE_CODE_DB_ERROR)
             for cb in cls._state_cbs:
                 SingleTask.run(cb, state)
Пример #9
0
    def __init__(self, **kwargs):
        """Initialize."""
        self.cb = kwargs["cb"]

        self._platform = kwargs.get("databind")
        self._symbols = kwargs.get("symbols")
        self._strategy = kwargs.get("strategy")
        self._account = kwargs.get("account")

        state = None
        if not self._platform:
            state = State(self._platform, self._account, "param platform miss")
        elif not self._symbols:
            state = State(self._platform, self._account, "param symbols miss")
        elif not self._strategy:
            state = State(self._platform, self._account, "param strategy miss")
        if state:
            logger.error(state, caller=self)
            return

        #资产列表
        self._assets: DefaultDict[str: Dict[str, float]] = defaultdict(lambda: {k: 0.0 for k in {'free', 'locked', 'total'}})

        #替换k线回调函数(K线方式驱动回测引擎)
        self._original_on_kline_update_callback = self.cb.on_kline_update_callback
        self.cb.on_kline_update_callback = self.on_kline_update_callback

        #替换订单簿回调函数(订单薄方式驱动回测引擎)
        self._original_on_orderbook_update_callback = self.cb.on_orderbook_update_callback
        self.cb.on_orderbook_update_callback = self.on_orderbook_update_callback

        #替换市场成交回调函数(市场成交方式驱动回测引擎)
        self._original_on_trade_update_callback = self.cb.on_trade_update_callback
        self.cb.on_trade_update_callback = self.on_trade_update_callback

        #为每个交易对绑定回测撮合引擎
        self.bind_match_engine(**kwargs)

        super(BacktestTrader, self).__init__(**kwargs)
Пример #10
0
    async def process(self, msg):
        """ Process message that received from websocket.

        Args:
            msg: message received from websocket.

        Returns:
            None.
        """
        if not isinstance(msg, dict):
            return
        logger.debug("msg:", json.dumps(msg), caller=self)

        #{"type": "pong"}
        if msg.get("type") == "pong":
            return
        #{"type": "error", "code": 400, "msg": "Invalid login credentials"}
        elif msg["type"] == "error":
            state = State(self._platform, self._account,
                          "Websocket connection failed: {}".format(msg),
                          State.STATE_CODE_GENERAL_ERROR)
            logger.error(state, caller=self)
            SingleTask.run(self.cb.on_state_update_callback, state)
        elif msg["type"] == "info":
            if msg["code"] == 20001:
                #交易所重启了,我们就断开连接,websocket会自动重连
                @async_method_locker("FTXMarket._ws_close.locker")
                async def _ws_close():
                    await self.socket_close()

                SingleTask.run(_ws_close)
        elif msg["type"] == "unsubscribed":
            return
        #{'type': 'subscribed', 'channel': 'trades', 'market': 'BTC-PERP'}
        elif msg["type"] == "subscribed":
            return
        elif msg["type"] == "update" or msg["type"] == "partial":
            channel = msg['channel']
            if channel == 'orderbook':
                self._update_orderbook(msg)
            elif channel == 'trades':
                self._update_trades(msg)
            elif channel == 'ticker':
                self._update_ticker(msg)
Пример #11
0
    async def process_binary(self, raw):
        """ Process binary message that received from websocket.

        Args:
            raw: Binary message received from websocket.

        Returns:
            None.
        """
        decompress = zlib.decompressobj(-zlib.MAX_WBITS)
        msg = decompress.decompress(raw)
        msg += decompress.flush()
        msg = msg.decode()
        if msg == "pong":
            return
        logger.debug("msg:", msg, caller=self)
        msg = json.loads(msg)

        # Authorization message received.
        if msg.get("event") == "login":
            if not msg.get("success"):
                state = State(
                    self._platform, self._account,
                    "Websocket connection authorized failed: {}".format(msg),
                    State.STATE_CODE_GENERAL_ERROR)
                logger.error(state, caller=self)
                SingleTask.run(self.cb.on_state_update_callback, state)
                return
            logger.info("Websocket connection authorized successfully.",
                        caller=self)
            await self._auth_success_callback()

        # Subscribe response message received.
        elif msg.get("event") == "subscribe":
            #msg.get("channel")
            self._subscribe_response_count = self._subscribe_response_count + 1  #每来一次订阅响应计数就加一
            count = len(self._account_channel) + len(
                self._order_channel)  #应该要返回的订阅响应数
            if self._subscribe_response_count == count:  #所有的订阅都成功了,通知上层接口都准备好了
                state = State(self._platform, self._account,
                              "Environment ready", State.STATE_CODE_READY)
                SingleTask.run(self.cb.on_state_update_callback, state)

        elif msg.get("event") == "error":
            state = State(self._platform, self._account,
                          "Websocket processing failed: {}".format(msg),
                          State.STATE_CODE_GENERAL_ERROR)
            SingleTask.run(self.cb.on_state_update_callback, state)

        # Order update message received.
        elif msg.get("table") == "spot/order":
            """
            {
            "table":"spot/order",
            "data":[
                {
                "client_oid":"",
                "filled_notional":"0",
                "filled_size":"0",
                "instrument_id":"ETC-USDT",
                "last_fill_px":"0",
                "last_fill_qty":"0",
                "last_fill_time":"1970-01-01T00:00:00.000Z",
                "margin_trading":"1",
                "notional":"",
                "order_id":"3576398568830976",
                "order_type":"0",
                "price":"5.826",
                "side":"buy",
                "size":"0.1",
                "state":"0",
                "status":"open",
                "timestamp":"2019-09-24T06:45:11.394Z",
                "type":"limit",
                "created_at":"2019-09-24T06:45:11.394Z"
                }
                ]
            }
            """
            for data in msg["data"]:
                self._update_order(data)

        elif msg.get("table") == "spot/account":
            self._update_asset(msg["data"])
Пример #12
0
    async def _auth_success_callback(self):
        """ 授权成功之后回调
        """
        #获取相关符号信息
        """
        [
        {
            "base_currency":"BTC",
            "instrument_id":"BTC-USDT",
            "min_size":"0.001",
            "quote_currency":"USDT",
            "size_increment":"0.00000001",
            "tick_size":"0.1"
        },
        {
            "base_currency":"OKB",
            "instrument_id":"OKB-USDT",
            "min_size":"1",
            "quote_currency":"USDT",
            "size_increment":"0.0001",
            "tick_size":"0.0001"
        }
        ]
        """
        success, error = await self._rest_api.get_symbols_info()
        if error:
            state = State(self._platform, self._account,
                          "get_symbols_info error: {}".format(error),
                          State.STATE_CODE_GENERAL_ERROR)
            SingleTask.run(self.cb.on_state_update_callback, state)
            #初始化过程中发生错误,关闭网络连接,触发重连机制
            await self.socket_close()
            return
        for info in success:
            self._syminfo[info[
                "instrument_id"]] = info  #符号信息一般不变,获取一次保存好,其他地方要用直接从这个变量获取就可以了

        #获取账户余额,更新资产
        """
        [
        {
            "frozen":"0",
            "hold":"0",
            "id": "",
            "currency":"BTC",
            "balance":"0.0049925",
            "available":"0.0049925",
            "holds":"0"
        },
        {
            "frozen":"0",
            "hold":"0",
            "id": "",
            "currency":"USDT",
            "balance":"226.74061435",
            "available":"226.74061435",
            "holds":"0"
        },
        {
            "frozen":"0",
            "hold":"0",
            "id": "",
            "currency":"EOS",
            "balance":"0.4925",
            "available":"0.4925",
            "holds":"0"
        }
        ]
        """
        success, error = await self._rest_api.get_account_balance()
        if error:
            state = State(self._platform, self._account,
                          "get_account_balance error: {}".format(error),
                          State.STATE_CODE_GENERAL_ERROR)
            SingleTask.run(self.cb.on_state_update_callback, state)
            #初始化过程中发生错误,关闭网络连接,触发重连机制
            await self.socket_close()
            return
        self._update_asset(success)

        # Fetch orders from server. (open + partially filled)
        for sym in self._symbols:
            """
            [
            {
                "client_oid":"oktspot86",
                "created_at":"2019-03-20T03:28:14.000Z",
                "filled_notional":"0",
                "filled_size":"0",
                "funds":"",
                "instrument_id":"BTC-USDT",
                "notional":"",
                "order_id":"2511109744100352",
                "order_type":"0",
                "price":"3594.7",
                "price_avg":"",
                "product_id":"BTC-USDT",
                "side":"buy",
                "size":"0.001",
                "status":"open",
                "state":"0",
                "timestamp":"2019-03-20T03:28:14.000Z",
                "type":"limit"
            }
            ]
            """
            success, error = await self._rest_api.get_open_orders(sym)
            if error:
                state = State(self._platform, self._account,
                              "get open orders error: {}".format(error),
                              State.STATE_CODE_GENERAL_ERROR)
                SingleTask.run(self.cb.on_state_update_callback, state)
                #初始化过程中发生错误,关闭网络连接,触发重连机制
                await self.socket_close()
                return
            for order_info in success:
                self._update_order(order_info)

        # Subscribe order channel.
        if self.cb.on_order_update_callback or self.cb.on_fill_update_callback:
            data = {"op": "subscribe", "args": self._order_channel}
            await self.send_json(data)

        #订阅账户余额通知
        if self.cb.on_asset_update_callback:
            sl = []
            for sym in self._symbols:
                si = self._syminfo[sym]
                if si:
                    sl.append(si["base_currency"])
                    sl.append(si["quote_currency"])
            #set的目的是去重
            self._account_channel = []
            for s in set(sl):
                self._account_channel.append(
                    "spot/account:{symbol}".format(symbol=s))
            #发送订阅
            data = {"op": "subscribe", "args": self._account_channel}
            await self.send_json(data)

        #计数初始化0
        self._subscribe_response_count = 0
Пример #13
0
    def __init__(self, **kwargs):
        """Initialize."""
        self.cb = kwargs["cb"]
        state = None

        self._platform = kwargs.get("platform")
        self._symbols = kwargs.get("symbols")
        self._strategy = kwargs.get("strategy")
        self._account = kwargs.get("account")
        self._access_key = kwargs.get("access_key")
        self._secret_key = kwargs.get("secret_key")
        self._passphrase = kwargs.get("passphrase")

        if not self._platform:
            state = State(self._platform, self._account, "param platform miss")
        elif self._account and (not self._access_key or not self._secret_key
                                or not self._passphrase):
            state = State(self._platform, self._account,
                          "param access_key or secret_key or passphrase miss")
        elif not self._strategy:
            state = State(self._platform, self._account, "param strategy miss")
        elif not self._symbols:
            state = State(self._platform, self._account, "param symbols miss")

        if state:
            logger.error(state, caller=self)
            SingleTask.run(self.cb.on_state_update_callback, state)
            return

        self._host = "https://www.okex.com"
        self._wss = "wss://real.okex.com:8443"

        self._order_channel = []
        for sym in self._symbols:
            self._order_channel.append(
                "spot/order:{symbol}".format(symbol=sym))

        url = self._wss + "/ws/v3"
        super(OKExTrader, self).__init__(url, send_hb_interval=5, **kwargs)
        self.heartbeat_msg = "ping"

        self._syminfo: DefaultDict[str:Dict[str, Any]] = defaultdict(dict)

        self._assets: DefaultDict[str:Dict[str, float]] = defaultdict(
            lambda: {k: 0.0
                     for k in {'free', 'locked', 'total'}})

        # Initializing our REST API client.
        self._rest_api = OKExRestAPI(self._host, self._access_key,
                                     self._secret_key, self._passphrase)

        if self._account != None:
            self.initialize()

        #如果四个行情回调函数都为空的话,就根本不需要执行市场行情相关代码
        if (self.cb.on_kline_update_callback
                or self.cb.on_orderbook_update_callback
                or self.cb.on_trade_update_callback
                or self.cb.on_ticker_update_callback):
            #市场行情数据
            OKExMarket(**kwargs)
Пример #14
0
 def __init__(self, **kwargs):
     """initialize trader object.
     
     Args:
         strategy: 策略名称,由哪个策略发起
         platform: 交易平台
         databind: 这个字段只有在platform等于datamatrix或backtest的时候才有用,代表为矩阵操作或策略回测提供历史数据的交易所
         symbols: 策略需要订阅和交易的符号
         account: 交易所登陆账号,如果为空就只是订阅市场公共行情数据,不进行登录认证,所以也无法进行交易等
         access_key: 登录令牌
         secret_key: 令牌密钥
         cb: ExchangeGateway.ICallBack {
             on_state_update_callback: `状态变化`(底层交易所接口,框架等)通知回调函数
             on_kline_update_callback: `K线数据`通知回调函数 (值为None就不启用此通知回调)
             on_orderbook_update_callback: `订单簿深度数据`通知回调函数 (值为None就不启用此通知回调)
             on_trade_update_callback: `市场最新成交`通知回调函数 (值为None就不启用此通知回调)
             on_ticker_update_callback: `市场行情tick`通知回调函数 (值为None就不启用此通知回调)
             on_order_update_callback: `用户挂单`通知回调函数 (值为None就不启用此通知回调)
             on_fill_update_callback: `用户挂单成交`通知回调函数 (值为None就不启用此通知回调)
             on_position_update_callback: `用户持仓`通知回调函数 (值为None就不启用此通知回调)
             on_asset_update_callback: `用户资产`通知回调函数 (值为None就不启用此通知回调)
         }
     """
     T = gateway_class(kwargs["platform"])  #找到指定的交易接口类
     if T == None:
         logger.error("platform not found:",
                      kwargs["platform"],
                      caller=self)
         cb = kwargs["cb"]
         SingleTask.run(
             cb.on_state_update_callback,
             State(kwargs["platform"], kwargs.get("account"),
                   "platform not found"))
         return
     #------------------------------------------------
     #符号映射转换相关
     self.is_upper = False  #币种符号是否转换成大写
     self.system_to_native = {}  #'量化平台通用交易符号'转换成'交易所原始符号'
     self.native_to_system = {}  #'交易所原始符号'转换成'量化平台通用交易符号'
     layer = T.mapping_layer()  #从交易所获取符号转换层信息
     if layer:
         self.system_to_native = layer.map_dict  #'交易对'符号映射信息,类似 BTC/USDT -> btcusdt
         self.is_upper = layer.is_upper  #'币种'符号是否大写,类似 btc -> BTC
         for (k, v) in self.system_to_native.items(
         ):  #生成逆转换映射信息,类似 btcusdt -> BTC/USDT
             self.native_to_system[v] = k
     #符号转换
     if self.system_to_native:  #存在映射信息,意味着启用了符号转换功能
         native_symbol = []
         for sym in kwargs["symbols"]:
             if not self.system_to_native.get(sym):  #如果符号映射信息中没有,返回错误
                 logger.error("symbols not found:",
                              kwargs["symbols"],
                              caller=self)
                 cb = kwargs["cb"]
                 SingleTask.run(
                     cb.on_state_update_callback,
                     State(kwargs["platform"], kwargs.get("account"),
                           "symbols not found"))
                 return
             native_symbol.append(self.system_to_native[sym])
         kwargs["symbols"] = native_symbol
     #映射功能启用就需要hook回调函数
     if self.system_to_native or self.is_upper:
         self.hookCB(kwargs["cb"])
     #
     self._t = T(**kwargs)
Пример #15
0
    async def connected_callback(self):
        """网络链接成功回调
        """
        if self._account != None:
            #账号不为空就要进行登录认证,然后订阅2个需要登录后才能订阅的私有频道:用户挂单通知和挂单成交通知(FTX只支持这2个私有频道)
            await self._login()  #登录认证

            success, error = await self._rest_api.list_markets()
            if error:
                state = State(self._platform, self._account,
                              "list_markets error: {}".format(error),
                              State.STATE_CODE_GENERAL_ERROR)
                SingleTask.run(self.cb.on_state_update_callback, state)
                #初始化过程中发生错误,关闭网络连接,触发重连机制
                await self.socket_close()
                return
            for info in success["result"]:
                self._syminfo[
                    info["name"]] = info  #符号信息一般不变,获取一次保存好,其他地方要用直接从这个变量获取就可以了

            if self.cb.on_order_update_callback != None:
                for sym in self._symbols:
                    orders, error = await self.get_orders(sym)
                    if error:
                        state = State(self._platform, self._account,
                                      "get_orders error: {}".format(error),
                                      State.STATE_CODE_GENERAL_ERROR)
                        SingleTask.run(self.cb.on_state_update_callback, state)
                        #初始化过程中发生错误,关闭网络连接,触发重连机制
                        await self.socket_close()
                        return
                    for o in orders:
                        SingleTask.run(self.cb.on_order_update_callback, o)

            if self.cb.on_position_update_callback != None:
                for sym in self._symbols:
                    pos, error = await self.get_position(sym)
                    if error:
                        state = State(self._platform, self._account,
                                      "get_position error: {}".format(error),
                                      State.STATE_CODE_GENERAL_ERROR)
                        SingleTask.run(self.cb.on_state_update_callback, state)
                        #初始化过程中发生错误,关闭网络连接,触发重连机制
                        await self.socket_close()
                        return
                    SingleTask.run(self.cb.on_position_update_callback, pos)

            if self.cb.on_asset_update_callback != None:
                ast, error = await self.get_assets()
                if error:
                    state = State(self._platform, self._account,
                                  "get_assets error: {}".format(error),
                                  State.STATE_CODE_GENERAL_ERROR)
                    SingleTask.run(self.cb.on_state_update_callback, state)
                    #初始化过程中发生错误,关闭网络连接,触发重连机制
                    await self.socket_close()
                    return
                SingleTask.run(self.cb.on_asset_update_callback, ast)

            #`用户挂单通知回调`不为空,就进行订阅
            if self.cb.on_order_update_callback != None:
                await self.send_json({'op': 'subscribe', 'channel': 'orders'})
            #`用户挂单成交通知回调`不为空,就进行订阅
            if self.cb.on_fill_update_callback != None:
                await self.send_json({'op': 'subscribe', 'channel': 'fills'})

            #计数初始化0
            self._subscribe_response_count = 0
Пример #16
0
    def __init__(self, **kwargs):
        """Initialize."""
        self.cb = kwargs["cb"]
        state = None

        self._platform = kwargs.get("platform")
        self._symbols = kwargs.get("symbols")
        self._strategy = kwargs.get("strategy")
        self._account = kwargs.get("account")
        self._access_key = kwargs.get("access_key")
        self._secret_key = kwargs.get("secret_key")
        self._subaccount_name = kwargs.get("subaccount_name")

        if not self._platform:
            state = State(self._platform, self._account, "param platform miss")
        elif self._account and (not self._access_key or not self._secret_key):
            state = State(self._platform, self._account,
                          "param access_key or secret_key miss")
        elif not self._strategy:
            state = State(self._platform, self._account, "param strategy miss")
        elif not self._symbols:
            state = State(self._platform, self._account, "param symbols miss")

        if state:
            logger.error(state, caller=self)
            SingleTask.run(self.cb.on_state_update_callback, state)
            return

        self._host = "https://ftx.com"
        self._wss = "wss://ftx.com"

        url = self._wss + "/ws"
        super(FTXTrader, self).__init__(url, send_hb_interval=15, **kwargs)
        self.heartbeat_msg = {"op": "ping"}

        # Initializing our REST API client.
        self._rest_api = FTXRestAPI(self._host, self._access_key,
                                    self._secret_key, self._subaccount_name)

        #订单簿深度数据
        self._orderbooks: DefaultDict[str, Dict[str, DefaultDict[
            float, float]]] = defaultdict(
                lambda:
                {side: defaultdict(float)
                 for side in {'bids', 'asks'}})

        self._assets: DefaultDict[str:Dict[str, float]] = defaultdict(
            lambda: {k: 0.0
                     for k in {'free', 'locked', 'total'}})

        self._syminfo: DefaultDict[str:Dict[str, Any]] = defaultdict(dict)

        if self._account != None:
            self.initialize()

        #如果四个行情回调函数都为空的话,就根本不需要执行市场行情相关代码
        if (self.cb.on_kline_update_callback
                or self.cb.on_orderbook_update_callback
                or self.cb.on_trade_update_callback
                or self.cb.on_ticker_update_callback):
            #市场行情数据
            FTXMarket(**kwargs)