Ejemplo n.º 1
0
 async def _candles(self, msg: dict, symbol: str, timestamp: float):
     """
     {
         'data': {
             'symbol': 'BTC-USDT',
             'candles': ['1619196960', '49885.4', '49821', '49890.5', '49821', '2.60137567', '129722.909001802'],
             'time': 1619196997007846442
         },
         'subject': 'trade.candles.update',
         'topic': '/market/candles:BTC-USDT_1min',
         'type': 'message'
     }
     """
     symbol, interval = symbol.split("_")
     interval = self.normalize_interval[interval]
     start, open, close, high, low, vol, _ = msg['data']['candles']
     end = int(start) + timedelta_str_to_sec(interval) - 1
     await self.callback(CANDLES,
                         feed=self.id,
                         symbol=symbol,
                         timestamp=msg['data']['time'] / 1000000000,
                         receipt_timestamp=timestamp,
                         start=int(start),
                         stop=end,
                         interval=interval,
                         trades=None,
                         open_price=Decimal(open),
                         close_price=Decimal(close),
                         high_price=Decimal(high),
                         low_price=Decimal(low),
                         volume=Decimal(vol),
                         closed=None)
Ejemplo n.º 2
0
 async def _candle(self, msg: dict, timestamp: float):
     '''
     {
         'action': 'update',
         'arg': {
             'instType': 'sp',
             'channel': 'candle1m',
             'instId': 'BTCUSDT'
         },
         'data': [['1649014920000', '46434.2', '46437.98', '46434.2', '46437.98', '0.9469']]
     }
     '''
     for entry in msg['data']:
         t = Candle(self.id,
                    self.exchange_symbol_to_std_symbol(
                        msg['arg']['instId']),
                    self.timestamp_normalize(int(entry[0])),
                    self.timestamp_normalize(int(entry[0])) +
                    timedelta_str_to_sec(self.candle_interval),
                    self.candle_interval,
                    None,
                    Decimal(entry[1]),
                    Decimal(entry[4]),
                    Decimal(entry[2]),
                    Decimal(entry[3]),
                    Decimal(entry[5]),
                    None,
                    self.timestamp_normalize(int(entry[0])),
                    raw=entry)
         await self.callback(CANDLES, t, timestamp)
Ejemplo n.º 3
0
 async def _candles(self, msg: dict, timestamp: float):
     '''
     {
         'candle_start_time': 1638134700000000,
         'close': None,
         'high': None,
         'last_updated': 1638134700318213,
         'low': None,
         'open': None,
         'resolution': '1m',
         'symbol': 'BTC_USDT',
         'timestamp': 1638134708903082,
         'type': 'candlestick_1m',
         'volume': 0
     }
     '''
     interval = self.normalize_candle_interval[msg['resolution']]
     c = Candle(self.id,
                self.exchange_symbol_to_std_symbol(msg['symbol']),
                self.timestamp_normalize(msg['candle_start_time']),
                self.timestamp_normalize(msg['candle_start_time']) +
                timedelta_str_to_sec(interval) - 1,
                interval,
                None,
                Decimal(msg['open'] if msg['open'] else 0),
                Decimal(msg['close'] if msg['close'] else 0),
                Decimal(msg['high'] if msg['high'] else 0),
                Decimal(msg['low'] if msg['low'] else 0),
                Decimal(msg['volume'] if msg['volume'] else 0),
                False,
                self.timestamp_normalize(msg['timestamp']),
                raw=msg)
     await self.callback(CANDLES, c, timestamp)
Ejemplo n.º 4
0
 def _candle_normalize(self, symbol: str, data: list,
                       interval: str) -> dict:
     return Candle(self.id,
                   symbol,
                   data[0],
                   data[0] + timedelta_str_to_sec(interval),
                   interval,
                   None,
                   Decimal(data[3]),
                   Decimal(data[4]),
                   Decimal(data[2]),
                   Decimal(data[1]),
                   Decimal(data[5]),
                   True,
                   data[0],
                   raw=data)
Ejemplo n.º 5
0
    async def candles(self,
                      symbol: str,
                      start=None,
                      end=None,
                      interval='1m',
                      retry_count=1,
                      retry_delay=60):
        _interval = self.candle_mappings[interval]
        sym = self.std_symbol_to_exchange_symbol(symbol)
        base_endpoint = f"{self.api}candles/trade:{_interval}:{sym}"
        start, end = self._interval_normalize(start, end)
        offset = timedelta_str_to_sec(interval)

        while True:
            if start and end:
                endpoint = f"{base_endpoint}/hist?limit=10000&start={int(start * 1000)}&end={int(end * 1000)}&sort=1"
            else:
                endpoint = f"{base_endpoint}/last"

            r = await self.http_conn.read(endpoint,
                                          retry_delay=retry_delay,
                                          retry_count=retry_count)
            data = json.loads(r, parse_float=Decimal)
            if not isinstance(data[0], list):
                data = [data]
            data = [
                Candle(self.id,
                       symbol,
                       self.timestamp_normalize(e[0]),
                       self.timestamp_normalize(e[0]) + offset,
                       interval,
                       None,
                       Decimal(e[1]),
                       Decimal(e[2]),
                       Decimal(e[3]),
                       Decimal(e[4]),
                       Decimal(e[5]),
                       True,
                       self.timestamp_normalize(e[0]),
                       raw=e) for e in data
            ]
            yield data

            if not end or len(data) < 10000:
                break
            start = data[-1].start + offset
Ejemplo n.º 6
0
    async def _candle(self, msg: dict, timestamp: float):
        '''
        {
            'instrument_name': 'BTC_USDT',
            'subscription': 'candlestick.14D.BTC_USDT',
            'channel': 'candlestick',
            'depth': 300,
            'interval': '14D',
            'data': [
                {
                    't': 1636934400000,
                    'o': Decimal('65502.68'),
                    'h': Decimal('66336.25'),
                    'l': Decimal('55313.95'),
                    'c': Decimal('57582.1'),
                    'v': Decimal('366802.492134')
                }
            ]
        }
        '''
        interval = msg['interval']
        if interval == '14D':
            interval = '2w'
        elif interval == '7D':
            interval = '1w'
        elif interval == '1D':
            interval = '1d'

        for entry in msg['data']:
            c = Candle(self.id,
                       self.exchange_symbol_to_std_symbol(msg['instrument_name']),
                       entry['t'] / 1000,
                       entry['t'] / 1000 + timedelta_str_to_sec(interval) - 1,
                       interval,
                       None,
                       entry['o'],
                       entry['c'],
                       entry['h'],
                       entry['l'],
                       entry['v'],
                       None,
                       None,
                       raw=entry)
            await self.callback(CANDLES, c, timestamp)
Ejemplo n.º 7
0
 async def _candles(self, msg: dict, symbol: str, interval: str, timestamp: float):
     interval = self.normalize_interval[interval]
     start = int(msg['tick']['id'])
     end = start + timedelta_str_to_sec(interval) - 1
     await self.callback(CANDLES,
                         feed=self.id,
                         symbol= self.std_symbol_to_exchange_symbol(msg['ch'].split('.')[1]),
                         timestamp=timestamp_normalize(self.id, msg['ts']),
                         receipt_timestamp=timestamp,
                         start=start,
                         stop=end,
                         interval=interval,
                         trades=msg['tick']['count'],
                         open_price=Decimal(msg['tick']['open']),
                         close_price=Decimal(msg['tick']['close']),
                         high_price=Decimal(msg['tick']['high']),
                         low_price=Decimal(msg['tick']['low']),
                         volume=Decimal(msg['tick']['amount']),
                         closed='NULL')
Ejemplo n.º 8
0
    async def _candles(self, msg: dict, timestamp: float):
        """
        {
            "jsonrpc": "2.0",
            "method": "updateCandles",
            "params": {
                "data": [
                    {
                        "timestamp": "2017-10-19T16:30:00.000Z",
                        "open": "0.054614",
                        "close": "0.054465",
                        "min": "0.054339",
                        "max": "0.054724",
                        "volume": "141.268",
                        "volumeQuote": "7.709353873"
                    }
                ],
                "symbol": "ETHBTC",
                "period": "M30"
            }
        }
        """

        interval = str(self.normalize_interval[msg['period']])

        for candle in msg['data']:
            start = self.timestamp_normalize(candle['timestamp'])
            end = start + timedelta_str_to_sec(interval) - 1
            c = Candle(self.id,
                       self.exchange_symbol_to_std_symbol(msg['symbol']),
                       start,
                       end,
                       interval,
                       None,
                       Decimal(candle['open']),
                       Decimal(candle['close']),
                       Decimal(candle['max']),
                       Decimal(candle['min']),
                       Decimal(candle['volume']),
                       None,
                       None,
                       raw=candle)
            await self.callback(CANDLES, c, timestamp)
Ejemplo n.º 9
0
    async def candles(self,
                      symbol: str,
                      start=None,
                      end=None,
                      interval='1m',
                      retry_count=1,
                      retry_delay=60):
        sym = self.std_symbol_to_exchange_symbol(symbol)
        interval_sec = timedelta_str_to_sec(interval)
        base = f'{self.api}ohlc/{sym}/?step={interval_sec}&limit=1000'
        start, end = self._interval_normalize(start, end)

        while True:
            endpoint = base
            if start and end:
                endpoint = f'{base}&start={int(start)}&end={int(end)}'

            r = await self.http_conn.read(endpoint,
                                          retry_count=retry_count,
                                          retry_delay=retry_delay)
            data = json.loads(r, parse_float=Decimal)['data']['ohlc']
            data = [
                Candle(self.id,
                       symbol,
                       float(e['timestamp']),
                       float(e['timestamp']) + interval_sec,
                       interval,
                       None,
                       Decimal(e['open']),
                       Decimal(e['close']),
                       Decimal(e['high']),
                       Decimal(e['low']),
                       Decimal(e['volume']),
                       True,
                       float(e['timestamp']),
                       raw=e) for e in data
            ]
            yield data

            end = data[0].start - interval_sec
            if not start or start >= end:
                break
            await asyncio.sleep(1 / self.request_limit)
Ejemplo n.º 10
0
    async def candles(self,
                      symbol: str,
                      start=None,
                      end=None,
                      interval='1m',
                      retry_count=1,
                      retry_delay=60):
        sym = self.std_symbol_to_exchange_symbol(symbol)
        interval_sec = timedelta_str_to_sec(interval)
        base = f'{self.api}/markets/{sym}/candles?resolution={interval_sec}'
        start, end = self._interval_normalize(start, end)

        while True:
            endpoint = base
            if start and end:
                endpoint = f'{base}&start_time={start}&end_time={end}'

            r = await self.http_conn.read(endpoint,
                                          retry_count=retry_count,
                                          retry_delay=retry_delay)
            data = json.loads(r, parse_float=Decimal)['result']
            data = [
                Candle(self.id,
                       symbol,
                       self.timestamp_normalize(e['startTime']),
                       self.timestamp_normalize(e['startTime']) + interval_sec,
                       interval,
                       None,
                       Decimal(e['open']),
                       Decimal(e['close']),
                       Decimal(e['high']),
                       Decimal(e['low']),
                       Decimal(e['volume']),
                       True,
                       self.timestamp_normalize(e['startTime']),
                       raw=e) for e in data
            ]
            yield data

            end = data[0].start - interval_sec
            if not start or len(data) < 1501:
                break
            await asyncio.sleep(1 / self.request_limit)
Ejemplo n.º 11
0
 async def _candle(self, msg: dict, ts: float):
     '''
     {
         'ch': 'candles/M1',
         'update': {
             'BTCUSDT': [{
                 't': 1633805940000,
                 'o': '54849.03',
                 'c': '54849.03',
                 'h': '54849.03',
                 'l': '54849.03',
                 'v': '0.00766',
                 'q': '420.1435698'
             }]
         }
     }
     '''
     interval = msg['ch'].split("/")[-1]
     for sym, updates in msg['update'].items():
         symbol = self.exchange_symbol_to_std_symbol(sym)
         for u in updates:
             c = Candle(
                 self.id,
                 symbol,
                 u['t'] / 1000,
                 u['t'] / 1000 +
                 timedelta_str_to_sec(self.normalize_interval[interval]) -
                 0.1,
                 self.normalize_interval[interval],
                 None,
                 Decimal(u['o']),
                 Decimal(u['c']),
                 Decimal(u['h']),
                 Decimal(u['l']),
                 Decimal(u['v']),
                 None,
                 self.timestamp_normalize(u['t']),
                 raw=msg)
             await self.callback(CANDLES, c, ts)
Ejemplo n.º 12
0
 async def _candles(self, msg: dict, timestamp: float):
     """
     {
         'time': 1619092863,
         'channel': 'spot.candlesticks',
         'event': 'update',
         'result': {
             't': '1619092860',
             'v': '1154.64627',
             'c': '54992.64',
             'h': '54992.64',
             'l': '54976.29',
             'o': '54976.29',
             'n': '1m_BTC_USDT'
         }
     }
     """
     interval, symbol = msg['result']['n'].split('_', 1)
     if interval == '7d':
         interval = '1w'
     c = Candle(self.id,
                self.exchange_symbol_to_std_symbol(symbol),
                float(msg['result']['t']),
                float(msg['result']['t']) + timedelta_str_to_sec(interval) -
                0.1,
                interval,
                None,
                Decimal(msg['result']['o']),
                Decimal(msg['result']['c']),
                Decimal(msg['result']['h']),
                Decimal(msg['result']['l']),
                Decimal(msg['result']['v']),
                None,
                float(msg['time']),
                raw=msg)
     await self.callback(CANDLES, c, timestamp)
Ejemplo n.º 13
0
 async def _candles(self, msg: dict, symbol: str, interval: str,
                    timestamp: float):
     """
     {
         'ch': 'market.btcusdt.kline.1min',
         'ts': 1618700872863,
         'tick': {
             'id': 1618700820,
             'open': Decimal('60751.62'),
             'close': Decimal('60724.73'),
             'low': Decimal('60724.73'),
             'high': Decimal('60751.62'),
             'amount': Decimal('2.1990737759143966'),
             'vol': Decimal('133570.944386'),
             'count': 235}
         }
     }
     """
     interval = self.normalize_interval[interval]
     start = int(msg['tick']['id'])
     end = start + timedelta_str_to_sec(interval) - 1
     await self.callback(CANDLES,
                         feed=self.id,
                         symbol=self.exchange_symbol_to_std_symbol(symbol),
                         timestamp=timestamp_normalize(self.id, msg['ts']),
                         receipt_timestamp=timestamp,
                         start=start,
                         stop=end,
                         interval=interval,
                         trades=msg['tick']['count'],
                         open_price=Decimal(msg['tick']['open']),
                         close_price=Decimal(msg['tick']['close']),
                         high_price=Decimal(msg['tick']['high']),
                         low_price=Decimal(msg['tick']['low']),
                         volume=Decimal(msg['tick']['amount']),
                         closed=None)
Ejemplo n.º 14
0
 async def _candles(self, msg: dict, symbol: str, interval: str,
                    timestamp: float):
     """
     {
         'ch': 'market.btcusdt.kline.1min',
         'ts': 1618700872863,
         'tick': {
             'id': 1618700820,
             'open': Decimal('60751.62'),
             'close': Decimal('60724.73'),
             'low': Decimal('60724.73'),
             'high': Decimal('60751.62'),
             'amount': Decimal('2.1990737759143966'),
             'vol': Decimal('133570.944386'),
             'count': 235}
         }
     }
     """
     interval = self.normalize_candle_interval[interval]
     start = int(msg['tick']['id'])
     end = start + timedelta_str_to_sec(interval) - 1
     c = Candle(self.id,
                self.exchange_symbol_to_std_symbol(symbol),
                start,
                end,
                interval,
                msg['tick']['count'],
                Decimal(msg['tick']['open']),
                Decimal(msg['tick']['close']),
                Decimal(msg['tick']['high']),
                Decimal(msg['tick']['low']),
                Decimal(msg['tick']['amount']),
                None,
                self.timestamp_normalize(msg['ts']),
                raw=msg)
     await self.callback(CANDLES, c, timestamp)
Ejemplo n.º 15
0
    async def candles(self,
                      symbol: str,
                      start=None,
                      end=None,
                      interval='1m',
                      retry_count=1,
                      retry_delay=60):
        '''
        [
            {
            "market": "KRW-BTC",
            "candle_date_time_utc": "2021-09-11T00:32:00",
            "candle_date_time_kst": "2021-09-11T09:32:00",
            "opening_price": 55130000,
            "high_price": 55146000,
            "low_price": 55104000,
            "trade_price": 55145000,
            "timestamp": 1631320340367,
            "candle_acc_trade_price": 136592120.21198,
            "candle_acc_trade_volume": 2.47785284,
            "unit": 1
            },
            ...
        ]
        '''
        sym = self.std_symbol_to_exchange_symbol(symbol)
        offset = timedelta_str_to_sec(interval)
        interval_mins = int(timedelta_str_to_sec(interval) / 60)
        if interval == '1d':
            base = f'{self.api}candles/days/?market={sym}&count=200'
        elif interval == '1w':
            base = f'{self.api}candles/weeks/?market={sym}&count=200'
        elif interval == '1M':
            base = f'{self.api}candles/months/?market={sym}&count=200'
        else:
            base = f'{self.api}candles/minutes/{interval_mins}?market={sym}&count=200'
        start, end = self._interval_normalize(start, end)

        def _ts_norm(timestamp: datetime) -> float:
            # Upbit sends timezone naïve datetimes, so need to force to UTC before converting to timestamp
            assert timestamp.tzinfo is None
            return timestamp.replace(tzinfo=timezone.utc).timestamp()

        def retain(c: Candle, _last: set):
            if start and end:
                return c.start <= end and c.start not in _last
            return True

        _last = set()
        while True:
            endpoint = base
            if start and end:
                end_timestamp = datetime.utcfromtimestamp(start + offset * 200)
                end_timestamp = end_timestamp.replace(
                    microsecond=0).isoformat() + 'Z'
                endpoint = f'{base}&to={end_timestamp}'

            r = await self.http_conn.read(endpoint,
                                          retry_count=retry_count,
                                          retry_delay=retry_delay)
            data = json.loads(r, parse_float=Decimal)
            data = [
                Candle(self.id,
                       symbol,
                       _ts_norm(e['candle_date_time_utc']),
                       _ts_norm(e['candle_date_time_utc']) +
                       interval_mins * 60,
                       interval,
                       None,
                       Decimal(e['opening_price']),
                       None,
                       Decimal(e['high_price']),
                       Decimal(e['low_price']),
                       Decimal(e['candle_acc_trade_volume']),
                       True,
                       float(e['timestamp']) / 1000,
                       raw=e) for e in data
            ]
            data = list(
                sorted([c for c in data if retain(c, _last)],
                       key=lambda x: x.start))
            yield data

            # exchange downtime can cause gaps in candles, and because of the way pagination works, there will be overlap in ranges that
            # cover the downtime. Solution: remove duplicates by storing last values returned to client.
            _last = set([c.start for c in data])

            start = data[-1].start + offset
            if not end or start >= end:
                break
            await asyncio.sleep(1 / self.request_limit)