UNPKG

ccxws

Version:

Websocket client for 37 cryptocurrency exchanges

406 lines (405 loc) 13.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DeribitClient = void 0; /* eslint-disable @typescript-eslint/member-ordering */ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ const BasicClient_1 = require("../BasicClient"); const Candle_1 = require("../Candle"); const CandlePeriod_1 = require("../CandlePeriod"); const Throttle_1 = require("../flowcontrol/Throttle"); const Level2Point_1 = require("../Level2Point"); const Level2Snapshots_1 = require("../Level2Snapshots"); const NotImplementedFn_1 = require("../NotImplementedFn"); const Ticker_1 = require("../Ticker"); const Trade_1 = require("../Trade"); class DeribitClient extends BasicClient_1.BasicClient { constructor({ wssPath = "wss://www.deribit.com/ws/api/v2", watcherMs } = {}) { super(wssPath, "Deribit", undefined, watcherMs); this._sendSubLevel2Snapshots = NotImplementedFn_1.NotImplementedFn; this._sendUnsubLevel2Snapshots = NotImplementedFn_1.NotImplementedFn; this._sendSubLevel3Snapshots = NotImplementedFn_1.NotImplementedFn; this._sendUnsubLevel3Snapshots = NotImplementedFn_1.NotImplementedFn; this._sendSubLevel3Updates = NotImplementedFn_1.NotImplementedFn; this._sendUnsubLevel3Updates = NotImplementedFn_1.NotImplementedFn; this.hasTickers = true; this.hasTrades = true; this.hasCandles = true; this.hasLevel2Updates = true; this.id = 0; this.candlePeriod = CandlePeriod_1.CandlePeriod._1m; this._send = (0, Throttle_1.throttle)(this.__send.bind(this), 50); } _beforeClose() { this._send.cancel(); } __send(message) { this._wss.send(message); } _sendSubTicker(remote_id) { this._send(JSON.stringify({ jsonrpc: "2.0", method: "public/subscribe", params: { channels: [`ticker.${remote_id}.raw`], }, id: ++this.id, })); } _sendUnsubTicker(remote_id) { this._send(JSON.stringify({ jsonrpc: "2.0", method: "public/unsubscribe", params: { channels: [`ticker.${remote_id}.raw`], }, id: ++this.id, })); } _sendSubTrades(remote_id) { this._send(JSON.stringify({ jsonrpc: "2.0", method: "public/subscribe", params: { channels: [`trades.${remote_id}.raw`], }, id: ++this.id, })); } _sendUnsubTrades(remote_id) { this._send(JSON.stringify({ jsonrpc: "2.0", method: "public/unsubscribe", params: { channels: [`trades.${remote_id}.raw`], }, id: ++this.id, })); } _sendSubCandles(remote_id) { this._send(JSON.stringify({ jsonrpc: "2.0", method: "public/subscribe", params: { channels: [`chart.trades.${remote_id}.${candlePeriod(this.candlePeriod)}`], }, id: ++this.id, })); } _sendUnsubCandles(remote_id) { this._send(JSON.stringify({ jsonrpc: "2.0", method: "public/unsubscribe", params: { channels: [`chart.trades.${remote_id}.${candlePeriod(this.candlePeriod)}`], }, id: ++this.id, })); } _sendSubLevel2Updates(remote_id) { this._send(JSON.stringify({ jsonrpc: "2.0", method: "public/subscribe", params: { channels: [`book.${remote_id}.raw`], }, id: ++this.id, })); } _sendUnsubLevel2Updates(remote_id) { this._wss.send(JSON.stringify({ jsonrpc: "2.0", method: "public/unsubscribe", params: { channels: [`book.${remote_id}.raw`], }, id: ++this.id, })); } _onMessage(raw) { const msg = JSON.parse(raw); // console.log(msg); // Error? if (!msg.params) { return; } // Everything past here should be a channel message const channel = msg.params.channel; if (!channel) { return; } // tickers - ticker.{instrument_name}.{interval} if (channel.startsWith("ticker")) { const parts = channel.split("."); const market = this._tickerSubs.get(parts[1]); if (!market) return; const ticker = this._constructTicker(msg, market); this.emit("ticker", ticker, market); return; } // trades - trades.{instrument_name}.{interval} if (channel.startsWith("trades")) { const parts = channel.split("."); const market = this._tradeSubs.get(parts[1]); if (!market) return; // eslint-disable-next-line prefer-const for (let datum of msg.params.data) { const trade = this._constructTrade(datum, market); this.emit("trade", trade, market); } return; } // candle - chart.trades.{instrument_name}.{resolution} if (channel.startsWith("chart")) { const parts = channel.split("."); const market = this._candleSubs.get(parts[2]); if (!market) return; const candle = this._constructCandle(msg.params.data); this.emit("candle", candle, market); return; } // book - book.{instrument_name}.{interval} if (channel.startsWith("book")) { const parts = channel.split("."); const market = this._level2UpdateSubs.get(parts[1]); if (!market) return; // capture snapshot if (!msg.params.data.prev_change_id) { const snapshot = this._constructLevel2Snapshot(msg.params.data, market); this.emit("l2snapshot", snapshot, market); } // capture update else { const update = this._constructLevel2Update(msg.params.data, market); this.emit("l2update", update, market); } return; } } /** { "jsonrpc": "2.0", "method": "subscription", "params": { "channel": "ticker.BTC-PERPETUAL.raw", "data": { "timestamp": 1597244851057, "stats": { "volume_usd": 404775400.0, "volume": 35574.05167122, "price_change": 0.493, "low": 11131.5, "high": 11632.5 }, "state": "open", "settlement_price": 11452.62, "open_interest": 117979530, "min_price": 11443.06, "max_price": 11791.58, "mark_price": 11617.8, "last_price": 11618.0, "instrument_name": "BTC-PERPETUAL", "index_price": 11609.61, "funding_8h": 0.00001212, "estimated_delivery_price": 11609.61, "current_funding": 0.00020545, "best_bid_price": 11618.0, "best_bid_amount": 7460.0, "best_ask_price": 11618.5, "best_ask_amount": 497870.0 } } } */ _constructTicker(msg, market) { const data = msg.params.data; return new Ticker_1.Ticker({ exchange: this.name, base: market.base, quote: market.quote, timestamp: data.timestamp, last: (data.last_price ? data.last_price : 0).toFixed(8), open: undefined, high: (data.stats.high ? data.stats.high : 0).toFixed(8), low: (data.stats.low ? data.stats.low : 0).toFixed(8), volume: (data.stats.volume ? data.stats.volume : 0).toFixed(8), quoteVolume: undefined, change: undefined, changePercent: (data.stats.price_change ? data.stats.price_change : 0).toFixed(2), ask: (data.best_ask_price ? data.best_ask_price : 0).toFixed(8), askVolume: (data.best_ask_amount ? data.best_ask_amount : 0).toFixed(8), bid: (data.best_bid_price ? data.best_bid_price : 0).toFixed(8), bidVolume: (data.best_bid_amount ? data.best_bid_amount : 0).toFixed(8), }); } /** * PERPETUAL { "trade_seq": 56761222, "trade_id": "88095252", "timestamp": 1597246721811, "tick_direction": 3, "price": 11576.0, "mark_price": 11574.5, "instrument_name": "BTC-PERPETUAL", "index_price": 11567.32, "direction": "buy", "amount": 4310.0 } */ _constructTrade(datum, market) { return new Trade_1.Trade({ exchange: this.name, base: market.base, quote: market.quote, tradeId: datum.trade_id, side: datum.direction, unix: datum.timestamp, price: datum.price.toFixed(8), amount: datum.amount.toFixed(8), tradeSeq: datum.trade_seq, blockTradeId: datum.block_trade_id, markPrice: datum.mark_price.toFixed(8), indexPrice: datum.index_price.toFixed(8), liquidation: datum.liquidation, iv: datum.iv, tickDirection: datum.tick_direction, }); } /** { "volume" : 0.05219351, "tick" : 1573645080000, "open" : 8869.79, "low" : 8788.25, "high" : 8870.31, "cost" : 460, "close" : 8791.25 }, */ _constructCandle(data) { return new Candle_1.Candle(data.tick, data.open.toFixed(8), data.high.toFixed(8), data.low.toFixed(8), data.close.toFixed(8), data.volume.toFixed(8)); } /** { "type" : "snapshot", "timestamp" : 1554373962454, "instrument_name" : "BTC-PERPETUAL", "change_id" : 297217, "bids" : [ [ "new", 5042.34, 30 ], [ "new", 5041.94, 20 ] ], "asks" : [ [ "new", 5042.64, 40 ], [ "new", 5043.3, 40 ] ] } */ _constructLevel2Snapshot(data, market) { const timestampMs = data.timestamp; const sequenceId = data.change_id; const asks = data.asks.map(p => new Level2Point_1.Level2Point(p[1].toFixed(8), p[2].toFixed(8), undefined, { type: p[0] })); const bids = data.bids.map(p => new Level2Point_1.Level2Point(p[1].toFixed(8), p[2].toFixed(8), undefined, { type: p[0] })); return new Level2Snapshots_1.Level2Snapshot({ exchange: this.name, base: market.base, quote: market.quote, timestampMs, sequenceId, asks, bids, }); } /** { "type" : "change", "timestamp" : 1554373911330, "prev_change_id" : 297217, "instrument_name" : "BTC-PERPETUAL", "change_id" : 297218, "bids" : [ [ "delete", 5041.94, 0 ], [ "delete", 5042.34, 0 ] ], "asks" : [ ] } */ _constructLevel2Update(data, market) { const timestampMs = data.timestamp; const lastSequenceId = data.prev_change_id; const sequenceId = data.change_id; const asks = data.asks.map(p => new Level2Point_1.Level2Point(p[1].toFixed(8), p[2].toFixed(2), undefined, { type: p[0] })); const bids = data.bids.map(p => new Level2Point_1.Level2Point(p[1].toFixed(8), p[2].toFixed(2), undefined, { type: p[0] })); return new Level2Snapshots_1.Level2Snapshot({ exchange: this.name, base: market.base, quote: market.quote, timestampMs, sequenceId, lastSequenceId, asks, bids, }); } } exports.DeribitClient = DeribitClient; function candlePeriod(period) { switch (period) { case CandlePeriod_1.CandlePeriod._1m: return "1"; case CandlePeriod_1.CandlePeriod._3m: return "3"; case CandlePeriod_1.CandlePeriod._5m: return "5"; case CandlePeriod_1.CandlePeriod._10m: return "10"; case CandlePeriod_1.CandlePeriod._15m: return "15"; case CandlePeriod_1.CandlePeriod._30m: return "30"; case CandlePeriod_1.CandlePeriod._1h: return "60"; case CandlePeriod_1.CandlePeriod._2h: return "120"; case CandlePeriod_1.CandlePeriod._3h: return "180"; case CandlePeriod_1.CandlePeriod._6h: return "360"; case CandlePeriod_1.CandlePeriod._12h: return "720"; case CandlePeriod_1.CandlePeriod._1d: return "1D"; } } //# sourceMappingURL=DeribitClient.js.map