async def _funding(self, msg: dict, pair: str, timestamp: float): if 'funding_rate' in msg: f = Funding( self.id, pair, None, msg['funding_rate'], self.timestamp_normalize(msg['next_funding_rate_time']), self.timestamp_normalize(msg['time']), predicted_rate=msg['funding_rate_prediction'], raw=msg ) await self.callback(FUNDING, f, timestamp) oi = msg['openInterest'] if pair in self._open_interest_cache and oi == self._open_interest_cache[pair]: return self._open_interest_cache[pair] = oi o = OpenInterest( self.id, pair, oi, self.timestamp_normalize(msg['time']), raw=msg ) await self.callback(OPEN_INTEREST, o, timestamp)
async def _open_interest(self, msg: dict, timestamp: float): """ { 'arg': { 'channel': 'open-interest', 'instId': 'BTC-USDT-SWAP }, 'data': [ { 'instId': 'BTC-USDT-SWAP', 'instType': 'SWAP', 'oi':'565474', 'oiCcy': '5654.74', 'ts': '1630338003010' } ] } """ symbol = self.exchange_symbol_to_std_symbol(msg['arg']['instId']) for update in msg['data']: oi = OpenInterest(self.id, symbol, Decimal(update['oi']), self.timestamp_normalize(int(update['ts'])), raw=update) await self.callback(OPEN_INTEREST, oi, timestamp)
async def _open_interest(self, msg: dict, timestamp: float): """ { "openInterest": "10659.509", "symbol": "BTCUSDT", "time": 1589437530011 // Transaction time } """ pair = msg['symbol'] oi = msg['openInterest'] if oi != self._open_interest_cache.get(pair, None): o = OpenInterest(self.id, self.exchange_symbol_to_std_symbol(pair), Decimal(oi), self.timestamp_normalize(msg['time']), raw=msg) await self.callback(OPEN_INTEREST, o, timestamp) self._open_interest_cache[pair] = oi
async def _open_interest(self, pairs: Iterable): """ { "success": true, "result": { "volume": 1000.23, "nextFundingRate": 0.00025, "nextFundingTime": "2019-03-29T03:00:00+00:00", "expirationPrice": 3992.1, "predictedExpirationPrice": 3993.6, "strikePrice": 8182.35, "openInterest": 21124.583 } } """ while True: for pair in pairs: # OI only for perp and futures, so check for / in pair name indicating spot if '/' in pair: continue end_point = f"https://ftx.com/api/futures/{pair}/stats" data = await self.http_conn.read(end_point) received = time() data = json.loads(data, parse_float=Decimal) if 'result' in data: oi = data['result']['openInterest'] if oi != self._open_interest_cache.get(pair, None): o = OpenInterest( self.id, self.exchange_symbol_to_std_symbol(pair), oi, None, raw=data) await self.callback(OPEN_INTEREST, o, received) self._open_interest_cache[pair] = oi await asyncio.sleep(1) await asyncio.sleep(60)
async def _instrument_info(self, msg: dict, timestamp: float): """ ### Snapshot type update { "topic": "instrument_info.100ms.BTCUSD", "type": "snapshot", "data": { "id": 1, "symbol": "BTCUSD", //instrument name "last_price_e4": 81165000, //the latest price "last_tick_direction": "ZeroPlusTick", //the direction of last tick:PlusTick,ZeroPlusTick,MinusTick, //ZeroMinusTick "prev_price_24h_e4": 81585000, //the price of prev 24h "price_24h_pcnt_e6": -5148, //the current last price percentage change from prev 24h price "high_price_24h_e4": 82900000, //the highest price of prev 24h "low_price_24h_e4": 79655000, //the lowest price of prev 24h "prev_price_1h_e4": 81395000, //the price of prev 1h "price_1h_pcnt_e6": -2825, //the current last price percentage change from prev 1h price "mark_price_e4": 81178500, //mark price "index_price_e4": 81172800, //index price "open_interest": 154418471, //open interest quantity - Attention, the update is not //immediate - slowest update is 1 minute "open_value_e8": 1997561103030, //open value quantity - Attention, the update is not //immediate - the slowest update is 1 minute "total_turnover_e8": 2029370141961401, //total turnover "turnover_24h_e8": 9072939873591, //24h turnover "total_volume": 175654418740, //total volume "volume_24h": 735865248, //24h volume "funding_rate_e6": 100, //funding rate "predicted_funding_rate_e6": 100, //predicted funding rate "cross_seq": 1053192577, //sequence "created_at": "2018-11-14T16:33:26Z", "updated_at": "2020-01-12T18:25:16Z", "next_funding_time": "2020-01-13T00:00:00Z", //next funding time //the rest time to settle funding fee "countdown_hour": 6 //the remaining time to settle the funding fee }, "cross_seq": 1053192634, "timestamp_e6": 1578853524091081 //the timestamp when this information was produced } ### Delta type update { "topic": "instrument_info.100ms.BTCUSD", "type": "delta", "data": { "delete": [], "update": [ { "id": 1, "symbol": "BTCUSD", "prev_price_24h_e4": 81565000, "price_24h_pcnt_e6": -4904, "open_value_e8": 2000479681106, "total_turnover_e8": 2029370495672976, "turnover_24h_e8": 9066215468687, "volume_24h": 735316391, "cross_seq": 1053192657, "created_at": "2018-11-14T16:33:26Z", "updated_at": "2020-01-12T18:25:25Z" } ], "insert": [] }, "cross_seq": 1053192657, "timestamp_e6": 1578853525691123 } """ update_type = msg['type'] if update_type == 'snapshot': updates = [msg['data']] else: updates = msg['data']['update'] for info in updates: if msg['topic'] in self._instrument_info_cache and self._instrument_info_cache[msg['topic']] == updates: continue else: self._instrument_info_cache[msg['topic']] = updates ts = int(msg['timestamp_e6']) / 1_000_000 if 'open_interest' in info: oi = OpenInterest( self.id, self.exchange_symbol_to_std_symbol(info['symbol']), Decimal(info['open_interest']), ts, raw=info ) await self.callback(OPEN_INTEREST, oi, timestamp) if 'index_price_e4' in info: i = Index( self.id, self.exchange_symbol_to_std_symbol(info['symbol']), Decimal(info['index_price_e4']) * Decimal('1e-4'), ts, raw=info ) await self.callback(INDEX, i, timestamp) if 'funding_rate_e6' in info: f = Funding( self.id, self.exchange_symbol_to_std_symbol(info['symbol']), None, Decimal(info['funding_rate_e6']) * Decimal('1e-6'), info['next_funding_time'].timestamp(), ts, predicted_rate=Decimal(info['predicted_funding_rate_e6']) * Decimal('1e-6'), raw=info ) await self.callback(FUNDING, f, timestamp)
async def _instrument(self, msg: dict, timestamp: float): """ Example instrument data { 'table':'instrument', 'action':'partial', 'keys':[ 'symbol' ], 'types':{ 'symbol':'symbol', 'rootSymbol':'symbol', 'state':'symbol', 'typ':'symbol', 'listing':'timestamp', 'front':'timestamp', 'expiry':'timestamp', 'settle':'timestamp', 'relistInterval':'timespan', 'inverseLeg':'symbol', 'sellLeg':'symbol', 'buyLeg':'symbol', 'optionStrikePcnt':'float', 'optionStrikeRound':'float', 'optionStrikePrice':'float', 'optionMultiplier':'float', 'positionCurrency':'symbol', 'underlying':'symbol', 'quoteCurrency':'symbol', 'underlyingSymbol':'symbol', 'reference':'symbol', 'referenceSymbol':'symbol', 'calcInterval':'timespan', 'publishInterval':'timespan', 'publishTime':'timespan', 'maxOrderQty':'long', 'maxPrice':'float', 'lotSize':'long', 'tickSize':'float', 'multiplier':'long', 'settlCurrency':'symbol', 'underlyingToPositionMultiplier':'long', 'underlyingToSettleMultiplier':'long', 'quoteToSettleMultiplier':'long', 'isQuanto':'boolean', 'isInverse':'boolean', 'initMargin':'float', 'maintMargin':'float', 'riskLimit':'long', 'riskStep':'long', 'limit':'float', 'capped':'boolean', 'taxed':'boolean', 'deleverage':'boolean', 'makerFee':'float', 'takerFee':'float', 'settlementFee':'float', 'insuranceFee':'float', 'fundingBaseSymbol':'symbol', 'fundingQuoteSymbol':'symbol', 'fundingPremiumSymbol':'symbol', 'fundingTimestamp':'timestamp', 'fundingInterval':'timespan', 'fundingRate':'float', 'indicativeFundingRate':'float', 'rebalanceTimestamp':'timestamp', 'rebalanceInterval':'timespan', 'openingTimestamp':'timestamp', 'closingTimestamp':'timestamp', 'sessionInterval':'timespan', 'prevClosePrice':'float', 'limitDownPrice':'float', 'limitUpPrice':'float', 'bankruptLimitDownPrice':'float', 'bankruptLimitUpPrice':'float', 'prevTotalVolume':'long', 'totalVolume':'long', 'volume':'long', 'volume24h':'long', 'prevTotalTurnover':'long', 'totalTurnover':'long', 'turnover':'long', 'turnover24h':'long', 'homeNotional24h':'float', 'foreignNotional24h':'float', 'prevPrice24h':'float', 'vwap':'float', 'highPrice':'float', 'lowPrice':'float', 'lastPrice':'float', 'lastPriceProtected':'float', 'lastTickDirection':'symbol', 'lastChangePcnt':'float', 'bidPrice':'float', 'midPrice':'float', 'askPrice':'float', 'impactBidPrice':'float', 'impactMidPrice':'float', 'impactAskPrice':'float', 'hasLiquidity':'boolean', 'openInterest':'long', 'openValue':'long', 'fairMethod':'symbol', 'fairBasisRate':'float', 'fairBasis':'float', 'fairPrice':'float', 'markMethod':'symbol', 'markPrice':'float', 'indicativeTaxRate':'float', 'indicativeSettlePrice':'float', 'optionUnderlyingPrice':'float', 'settledPrice':'float', 'timestamp':'timestamp' }, 'foreignKeys':{ 'inverseLeg':'instrument', 'sellLeg':'instrument', 'buyLeg':'instrument' }, 'attributes':{ 'symbol':'unique' }, 'filter':{ 'symbol':'XBTUSD' }, 'data':[ { 'symbol':'XBTUSD', 'rootSymbol':'XBT', 'state':'Open', 'typ':'FFWCSX', 'listing':'2016-05-13T12:00:00.000Z', 'front':'2016-05-13T12:00:00.000Z', 'expiry':None, 'settle':None, 'relistInterval':None, 'inverseLeg':'', 'sellLeg':'', 'buyLeg':'', 'optionStrikePcnt':None, 'optionStrikeRound':None, 'optionStrikePrice':None, 'optionMultiplier':None, 'positionCurrency':'USD', 'underlying':'XBT', 'quoteCurrency':'USD', 'underlyingSymbol':'XBT=', 'reference':'BMEX', 'referenceSymbol':'.BXBT', 'calcInterval':None, 'publishInterval':None, 'publishTime':None, 'maxOrderQty':10000000, 'maxPrice':1000000, 'lotSize':1, 'tickSize':Decimal( '0.5' ), 'multiplier':-100000000, 'settlCurrency':'XBt', 'underlyingToPositionMultiplier':None, 'underlyingToSettleMultiplier':-100000000, 'quoteToSettleMultiplier':None, 'isQuanto':False, 'isInverse':True, 'initMargin':Decimal( '0.01' ), 'maintMargin':Decimal( '0.005' ), 'riskLimit':20000000000, 'riskStep':10000000000, 'limit':None, 'capped':False, 'taxed':True, 'deleverage':True, 'makerFee':Decimal( '-0.00025' ), 'takerFee':Decimal( '0.00075' ), 'settlementFee':0, 'insuranceFee':0, 'fundingBaseSymbol':'.XBTBON8H', 'fundingQuoteSymbol':'.USDBON8H', 'fundingPremiumSymbol':'.XBTUSDPI8H', 'fundingTimestamp':'2020-02-02T04:00:00.000Z', 'fundingInterval':'2000-01-01T08:00:00.000Z', 'fundingRate':Decimal( '0.000106' ), 'indicativeFundingRate':Decimal( '0.0001' ), 'rebalanceTimestamp':None, 'rebalanceInterval':None, 'openingTimestamp':'2020-02-02T00:00:00.000Z', 'closingTimestamp':'2020-02-02T01:00:00.000Z', 'sessionInterval':'2000-01-01T01:00:00.000Z', 'prevClosePrice':Decimal( '9340.63' ), 'limitDownPrice':None, 'limitUpPrice':None, 'bankruptLimitDownPrice':None, 'bankruptLimitUpPrice':None, 'prevTotalVolume':1999389257669, 'totalVolume':1999420432348, 'volume':31174679, 'volume24h':1605909209, 'prevTotalTurnover':27967114248663460, 'totalTurnover':27967447182062520, 'turnover':332933399058, 'turnover24h':17126993087717, 'homeNotional24h':Decimal( '171269.9308771703' ), 'foreignNotional24h':1605909209, 'prevPrice24h':9348, 'vwap':Decimal( '9377.3443' ), 'highPrice':9464, 'lowPrice':Decimal( '9287.5' ), 'lastPrice':9352, 'lastPriceProtected':9352, 'lastTickDirection':'ZeroMinusTick', 'lastChangePcnt':Decimal( '0.0004' ), 'bidPrice':9352, 'midPrice':Decimal( '9352.25' ), 'askPrice':Decimal( '9352.5' ), 'impactBidPrice':Decimal( '9351.9125' ), 'impactMidPrice':Decimal( '9352.25' ), 'impactAskPrice':Decimal( '9352.7871' ), 'hasLiquidity':True, 'openInterest':983043322, 'openValue':10518563545400, 'fairMethod':'FundingRate', 'fairBasisRate':Decimal( '0.11607' ), 'fairBasis':Decimal( '0.43' ), 'fairPrice':Decimal( '9345.36' ), 'markMethod':'FairPrice', 'markPrice':Decimal( '9345.36' ), 'indicativeTaxRate':0, 'indicativeSettlePrice':Decimal( '9344.93' ), 'optionUnderlyingPrice':None, 'settledPrice':None, 'timestamp':'2020-02-02T00:30:43.772Z' } ] } """ for data in msg['data']: if 'openInterest' in data: ts = self.timestamp_normalize(data['timestamp']) oi = OpenInterest(self.id, self.exchange_symbol_to_std_symbol(data['symbol']), Decimal(data['openInterest']), ts, raw=data) await self.callback(OPEN_INTEREST, oi, timestamp)
async def _ticker(self, msg: dict, timestamp: float): ''' { "params" : { "data" : { "timestamp" : 1550652954406, "stats" : { "volume" : null, "low" : null, "high" : null }, "state" : "open", "settlement_price" : 3960.14, "open_interest" : 0.12759952124659626, "min_price" : 3943.21, "max_price" : 3982.84, "mark_price" : 3940.06, "last_price" : 3906, "instrument_name" : "BTC-PERPETUAL", "index_price" : 3918.51, "funding_8h" : 0.01520525, "current_funding" : 0.00499954, "best_bid_price" : 3914.97, "best_bid_amount" : 40, "best_ask_price" : 3996.61, "best_ask_amount" : 50 }, "channel" : "ticker.BTC-PERPETUAL.raw" }, "method" : "subscription", "jsonrpc" : "2.0"} ''' pair = self.exchange_symbol_to_std_symbol( msg['params']['data']['instrument_name']) ts = self.timestamp_normalize(msg['params']['data']['timestamp']) t = Ticker(self.id, pair, Decimal(msg["params"]["data"]['best_bid_price']), Decimal(msg["params"]["data"]['best_ask_price']), ts, raw=msg) await self.callback(TICKER, t, timestamp) if "current_funding" in msg["params"]["data"] and "funding_8h" in msg[ "params"]["data"]: f = Funding(self.id, pair, Decimal(msg['params']['data']['mark_price']), Decimal(msg["params"]["data"]["current_funding"]), None, ts, raw=msg) await self.callback(FUNDING, f, timestamp) oi = msg['params']['data']['open_interest'] if pair in self._open_interest_cache and oi == self._open_interest_cache[ pair]: return self._open_interest_cache[pair] = oi o = OpenInterest(self.id, pair, Decimal(oi), ts, raw=msg) await self.callback(OPEN_INTEREST, o, timestamp)