Esempio n. 1
0
    def connect(
        self
    ) -> List[Tuple[AsyncConnection, Callable[[None], None], Callable[
        [str, float], None]]]:
        ret = []

        for chan in self.subscription:
            chan = self.exchange_channel_to_std(chan)
            if self.is_authenticated_channel(chan):
                LOG.info(f'{self.id}: {chan} will be authenticated')
                if chan == ORDER_INFO:
                    ret.append(
                        (WSAsyncConn(self.address['trading'], self.id,
                                     **self.ws_defaults), self.subscribe,
                         self.message_handler, self.authenticate))
                if chan in [BALANCES, TRANSACTIONS]:
                    ret.append(
                        (WSAsyncConn(self.address['account'], self.id,
                                     **self.ws_defaults), self.subscribe,
                         self.message_handler, self.authenticate))
            else:
                ret.append((WSAsyncConn(self.address['market'], self.id,
                                        **self.ws_defaults), self.subscribe,
                            self.message_handler, self.authenticate))
        return ret
Esempio n. 2
0
    def connect(
        self
    ) -> List[Tuple[AsyncConnection, Callable[[None], None], Callable[
        [str, float], None]]]:
        """
        Generic connection method for exchanges. Exchanges that require/support
        multiple addresses will need to override this method in their specific class
        unless they use the same subscribe method and message handler for all
        connections.

        Connect returns a list of tuples. Each tuple contains
        1. an AsyncConnection object
        2. the subscribe function pointer associated with this connection
        3. the message handler for this connection
        """
        channels_id = '|'.join(list(self.channels))
        symbols_id = '|'.join(list(self.symbols))
        conn_id = '-'.join([channels_id, self.id, symbols_id])

        ret = []
        if isinstance(self.address, str):
            return [(WSAsyncConn(self.address, conn_id, **self.ws_defaults),
                     self.subscribe, self.message_handler)]

        for _, addr in self.address.items():
            ret.append((WSAsyncConn(addr, conn_id, **self.ws_defaults),
                        self.subscribe, self.message_handler))
        return ret
Esempio n. 3
0
        def limit_sub(subscription: dict, limit: int, auth, options: dict):
            ret = []
            sub = {}
            for channel in subscription:
                for pair in subscription[channel]:
                    if channel not in sub:
                        sub[channel] = []
                    sub[channel].append(pair)
                    if sum(map(len, sub.values())) == limit:
                        ret.append((WSAsyncConn(addr,
                                                self.id,
                                                authentication=auth,
                                                subscription=sub,
                                                **options), self.subscribe,
                                    self.message_handler, self.authenticate))
                        sub = {}

            if sum(map(len, sub.values())) > 0:
                ret.append((WSAsyncConn(addr,
                                        self.id,
                                        authentication=auth,
                                        subscription=sub,
                                        **options), self.subscribe,
                            self.message_handler, self.authenticate))
            return ret
Esempio n. 4
0
    def connect(self) -> List[Tuple[AsyncConnection, Callable[[None], None], Callable[[str, float], None]]]:
        ret = []
        for channel in self.subscription:
            if is_authenticated_channel(channel):
                for s in self.subscription[channel]:
                    ret.append((WSAsyncConn(self.address, self.id, **self.ws_defaults), partial(self.user_order_subscribe, symbol=s), self.message_handler, self.authenticate))
            else:
                ret.append((WSAsyncConn(self.address, self.id, **self.ws_defaults), self.subscribe, self.message_handler, self.authenticate))

        return ret
Esempio n. 5
0
 def _connect_builder(self, address: str, options: list, header=None, sub=None, handler=None):
     """
     Helper method for building a custom connect tuple
     """
     subscribe = partial(self.subscribe if not sub else sub, options=options)
     conn = WSAsyncConn(address, self.id, extra_headers=header, **self.ws_defaults)
     return conn, subscribe, handler if handler else self.message_handler
Esempio n. 6
0
    def connect(
        self
    ) -> List[Tuple[AsyncConnection, Callable[[None], None], Callable[
        [str, float], None]]]:
        ret = []

        if any(pair[-4:] == 'USDT' for pair in self.normalized_symbols):
            subscribe = partial(self.subscribe, quote='USDT')
            ret.append((WSAsyncConn(self.address['USDT'], self.id,
                                    **self.ws_defaults), subscribe,
                        self.message_handler))
        if any(pair[-3:] == 'USD' for pair in self.normalized_symbols):
            subscribe = partial(self.subscribe, quote='USD')
            ret.append((WSAsyncConn(self.address['USD'], self.id,
                                    **self.ws_defaults), subscribe,
                        self.message_handler))

        return ret
Esempio n. 7
0
    def connect(self) -> List[Tuple[AsyncConnection, Callable[[None], None], Callable[[str, float], None]]]:
        """
        Generic websocket connection method for exchanges. Uses the websocket endpoints defined in the
        exchange to determine, based on the subscription information, which endpoints should be used,
        and what instruments/channels should be enabled on each connection.

        Connect returns a list of tuples. Each tuple contains
        1. an AsyncConnection object
        2. the subscribe function pointer associated with this connection
        3. the message handler for this connection
        4. The authentication method for this connection
        """
        def limit_sub(subscription: dict, limit: int, auth, options: dict):
            ret = []
            sub = {}
            for channel in subscription:
                for pair in subscription[channel]:
                    if channel not in sub:
                        sub[channel] = []
                    sub[channel].append(pair)
                    if sum(map(len, sub.values())) == limit:
                        ret.append((WSAsyncConn(addr, self.id, authentication=auth, subscription=sub, **options), self.subscribe, self.message_handler, self.authenticate))
                        sub = {}

            if sum(map(len, sub.values())) > 0:
                ret.append((WSAsyncConn(addr, self.id, authentication=auth, subscription=sub, **options), self.subscribe, self.message_handler, self.authenticate))
            return ret

        ret = self._connect_rest()
        for endpoint in self.websocket_endpoints:
            auth = None
            if endpoint.authentication:
                # if a class has an endpoint with the authentication flag set to true, this
                # method must be define. The method will be called immediately before connecting
                # to authenticate the connection. _ws_authentication returns a tuple of address and ws options
                auth = self._ws_authentication
            limit = endpoint.limit
            addr = self._address()
            addr = endpoint.get_address(self.sandbox) if addr is None else addr
            if not addr:
                continue

            # filtering can only be done on normalized symbols, but this subscription needs to have the raw/exchange specific
            # subscription, so we need to temporarily convert the symbols back and forth. It has to be done here
            # while in the context of the class
            temp_sub = {chan: [self.exchange_symbol_to_std_symbol(s) for s in symbols] for chan, symbols in self.subscription.items()}
            filtered_sub = {chan: [self.std_symbol_to_exchange_symbol(s) for s in symbols] for chan, symbols in endpoint.subscription_filter(temp_sub).items()}
            count = sum(map(len, filtered_sub.values()))

            if not filtered_sub or count == 0:
                continue
            if limit and count > limit:
                ret.extend(limit_sub(filtered_sub, limit, auth, endpoint.options))
            else:
                ret.append((WSAsyncConn(addr, self.id, authentication=auth, subscription=filtered_sub, **endpoint.options), self.subscribe, self.message_handler, self.authenticate))

        return ret
Esempio n. 8
0
 def connect(
     self
 ) -> List[Tuple[AsyncConnection, Callable[[None], None], Callable[
     [str, float], None]]]:
     ret = []
     if any(
             self.is_authenticated_channel(
                 self.exchange_channel_to_std(chan))
             for chan in self.subscription):
         ret.append((WSAsyncConn(self.address['private'], self.id,
                                 **self.ws_defaults),
                     partial(self.subscribe, private=True),
                     self.message_handler, self.authenticate))
     if any(not self.is_authenticated_channel(
             self.exchange_channel_to_std(chan))
            for chan in self.subscription):
         ret.append(
             (WSAsyncConn(self.address['public'], self.id,
                          **self.ws_defaults),
              partial(self.subscribe,
                      private=False), self.message_handler, self.__no_auth))
     return ret
Esempio n. 9
0
    def connect(self) -> List[Tuple[AsyncConnection, Callable[[None], None], Callable[[str, float], None]]]:
        # Phemex only allows 5 connections, with 20 subscriptions per connection, so split the subscription into separate
        # connections if necessary
        ret = []
        sub_pair = []

        if self.std_channel_to_exchange(BALANCES) in self.subscription:
            sub_pair.append([self.std_channel_to_exchange(BALANCES), BALANCES])

        for chan, symbols in self.subscription.items():
            if self.exchange_channel_to_std(chan) == BALANCES:
                continue
            for sym in symbols:
                sub_pair.append([chan, sym])
                if len(sub_pair) == 20:
                    func = partial(self.subscribe, subs=sub_pair)
                    ret.append((WSAsyncConn(self.address, self.id, **self.ws_defaults), func, self.message_handler, self.authenticate))
                    sub_pair = []

        if len(sub_pair) > 0:
            func = partial(self.subscribe, subs=sub_pair)
            ret.append((WSAsyncConn(self.address, self.id, **self.ws_defaults), func, self.message_handler, self.authenticate))

        return ret
Esempio n. 10
0
 def connect(
     self
 ) -> List[Tuple[AsyncConnection, Callable[[None], None], Callable[
     [str, float], None]]]:
     '''
         Linear PERPETUAL (USDT) public goes to USDT endpoint
         Linear PERPETUAL (USDT) private goes to USDTP endpoint
         Inverse PERPETUAL and FUTURES (USD) both private and public goes to USD endpoint
     '''
     ret = []
     if any(
             pair.split('-')[1] == 'USDT'
             for pair in self.normalized_symbols):
         if any(
                 self.is_authenticated_channel(
                     self.exchange_channel_to_std(chan))
                 for chan in self.subscription):
             ret.append((WSAsyncConn(self.address['USDTP'], self.id,
                                     **self.ws_defaults),
                         partial(self.subscribe, quote='USDTP'),
                         self.message_handler, self.authenticate))
         if any(not self.is_authenticated_channel(
                 self.exchange_channel_to_std(chan))
                for chan in self.subscription):
             ret.append((WSAsyncConn(self.address['USDT'], self.id,
                                     **self.ws_defaults),
                         partial(self.subscribe, quote='USDT'),
                         self.message_handler, self.__no_auth))
     if any(
             pair.split('-')[1] == 'USD'
             for pair in self.normalized_symbols):
         ret.append(
             (WSAsyncConn(self.address['USD'], self.id, **self.ws_defaults),
              partial(self.subscribe, quote='USD'), self.message_handler,
              self.authenticate))
     return ret
Esempio n. 11
0
 def build(options: list):
     subscribe = partial(self.subscribe, options=options)
     conn = WSAsyncConn(self.address, self.id, **self.ws_defaults)
     return conn, subscribe, self.message_handler