UNPKG

tlab-trading-toolkit

Version:

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

310 lines (277 loc) 14.3 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 OrderbookUtils from '../../src/lib/OrderbookUtils'; import { ZERO, Big } from '../../src/lib/types'; import createOrderbookUtils from './createOrderbookUtils'; import assert = require('assert'); describe('An OrderbookUtils object', () => { let obu: OrderbookUtils = null; beforeEach(() => { const bids = [[100, 10, 1], [99, 5, 1], [98, 1, 1]]; const asks = [[110, 2, 1], [115, 1, 1], [120, 4, 10]]; obu = createOrderbookUtils(bids, asks); }); it('can calculate buy side stats when pre-cached', () => { const stats = obu.calculateMarketOrderStats('buy', 4, ZERO); assert(stats); assert.equal(stats.total_cost.toFixed(1), '455.0'); assert.equal(stats.ave_price.toFixed(2), '113.75'); assert.equal(stats.slippage.toFixed(4), '0.0341'); assert.equal(stats.unfilled.toFixed(4), '0.0000'); assert.equal(stats.first_price.toFixed(2), '110.00'); assert.equal(stats.last_price.toFixed(2), '120.00'); }); it('can calculate sell side stats when pre-cached', () => { const stats = obu.calculateMarketOrderStats('sell', 15.5); assert(stats); assert.equal(stats.total_cost.toFixed(1), '1544.0'); assert.equal(stats.ave_price.toFixed(2), '99.61'); assert.equal(stats.slippage.toFixed(5), '0.00387'); assert.equal(stats.unfilled.toFixed(4), '0.0000'); assert.equal(stats.first_price.toFixed(2), '100.00'); assert.equal(stats.last_price.toFixed(2), '98.00'); }); it('perfect fill case when pre-cached', () => { const stats = obu.calculateMarketOrderStats('sell', 15.0); assert(stats); assert.equal(stats.total_cost.toFixed(1), '1495.0'); assert.equal(stats.ave_price.toFixed(2), '99.67'); assert.equal(stats.slippage.toFixed(5), '0.00333'); assert.equal(stats.unfilled.toFixed(4), '0.0000'); assert.equal(stats.first_price.toFixed(2), '100.00'); assert.equal(stats.last_price.toFixed(2), '99.00'); }); it('can handle too-large orders when pre-cached', () => { const stats = obu.calculateMarketOrderStats('buy', 8); assert(stats); assert.equal(stats.total_cost.toFixed(1), '815.0'); assert.equal(stats.total_size.toFixed(1), '7.0'); assert.equal(stats.ave_price.toFixed(2), '116.43'); assert.equal(stats.slippage.toFixed(4), '0.0584'); assert.equal(stats.unfilled.toFixed(4), '1.0000'); assert.equal(stats.fees.toFixed(2), '0.00'); }); it('can handle zero-size orders when pre-cached', () => { const stats = obu.calculateMarketOrderStats('buy', 0); assert(stats); assert.equal(stats.total_cost.toFixed(1), '0.0'); assert.equal(stats.total_size.toFixed(1), '0.0'); assert.equal(stats.ave_price.toFixed(2), '110.00'); assert.equal(stats.slippage.toFixed(4), '0.0000'); assert.equal(stats.unfilled.toFixed(4), '0.0000'); assert.equal(stats.fees.toFixed(2), '0.00'); }); it('can determine fees when pre-cached', () => { const stats = obu.calculateMarketOrderStats('buy', 4, Big(0.001)); assert(stats); assert.equal(stats.total_cost.toFixed(3), '455.455'); assert.equal(stats.fees.toFixed(3), '0.455'); assert.equal(stats.ave_price.toFixed(3), '113.864'); assert.equal(stats.slippage.toFixed(6), '0.035125'); }); it('can calculate sum of order sizes up to index n', () => { assert.equal(+obu.getCumulativeSize(1, true), 3); assert.equal(+obu.getCumulativeSize(1, false), 15); assert.equal(+obu.getCumulativeSize(0, true), 2); assert.equal(+obu.getCumulativeSize(0, false), 10); assert.equal(+obu.getCumulativeSize(2, true), 7); assert.equal(+obu.getCumulativeSize(3, false), 16); }); it('can calculate sum of costs up to index n', () => { assert.equal(+obu.getCumulativeCost(1, true), 335); assert.equal(+obu.getCumulativeCost(1, false), 1495); assert.equal(+obu.getCumulativeCost(0, true), 220); assert.equal(+obu.getCumulativeCost(0, false), 1000); assert.equal(+obu.getCumulativeCost(2, true), 815); assert.equal(+obu.getCumulativeCost(3, false), 1593); }); }); describe('Partial sums of orderbooks', () => { let obu: OrderbookUtils = null; beforeEach(() => { const bids = [[100, 10, 1], [99, 5, 1], [98, 1, 1], [97, 3, 1]]; const asks = [[110, 2, 1], [115, 1, 1], [120, 4, 10], [125, 2, 3]]; obu = createOrderbookUtils(bids, asks); }); it('calculates sell stats between 10 and 15 BTC', () => { const stats = obu.integrateBetween(Big(10), Big(15), false, Big(0)); assert.equal(+stats.total_size, 5); assert.equal(+stats.first_price, 99); assert.equal(+stats.last_price, 99); assert.equal(+stats.total_cost, 495); assert.equal(+stats.unfilled, 0); }); it('calculates sell stats between 3 and 15.5 BTC', () => { const stats = obu.integrateBetween(Big(3), Big(15.5), false, Big(0)); assert.equal(+stats.total_size, 12.5); assert.equal(+stats.first_price, 100); assert.equal(+stats.last_price, 98); assert.equal(+stats.total_cost, 700 + 495 + 49); assert.equal(+stats.unfilled, 0); }); it('calculates sell stats between 10 and 10.1 BTC', () => { const stats = obu.integrateBetween(Big(10), Big(10.1), false, Big(0)); assert.equal(+stats.total_size, 0.1); assert.equal(+stats.first_price, 99); assert.equal(+stats.last_price, 99); assert.equal(+stats.total_cost, 9.9); assert.equal(+stats.unfilled, 0); }); it('calculates sell stats between 11 and 17 BTC', () => { const stats = obu.integrateBetween(Big(11), Big(17), false, Big(0)); assert.equal(+stats.total_size, 6); assert.equal(+stats.first_price, 99); assert.equal(+stats.last_price, 97); assert.equal(+stats.total_cost, 4 * 99 + 98 + 97); assert.equal(+stats.unfilled, 0); }); it('calculates sell stats between 11 and 17 BTC with fees', () => { const stats = obu.integrateBetween(Big(11), Big(17), false, Big(0.01)); assert.equal(+stats.total_size, 6); assert.equal(+stats.first_price, 99); assert.equal(+stats.last_price, 97); assert.equal(+stats.total_cost, (4 * 99 + 98 + 97) * 1.01); assert.equal(+stats.fees, (4 * 99 + 98 + 97) * 0.01); assert.equal(+stats.unfilled, 0); }); it('calculates sell stats between 16 and 20 BTC', () => { const stats = obu.integrateBetween(Big(16), Big(20), false, Big(0)); assert.equal(+stats.total_size, 3); assert.equal(+stats.first_price, 97); assert.equal(+stats.last_price, 97); assert.equal(+stats.total_cost, 3 * 97); assert.equal(+stats.unfilled, 1); }); it('calculates buy stats between 1 and 3 BTC', () => { const stats = obu.integrateBetween(Big(1), Big(3), true, Big(0)); assert.equal(+stats.total_size, 2); assert.equal(+stats.first_price, 110); assert.equal(+stats.last_price, 115); assert.equal(+stats.total_cost, 110 + 115); assert.equal(+stats.unfilled, 0); }); it('calculates buy stats between 2 and 7 BTC', () => { const stats = obu.integrateBetween(Big(2), Big(7), true, Big(0)); assert.equal(+stats.total_size, 5); assert.equal(+stats.first_price, 115); assert.equal(+stats.last_price, 120); assert.equal(+stats.total_cost, 115 + 4 * 120); assert.equal(+stats.unfilled, 0); }); it('calculates buy stats between 2 and 2 BTC', () => { const stats = obu.integrateBetween(Big(2), Big(2), true, Big(0)); assert.equal(+stats.total_size, 0); assert.equal(+stats.first_price, 115); assert.equal(+stats.last_price, 115); assert.equal(+stats.total_cost, 0); assert.equal(+stats.unfilled, 0); }); it('calculates buy stats between 2.5 and 2.5 BTC', () => { const stats = obu.integrateBetween(Big(2.5), Big(2.5), true, Big(0)); assert.equal(+stats.total_size, 0); assert.equal(+stats.first_price, 115); assert.equal(+stats.last_price, 115); assert.equal(+stats.total_cost, 0); assert.equal(+stats.unfilled, 0); }); }); describe('Sums using quote currency', () => { let obu: OrderbookUtils = null; beforeEach(() => { const bids = [[100, 10, 1], [95, 50, 1], [90, 10, 1], [85, 20, 1]]; const asks = [[110, 2, 1], [115, 1, 1], [120, 4, 10], [125, 100, 1]]; obu = createOrderbookUtils(bids, asks); }); it('calculates sell stats for $550', () => { const stats = obu.getSizeFromCost(Big(0), Big(550), false, Big(0)); assert.equal(+stats.total_size, 5.5); assert.equal(+stats.first_price, 100); assert.equal(+stats.last_price, 100); assert.equal(+stats.total_cost, 550); assert.equal(+stats.unfilled, 0); }); it('calculates buy stats for $165', () => { const stats = obu.getSizeFromCost(Big(0), Big(165), true, Big(0)); assert.equal(+stats.total_size, 1.5); assert.equal(+stats.first_price, 110); assert.equal(+stats.last_price, 110); assert.equal(+stats.total_cost, 165); assert.equal(+stats.unfilled, 0); }); it('calculates sell stats for $1095', () => { const stats = obu.getSizeFromCost(Big(0), Big(1095), false, Big(0)); assert.equal(+stats.total_size, 11); assert.equal(+stats.first_price, 100); assert.equal(+stats.last_price, 95); assert.equal(+stats.total_cost, 1095); assert.equal(+stats.unfilled, 0); }); it('calculates buy stats for $8,000', () => { const stats = obu.getSizeFromCost(Big(0), Big(8000), true, Big(0)); assert.equal(+stats.total_size, 64.48); assert.equal(+stats.first_price, 110); assert.equal(+stats.last_price, 125); assert.equal(+stats.total_cost, 8000); assert.equal(+stats.unfilled, 0); }); it('calculates sell stats for $1000 starting from $500', () => { const stats = obu.getSizeFromCost(Big(500), Big(1000), false, Big(0)); assert.equal(+stats.total_size, 5 + 500 / 95); // 10.26315789 assert.equal(+stats.first_price, 100); assert.equal(+stats.last_price, 95); assert.equal(+stats.total_cost, 1000); assert.equal(+stats.unfilled, 0); }); it('calculates buy stats for $2000 starting from $1000', () => { const stats = obu.getSizeFromCost(Big(1000), Big(2000), true, Big(0)); assert.equal(+stats.total_size.toFixed(6), 16); assert.equal(+stats.first_price, 125); assert.equal(+stats.last_price, 125); assert.equal(+stats.total_cost, 2000); assert.equal(+stats.unfilled, 0); }); it('calculates sell stats for $0 starting from $1200', () => { const stats = obu.getSizeFromCost(Big(5000), Big(0), false, Big(0)); assert.equal(+stats.total_size, 0); assert.equal(+stats.first_price, 95); assert.equal(+stats.last_price, 95); assert.equal(+stats.total_cost, 0); assert.equal(+stats.unfilled, 0); }); it('calculates buy stats for $0 starting from $2500', () => { const stats = obu.getSizeFromCost(Big(2500), Big(0), true, Big(0)); assert.equal(+stats.total_size, 0); assert.equal(+stats.first_price, 125); assert.equal(+stats.last_price, 125); assert.equal(+stats.total_cost, 0); assert.equal(+stats.unfilled, 0); }); it('calculates sell stats for $1000 starting from $500, including fees', () => { const stats = obu.getSizeFromCost(Big(500), Big(1000), false, Big(0.01)); assert.equal(+stats.total_size.toFixed(6), 10.158937); assert.equal(+stats.first_price, 100); assert.equal(+stats.last_price, 95); assert.equal(+stats.total_cost, 1000); assert.equal(+stats.unfilled, 0); }); it('calculates buy stats for $15,000 starting from $750, including fees', () => { const stats = obu.getSizeFromCost(Big(750), Big(15000), true, Big(0.01)); assert.equal(+stats.total_size.toFixed(3), 100.542); assert.equal(+stats.first_price, 120); assert.equal(+stats.last_price, 125); assert.equal(+stats.total_cost, 12690.65); assert.equal(+stats.fees, 125.65); assert.equal(+stats.unfilled, 2309.35); }); });