UNPKG

tlab-trading-toolkit

Version:

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

133 lines (125 loc) 8.87 kB
/*************************************************************************************************************************** * @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. * ***************************************************************************************************************************/ import { OrderbookDiff } from '../../src/lib/OrderbookDiff'; import { BookBuilder } from '../../src/lib/BookBuilder'; import assert = require('assert'); import { PriceLevel } from '../../src/lib/Orderbook'; import { Biglike, Big } from '../../src/lib/types'; import { NullLogger } from '../../src/utils/Logger'; function assertPriceLevel(actual: PriceLevel, price: Biglike, size: Biglike, numOrders?: number) { assert.equal(+actual.totalSize, +size, 'size'); assert.equal(+actual.price, +price, 'price'); return true; } describe('OrderbookDiff', () => { it('produces a diff of orders missing on source', () => { const initial: BookBuilder = new BookBuilder(NullLogger); const final: BookBuilder = new BookBuilder(NullLogger); initial.add({ id: '1', price: Big(100), size: Big(5), side: 'buy' }); final.add({ id: '1', price: Big(100), size: Big(4), side: 'buy' }); final.add({ id: '2', price: Big(101), size: Big(3), side: 'buy' }); final.add({ id: '3', price: Big(102), size: Big(1), side: 'sell' }); const diff = OrderbookDiff.compareByLevel(initial, final, false); assert.equal(diff.bids.length, 2); assertPriceLevel(diff.bids[0], 100, -1); assertPriceLevel(diff.bids[1], 101, 3); assert.equal(diff.asks.length, 1); assertPriceLevel(diff.asks[0], 102, 1); }); it('produces a diff of orders missing on final', () => { const initial: BookBuilder = new BookBuilder(NullLogger); const final: BookBuilder = new BookBuilder(NullLogger); initial.add({ id: '1', price: Big(100), size: Big(5), side: 'buy' }); initial.add({ id: '2', price: Big(101), size: Big(5), side: 'sell' }); final.add({ id: '1', price: Big(101), size: Big(5), side: 'sell' }); const diff = OrderbookDiff.compareByLevel(initial, final, false); assert.equal(diff.bids.length, 1); assert.equal(diff.asks.length, 0); assertPriceLevel(diff.bids[0], 100, -5); }); it('produces a diff of null when books are identical', () => { const final: BookBuilder = new BookBuilder(NullLogger); final.add({ id: '1', price: Big(100), size: Big(4), side: 'buy' }); final.add({ id: '2', price: Big(101), size: Big(3), side: 'buy' }); final.add({ id: '3', price: Big(102), size: Big(1), side: 'sell' }); const diff = OrderbookDiff.compareByLevel(final, final, false); assert.equal(diff.bids.length, 0); assert.equal(diff.asks.length, 0); }); it('produces a order-level diff', () => { const initial: BookBuilder = new BookBuilder(NullLogger); const final: BookBuilder = new BookBuilder(NullLogger); initial.add({ id: '1', price: Big(100), size: Big(5), side: 'buy' }); initial.add({ id: '100', price: Big(98), size: Big(5), side: 'buy' }); initial.add({ id: '101', price: Big(104), size: Big(3.5), side: 'sell' }); final.add({ id: '2', price: Big(100), size: Big(4), side: 'buy' }); final.add({ id: '3', price: Big(101), size: Big(3), side: 'buy' }); final.add({ id: '4', price: Big(102), size: Big(1), side: 'sell' }); final.add({ id: '100', price: Big(98), size: Big(5), side: 'buy' }); final.add({ id: '101', price: Big(104), size: Big(3.5), side: 'sell' }); const diff = OrderbookDiff.compareByOrder(initial, final); assert.equal(Object.keys(diff.orderPool).length, 4); assert.equal(diff.bids.length, 2); assertPriceLevel(diff.bids[0], 101, 3, 1); assertPriceLevel(diff.bids[1], 100, -1, 2); assert.equal(diff.asks.length, 1); assertPriceLevel(diff.asks[0], 102, 1); }); it('produces a simple set of trade messages', () => { const initial: BookBuilder = new BookBuilder(NullLogger); const final: BookBuilder = new BookBuilder(NullLogger); initial.add({ id: '1', price: Big(100), size: Big(5), side: 'buy' }); initial.add({ id: '100', price: Big(98), size: Big(5), side: 'buy' }); initial.add({ id: '101', price: Big(104), size: Big(3.5), side: 'sell' }); final.add({ id: '2', price: Big(100), size: Big(4), side: 'buy' }); final.add({ id: '3', price: Big(101), size: Big(3), side: 'buy' }); final.add({ id: '4', price: Big(102), size: Big(1), side: 'sell' }); final.add({ id: '100', price: Big(98), size: Big(5), side: 'buy' }); final.add({ id: '101', price: Big(104), size: Big(3.5), side: 'sell' }); const diff = new OrderbookDiff('BTC-ABC', initial, final); const messages = diff.generateSimpleCommandSet({ postOnly: true }); const now = messages[0].time; assert.deepEqual(messages, [ { type: 'cancelAllOrders', time: now }, { type: 'placeOrder', time: now, orderType: 'limit', productId: 'BTC-ABC', price: '101', size: '3', side: 'buy', postOnly: true }, { type: 'placeOrder', time: now, orderType: 'limit', productId: 'BTC-ABC', price: '100', size: '4', side: 'buy', postOnly: true }, { type: 'placeOrder', time: now, orderType: 'limit', productId: 'BTC-ABC', price: '98', size: '5', side: 'buy', postOnly: true }, { type: 'placeOrder', time: now, orderType: 'limit', productId: 'BTC-ABC', price: '102', size: '1', side: 'sell', postOnly: true }, { type: 'placeOrder', time: now, orderType: 'limit', productId: 'BTC-ABC', price: '104', size: '3.5', side: 'sell', postOnly: true } ]); }); it('produces a diff-set of trade messages', () => { const initial: BookBuilder = new BookBuilder(NullLogger); const final: BookBuilder = new BookBuilder(NullLogger); initial.add({ id: '10', price: Big(100), size: Big(5), side: 'buy' }); initial.add({ id: '11', price: Big(100), size: Big(6), side: 'buy' }); initial.add({ id: '100', price: Big(98), size: Big(5), side: 'buy' }); initial.add({ id: '101', price: Big(104), size: Big(3.5), side: 'sell' }); final.add({ id: '2', price: Big(100), size: Big(4), side: 'buy' }); final.add({ id: '3', price: Big(101), size: Big(3), side: 'buy' }); final.add({ id: '4', price: Big(102), size: Big(1), side: 'sell' }); final.add({ id: '100', price: Big(98), size: Big(5), side: 'buy' }); final.add({ id: '101', price: Big(104), size: Big(3.5), side: 'sell' }); const diff = new OrderbookDiff('BTC-ABC', initial, final); const messages = diff.generateDiffCommands(null, { postOnly: true }); const now = messages[0].time; assert.deepEqual(messages, [ { type: 'cancelOrder', time: now, orderId: '10' }, { type: 'cancelOrder', time: now, orderId: '11' }, { type: 'placeOrder', time: now, orderType: 'limit', productId: 'BTC-ABC', price: '100', size: '4', side: 'buy', postOnly: true }, { type: 'placeOrder', time: now, orderType: 'limit', productId: 'BTC-ABC', price: '101', size: '3', side: 'buy', postOnly: true }, { type: 'placeOrder', time: now, orderType: 'limit', productId: 'BTC-ABC', price: '102', size: '1', side: 'sell', postOnly: true } ]); }); });