tlab-trading-toolkit
Version:
A trading toolkit for building advanced trading bots on the GDAX platform
197 lines (196 loc) • 9.02 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
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 ExchangeFeed_1 = require("../ExchangeFeed");
const Orderbook_1 = require("../../lib/Orderbook");
const ProductMap_1 = require("../ProductMap");
class HitbtcMarketFeed extends ExchangeFeed_1.ExchangeFeed {
constructor(config) {
super(config);
this.requestId = 0;
this.counters = {};
this.owner = 'Hitbtc';
this.url = `wss://api.hitbtc.com/api/2/ws`;
this.seq = 0;
this.connect();
setInterval(() => {
this.ping();
}, 25 * 1000);
}
static product(genericProduct) {
return ProductMap_1.ProductMap.ExchangeMap.get('Hitbtc').getExchangeProduct(genericProduct) || genericProduct;
}
static genericProduct(exchangeProduct) {
return ProductMap_1.ProductMap.ExchangeMap.get('Hitbtc').getGenericProduct(exchangeProduct) || exchangeProduct;
}
static getMarket(genericProduct) {
return ProductMap_1.ProductMap.ExchangeMap.get('Hitbtc').getMarket(genericProduct);
}
static getMarketForExchangeProduct(exchangeProduct) {
return ProductMap_1.ProductMap.ExchangeMap.get('Hitbtc').getMarket(HitbtcMarketFeed.genericProduct(exchangeProduct));
}
nextSequence(product) {
let counter = this.counters[product];
if (!counter) {
counter = this.counters[product] = { base: -1, offset: 0 };
}
if (counter.base < 1) {
console.warn(`Requesting next sequence without setting snapshot sequence for product ${product}, current counter offset ${counter.offset}`);
return -1;
}
counter.offset += 1;
return counter.base + counter.offset;
}
setSnapshotSequence(product, sequence) {
let counter = this.counters[product];
if (!counter) {
counter = this.counters[product] = { base: -1, offset: 0 };
}
counter.base = sequence;
}
getSnapshotSequence(product) {
const counter = this.counters[product];
return counter ? counter.base : -1;
}
subscribe(productIds) {
return __awaiter(this, void 0, void 0, function* () {
this.logger.log('debug', `Subscribing to the following symbols: ${JSON.stringify(productIds)}`);
var totalCount = productIds.length;
var count = 0;
for (const productId of productIds) {
this.counters[productId] = { base: -1, offset: 0 };
const subscribeOrderbookMessage = {
method: "subscribeOrderbook",
id: this.requestId++,
params: {
symbol: productId
}
};
const subscribeTradebookMessage = {
method: "subscribeTrades",
id: this.requestId++,
params: {
limit: 100,
symbol: productId
}
};
this.send(JSON.stringify(subscribeOrderbookMessage));
this.send(JSON.stringify(subscribeTradebookMessage));
yield new Promise((resolve, reject) => { setTimeout(resolve, 750); });
this.logger.log('debug', `completed ${count++} of ${totalCount}`);
}
return true;
});
}
onOpen() {
// Nothing for now
}
handleMessage(rawMsg) {
const msg = JSON.parse(rawMsg);
switch (msg.method) {
case "snapshotOrderbook":
this.handleSnapshot(msg);
break;
case "updateOrderbook":
this.handleOrderbookUpdate(msg);
break;
case "snapshotTrades":
case "updateTrades":
this.handleTrade(msg);
break;
}
}
handleSnapshot(snapshot) {
// (re)initialize our order id map
let sequence = snapshot.params.sequence;
let exchangeSymbol = snapshot.params.symbol;
let genericProduct = HitbtcMarketFeed.genericProduct(exchangeSymbol);
this.setSnapshotSequence(exchangeSymbol, sequence);
var asks = snapshot.params.ask.map((info) => {
return Orderbook_1.PriceLevelFactory(parseFloat(info.price), parseFloat(info.size), 'sell');
});
var bids = snapshot.params.bid.map((info) => {
return Orderbook_1.PriceLevelFactory(parseFloat(info.price), parseFloat(info.size), 'buy');
});
const snapshotMsg = {
time: new Date(snapshot.params.timestamp),
sequence: sequence,
type: 'snapshot',
productId: genericProduct,
asks,
bids,
orderPool: null
};
this.push(snapshotMsg);
}
handleOrderbookUpdate(updates) {
let sequence = updates.params.sequence;
let exchangeSymbol = updates.params.symbol;
let genericProduct = HitbtcMarketFeed.genericProduct(updates.params.symbol);
updates.params.ask.map((info) => {
const seq = this.nextSequence(exchangeSymbol);
const message = {
time: new Date(updates.params.timestamp),
sourceSequence: sequence,
sequence: seq,
type: 'level',
productId: genericProduct,
price: (info.price).toString(),
size: info.size ? info.size.toString() : '0',
side: 'sell',
count: 1,
};
this.push(message);
});
updates.params.bid.map((info) => {
const seq = this.nextSequence(exchangeSymbol);
const message = {
time: new Date(updates.params.timestamp),
sourceSequence: sequence,
sequence: seq,
type: 'level',
productId: genericProduct,
price: (info.price).toString(),
size: info.size ? info.size.toString() : '0',
side: 'buy',
count: 1,
};
this.push(message);
});
}
handleTrade(trades) {
trades.params.data.forEach((trade) => {
const message = {
type: 'trade',
productId: HitbtcMarketFeed.genericProduct(trades.params.symbol),
time: new Date(trade.timestamp),
tradeId: trade.id.toString(),
price: trade.price.toString(),
size: trade.quantity.toString(),
side: trade.side.toLowerCase(),
};
this.push(message);
});
}
}
exports.HitbtcMarketFeed = HitbtcMarketFeed;