UNPKG

tlab-trading-toolkit

Version:

A trading toolkit for building advanced trading bots on the GDAX platform

159 lines (158 loc) 6.9 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); /*************************************************************************************************************************** * @license * * Copyright 2017 Coinbase, Inc. * * * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * * with the License. You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on * * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * * License for the specific language governing permissions and limitations under the License. * ***************************************************************************************************************************/ const _1 = require("../"); const ExchangeFeed_1 = require("../ExchangeFeed"); const types_1 = require("../../lib/types"); exports.GEMINI_API_URL = 'https://api.gemini.com/v1'; exports.GEMINI_WS_FEED = 'wss://api.gemini.com/v1/marketdata/'; class GeminiMarketFeed extends ExchangeFeed_1.ExchangeFeed { static product(genericProduct) { return _1.ProductMap.ExchangeMap.get('Gemini').getExchangeProduct(genericProduct) || genericProduct; } static genericProduct(exchangeProduct) { return _1.ProductMap.ExchangeMap.get('Gemini').getGenericProduct(exchangeProduct) || exchangeProduct; } static getMarket(genericProduct) { return _1.ProductMap.ExchangeMap.get('Gemini').getMarket(genericProduct); } static getMarketForExchangeProduct(exchangeProduct) { return _1.ProductMap.ExchangeMap.get('Gemini').getMarket(GeminiMarketFeed.genericProduct(exchangeProduct)); } constructor(config) { super(config); this.owner = 'Gemini'; this.multiSocket = true; this.feedUrl = config.wsUrl || exports.GEMINI_WS_FEED; this.connect(config.products); } getWebsocketUrlForProduct(product) { return exports.GEMINI_WS_FEED + product; } handleMessage(msg, productId) { try { const feedMessage = JSON.parse(msg); if (productId) feedMessage.productId = GeminiMarketFeed.genericProduct(productId); switch (feedMessage.type) { case 'heartbeat': this.confirmAlive(); break; case 'update': this.processUpdate(feedMessage); break; } } catch (err) { err.ws_msg = msg; this.onError(err); } } onOpen() { // Do nothing for now } processUpdate(update) { if (update.socket_sequence === 0) { // Process the first message with the orderbook state this.push(this.createSnapshotMessage(update)); } else { update.events.forEach((event) => { let message; switch (event.type) { case 'trade': message = this.processTrade(event, update); break; case 'change': message = this.processChange(event, update); break; case 'auction': message = this.processAuction(event, update); break; } this.push(message); }); } } createSnapshotMessage(update) { const orders = {}; const snapshotMessage = { type: 'snapshot', time: new Date(+update.timestampms), productId: update.productId, sequence: 0, asks: [], bids: [], orderPool: orders }; // First message only contains 'change' events with reason as 'initial' update.events.forEach((event) => { if (event.type === 'change') { const changeEvent = event; if (changeEvent.reason === 'initial') { const newOrder = { id: changeEvent.price, price: types_1.Big(changeEvent.price), size: types_1.Big(changeEvent.delta), side: changeEvent.side === 'ask' ? 'sell' : 'buy' }; const level = { price: types_1.Big(changeEvent.price), totalSize: types_1.Big(changeEvent.delta), orders: [newOrder] }; if (changeEvent.side === 'ask') { snapshotMessage.asks.push(level); } else if (changeEvent.side === 'bid') { snapshotMessage.bids.push(level); } orders[newOrder.id] = newOrder; } } }); return snapshotMessage; } processTrade(event, update) { const message = { type: 'trade', productId: update.productId, time: new Date(+update.timestampms), tradeId: event.tid.toString(), price: event.price, size: event.amount, side: event.makerSide === 'ask' ? 'sell' : 'buy' }; return message; } processChange(event, update) { const message = { type: 'level', productId: update.productId, time: new Date(+update.timestampms), price: event.price, size: event.remaining, sequence: update.socket_sequence, side: event.side === 'ask' ? 'sell' : 'buy', count: 1 }; return message; } processAuction(event, update) { // TODO: Are auctions unique to Gemini? return undefined; } } exports.GeminiMarketFeed = GeminiMarketFeed;