UNPKG

tlab-trading-toolkit

Version:

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

174 lines (131 loc) 8.63 kB
--- title: Introduction to the Live orderbook keywords: GTT, feed data, exchange, GDAX, orderbook last_updated: August 15, 2017 tags: [getting_started, tutorials] summary: "Producing a live orderbook" sidebar: gtt_sidebar permalink: gtt_tutorials_liveorderbook.html folder: gtt --- ## Introduction The Live Orderbook will lie at the heart of almost any real-world trading bot or algorithm. In this tutorial, we illustrate the steps to hook a LiveOrderbook instance up to a message feed and to start extracting information from it. ## Configuration The [LiveOrderbook class](apiref/modules/_src_core_liveorderbook_.html) configuration object has only one required field: `product`. Since an orderbook represents a single trading pair, any message with a product ID other than `product` will be filtered out. The other config options are `logger`, to pass a global [Logger](apiref/modules/_src_utils_logger_.html) object to the orderbook; and `strictMode`, a boolean, that determines the behavior when a skipped message is detected. `LiveOrderbook` is a writable stream, so once you have a feed message stream, and applied whatever filters and transformers to it that you like, you can pipe it straight in and the orderbook will update itself automatically. A standard template for creating and configuring a LiveOrderbook looks like this: import * as GTT from 'gdax-trading-toolkit'; const products = ['LTC-USD']; const logger = GTT.utils.ConsoleLoggerFactory({ level: 'debug' }); GTT.Factories.GDAX.FeedFactory(logger, products).then((feed: GDAXFeed) => { // Configure the live book object const config: LiveBookConfig = { product: product, logger: logger }; const book = new LiveOrderbook(config); feed.pipe(book); ... }); ## Orderbook messages `LiveOrderbook` emits an array of messages in response to certain events. | Event tag | Emitted when | Data provided | |-----------|--------------|---------------| | LiveOrderbook.update | The orderbook changes due to a new order, a cancelled order, or a trade | A descendant of [OrderbookMessage](apiref/interfaces/_src_core_messages_.orderbookmessage.html) causing the change | | LiveOrderbook.trade | a trade occurs | A [TradeMessage](apiref/interfaces/_src_core_messages_.trademessage.html) describing the trade | | LiveOrderbook.ticker | Whenever the ticker is updated | A [TickerMessage](apiref/interfaces/_src_core_messages_.tickermessage.html) instance | | LiveOrderbook.snapshot | When an orderbook snapshot is received, usually immediately after subscribing to the message feed. | The [SnapshotMessage](apiref/interfaces/_src_core_messages_.snapshotmessage.html) | | LiveOrderbook.skippedMessage | if a sequencing error in the message feed is detected. | A [SkippedMessageEvent](apiref/interfaces/_src_core_liveorderbook_.skippedmessageevent.html)| | error | An unrecoverable error occurs | The `Error` object | ## Orderbook methods and properties All the orderbook methods and properties are near-realtime. You can query the last update time with `book.timeSinceTickerUpdate` or `book.timeSinceOrderbookUpdate` which returns the time (is seconds) since the last update to the orderbook. Some of the handy properties available on `LiveOrderbook` are: | Property | Type | Description | |----------|------|-------------| | sourceSequence | number | The last known sequence number from the underlying feed, if it exists. Some websocket feeds don't supply sequences, for example. | | sequence | number | The sequence number as generated by the connected feed source. It may or may not correspond to `sourceSequence` | | numAsks | number | The number of orders on the sell side of the book | | numBids | number | The number of orders on the buy side of the book | | asksTotal | BigJS | The total value of the sell side of the book (in base currency) | | bidsTotal | BigJS | The total value of the buy side of the book (in base currency) | | book | BookBuilder | Provides access to the underlying book builder. Note: Modifying the book will cause the `LiveOrderbook` to go out of sync. | | ticker | Ticker | Returns the latest ticker information about the book | | baseCurrency | string | The base currency for the trading pair (e.g. BTC in BTC-USD) | | quoteCurrency | string | The quote currency for the trading pair (e.g. USD in BTC-USD) | ### ordersForValue `ordersForValue` is probably the most useful method in `liveOrderbook`. It allows you to query the orderbook to determine which orders would be filled for a given trade. This comes in useful for calculating things like average price, slippage and various other metrics for liquidity that are important for algorithmic trading. The function takes a side ('buy' or 'sell') and a value and returns the orders that would be filled by that trade. However, it also returns the cumulative size and cost/value of the trade at each level, from which all the liquidity metrics can be derived. The 3rd and 4th arguments to `ordersForValue` modify the interpretation of the trade. `useQuote` instructs the method to interpret `value` in quote currency rather than base currency. And `startingPoint` allows you to specify an offset value (by default it is zero). This allows you to calculate order tranches (the first 100 BTC, the second 100 BTC etc). ## Try it out Given a running LiveOrderbook instance, the following snippet console.log(`Number of bids: ${book.numBids} asks: ${book.numAsks}`); console.log(`Total ${book.baseCurrency} liquidity: ${book.bidsTotal.toFixed(3)} asks: ${book.asksTotal.toFixed(3)}`); let orders: CumulativePriceLevel[] = book.ordersForValue('buy', 100, false); console.log(`Cost of buying 100 ${book.baseCurrency}: ${orders[orders.length - 1].cumValue.toFixed(2)} ${book.quoteCurrency}`); orders = book.ordersForValue('sell', 1000, true); console.log(`Need to sell ${orders[orders.length - 1].cumSize.toFixed(3)} ${book.baseCurrency} to get 1000 ${book.quoteCurrency}`); would produce output similar to Number of bids: 1849 asks: 2297 Total LTC liquidity: 4004381.314 asks: 172100.402 Cost of buying 100 LTC: 4299.23 USD Need to sell 23.278 LTC to get 1000 USD To respond to orderbook messages, simple add an event listener to the book. To respond to ticker events you can do something like book.on('LiveOrderbook.ticker', (ticker: Ticker) => { console.log(ticker); }); And to track total trading volume since connecting, you would have let tradeVolume: number = 0; book.on('LiveOrderbook.trade', (trade: TradeMessage) => { tradeVolume += +(trade.size); }); A full working example can be found in the repository, in `tutorials/t002_liveOrderbook.ts`. It can be executed by running $ ts-node src/tutorials/t002_liveOrderbook.ts to obtain output similar to 2017-08-15T20:35:56.317Z - info: Creating new GDAX Websocket connection to wss://ws-feed.gdax.com 2017-08-15T20:35:57.661Z - debug: Connection to wss://ws-feed.gdax.com has been established. 2017-08-15T20:35:57.662Z - debug: Sending subscribe message to WS server 2017-08-15T20:35:58.697Z - info: Snapshot received by LiveOrderbook Demo Price: 42.89 | Bid: 42.89 | Ask: 42.90 | sequence: 4282257 Orderbook 266 1.3168 1.3168 $ 42.89 $ 42.90 3.8946 3.8946 67.3168 66.0000 $ 42.88 $ 42.91 1.0826 4.9772 67.3268 0.0100 $ 42.87 $ 42.92 1.0000 5.9772 97.3919 30.0652 $ 42.86 $ 42.94 0.1392 6.1164 117.4271 20.0352 $ 42.85 $ 42.95 0.9465 7.0629 160.4720 43.0449 $ 42.84 $ 42.96 52.4897 59.5527 182.9364 22.4644 $ 42.83 $ 42.97 5.8179 65.3706 182.9713 0.0349 $ 42.82 $ 42.98 11.7460 77.1166 223.0063 40.0349 $ 42.81 $ 42.99 7.4361 84.5527 1225.8337 1002.8275 $ 42.80 $ 43.00 213.4548 298.0075 Number of bids: 1846 asks: 2300 Total LTC liquidity: 4025988.612 asks: 171302.649 Cost of buying 100 LTC: 4296.80 USD Need to sell 1000.000 LTC to get 1000 USD 2017-08-15T20:36:03.704Z - info: Cumulative trade volume: 27.9451 Orderbook 409 1.3168 1.3168 $ 42.89 $ 42.90 3.8946 3.8946 26.3168 25.0000 $ 42.88 $ 42.91 1.0826 4.9772 56.3268 30.0100 $ 42.87 $ 42.92 1.0000 5.9772 ...