├── .eslintignore ├── .eslintrc.json ├── .gitattributes ├── .github └── workflows │ └── nodejs.yml ├── .gitignore ├── .npmignore ├── .prettierrc ├── LICENSE ├── README.md ├── jest.config.js ├── package.json ├── src ├── __test__ │ └── orderbook.test.ts ├── index.ts ├── orderbook.ts ├── orderbook_store.ts ├── types.ts └── utils.ts └── tsconfig.json /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib 3 | types 4 | *__test__ 5 | jest.config.js 6 | package-lock.json -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "node": true 4 | }, 5 | "root": true, 6 | "parser": "@typescript-eslint/parser", 7 | "parserOptions": { 8 | "project": "./tsconfig.json" 9 | }, 10 | "plugins": ["@typescript-eslint", "prettier"], 11 | "extends": ["airbnb-typescript", "plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/recommended", "plugin:prettier/recommended"], 12 | "rules": { 13 | "no-console": "error", 14 | "camelcase": "off", 15 | "import/prefer-default-export": "off", 16 | "import/no-default-export": "off", 17 | "no-bitwise": "off", 18 | "no-plusplus": "off", 19 | "import/no-cycle": "off", 20 | "no-underscore-dangle": "off", 21 | "consistent-return": "off", 22 | "no-restricted-syntax": "off", 23 | "no-await-in-loop": "off", 24 | "no-return-assign": "warn", 25 | "class-methods-use-this": "off", 26 | "import/no-dynamic-require": "off", 27 | "global-require": "off", 28 | "lines-between-class-members": "off", 29 | "array-element-newline": ["error", "consistent"], 30 | "array-bracket-newline": ["error", "consistent"] 31 | }, 32 | "settings": { 33 | "react": { 34 | "version": "999.999.999" 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | pull_request: 10 | branches: [ master ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | strategy: 18 | matrix: 19 | node-version: [10.x, 12.x] 20 | 21 | steps: 22 | - uses: actions/checkout@v2 23 | - name: Use Node.js ${{ matrix.node-version }} 24 | uses: actions/setup-node@v1 25 | with: 26 | node-version: ${{ matrix.node-version }} 27 | - run: npm install 28 | - run: npm run build --if-present 29 | - run: npm test 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Optional REPL history 57 | .node_repl_history 58 | 59 | # Output of 'npm pack' 60 | *.tgz 61 | 62 | # Yarn Integrity file 63 | .yarn-integrity 64 | 65 | # dotenv environment variables file 66 | .env 67 | .env.test 68 | 69 | # parcel-bundler cache (https://parceljs.org/) 70 | .cache 71 | 72 | # next.js build output 73 | .next 74 | 75 | # nuxt.js build output 76 | .nuxt 77 | 78 | # vuepress build output 79 | .vuepress/dist 80 | 81 | # Serverless directories 82 | .serverless/ 83 | 84 | # FuseBox cache 85 | .fusebox/ 86 | 87 | # DynamoDB Local files 88 | .dynamodb/ 89 | lib/ 90 | package-lock.json 91 | .coveralls.yml 92 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .babelrc 2 | .eslintignore 3 | .eslintrc.json 4 | .gitignore 5 | .lintstagedrc.json 6 | .nycrc 7 | .prettierrc 8 | .coveralls.yml 9 | 10 | tsconfig.json 11 | jest.config.js 12 | coverage 13 | src 14 | __tests__ 15 | examples -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "trailingComma": "all", 4 | "singleQuote": true 5 | } 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Valamidev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Orderbook Synchronizer 2 | 3 | [![DeepScan grade](https://deepscan.io/api/teams/6761/projects/8876/branches/113562/badge/grade.svg)](https://deepscan.io/dashboard#view=project&tid=6761&pid=8876&bid=113562) 4 | [![npm](https://img.shields.io/npm/v/orderbook-synchronizer)](https://www.npmjs.com/package/orderbook-synchronizer) 5 | [![npm](https://img.shields.io/npm/dy/orderbook-synchronizer)](https://www.npmjs.com/package/orderbook-synchronizer) 6 | [![Coverage Status](https://coveralls.io/repos/github/valamidev/orderbook-synchronizer/badge.svg)](https://coveralls.io/github/valamidev/orderbook-synchronizer) 7 | 8 | This package allow you to keep update your Orderbook snapshot from a given Websocket source of Orders. 9 | 10 | **Features:** 11 | 12 | - Orderbook size limit available to avoid overgrow 13 | - Lightweight / No dependency 14 | - Handle Bid/Ask overlaps, best Ask always higher or equal with best Bids 15 | 16 | **Orderbook output sample(`.getOrderBook()`):** 17 | 18 | ```javascript 19 | { 20 | asks: [ 21 | [8000, 1.9869372781826433], 22 | [8001, 0.6590219188159661], 23 | [8002, 1.0430790809329253], 24 | [8003, 0.1279416255016304], 25 | [8004, 1.3397780002928084], 26 | [8005, 1.8250517469118535], 27 | ], 28 | bids: [ 29 | [6020, 1.5764351751676466], 30 | [6019, 1.9678679870588733], 31 | [6018, 1.7349295266546774], 32 | [6017, 1.0087743314824977], 33 | [6016, 0.0942339070977258], 34 | ] 35 | } 36 | ``` 37 | 38 | **Imports:** 39 | 40 | ```javascript 41 | import {OrderBookStore} from 'orderbook-synchronizer'; // Multiple OrderBooks in a single class 42 | import {Orderbook} from 'orderbook-synchronizer'; // Single OrderBook 43 | ``` 44 | 45 | ## Available methods(OrderBookStore): 46 | 47 | #### Constructor: 48 | 49 | ```javascript 50 | const OrderBooks = new OrderBookStore(1000); // Set memory limit / maximum length of Ask/Bid array 51 | ``` 52 | 53 | #### updateOrderBook: 54 | 55 | ```javascript 56 | OrderBooks.updateOrderBook('BTC/USD', asks: Order[], bids: Order[]); // Create/Update Orderbook 57 | ``` 58 | 59 | #### hasOrderBook: 60 | 61 | ```javascript 62 | OrderBooks.hasOrderBook('BTC/USD'); // return boolean if Orderbook exist 63 | ``` 64 | 65 | #### getOrderBook: 66 | 67 | ```javascript 68 | OrderBooks.getOrderBook('BTC/USD'); // return Orderbook | undefined depends on Orderbook exist 69 | ``` 70 | 71 | #### getSymbolList: 72 | 73 | ```javascript 74 | OrderBooks.getSymbolList(); // return all Orderbook keys in array ['BTC/USD'] 75 | ``` 76 | 77 | ## Available methods(Orderbook): 78 | 79 | #### Constructor: 80 | 81 | ```javascript 82 | const SingleOrderBook = new Orderbook(1000); // Set memory limit / maximum length of Ask/Bid array 83 | ``` 84 | 85 | #### getOrderBook: 86 | 87 | ```javascript 88 | SingleOrderBook.getOrderBook(); // return Orderbook 89 | ``` 90 | 91 | #### updateOrderBook: 92 | 93 | ```javascript 94 | SingleOrderBook.updateOrderBook(asks: Order[], bids: Order[]); // Update Orderbook 95 | ``` 96 | 97 | **Original inspiration source:** 98 | 99 | - https://gist.github.com/hitbtc-com/fc738c1b926d9d7aa7e3bd5247f792a1 100 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | globals: { 3 | 'ts-jest': { 4 | diagnostics: { 5 | ignoreCodes: [2532], 6 | }, 7 | }, 8 | }, 9 | 10 | collectCoverage: true, 11 | 12 | coveragePathIgnorePatterns: ['/node_modules|lib/'], 13 | 14 | collectCoverageFrom: ['src/**/*.ts'], 15 | 16 | transform: { 17 | '.(ts|tsx)': 'ts-jest', 18 | }, 19 | testRegex: '(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$', 20 | moduleFileExtensions: ['ts', 'tsx', 'js'], 21 | }; 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "orderbook-synchronizer", 3 | "version": "5.0.1", 4 | "description": "Orderbook Synchronizer for cryptocurrency exchanges", 5 | "main": "lib/index.js", 6 | "types": "lib/index.d.ts", 7 | "scripts": { 8 | "start": "node example.js", 9 | "prebuild": "rimraf lib", 10 | "build": "tsc", 11 | "prepublish": "rimraf lib && tsc", 12 | "test": "jest", 13 | "coveralls": "jest --coverage --coverageReporters=text-lcov | coveralls", 14 | "lint": "eslint . --ext .ts", 15 | "lint:fix": "eslint . --ext .ts --fix" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/valamidev/orderbook-synchronizer.git" 20 | }, 21 | "keywords": [ 22 | "orderbook", 23 | "exchanges", 24 | "binance", 25 | "ccxt", 26 | "algotrading", 27 | "realtime", 28 | "api" 29 | ], 30 | "author": "", 31 | "license": "ISC", 32 | "devDependencies": { 33 | "coveralls": "^3.0.11", 34 | "@types/jest": "^24.0.18", 35 | "@types/node": "^12.12.26", 36 | "@types/request": "^2.48.4", 37 | "@typescript-eslint/eslint-plugin": "^2.26.0", 38 | "@typescript-eslint/parser": "^2.21.0", 39 | "eslint": "^6.8.0", 40 | "eslint-config-airbnb-typescript": "^7.2.0", 41 | "eslint-config-prettier": "^6.10.1", 42 | "eslint-plugin-import": "^2.20.2", 43 | "eslint-plugin-jsx-a11y": "^6.2.3", 44 | "eslint-plugin-prettier": "^3.1.2", 45 | "eslint-plugin-react": "^7.19.0", 46 | "eslint-plugin-react-hooks": "^2.5.1", 47 | "husky": "^4.2.3", 48 | "jest": "^24.9.0", 49 | "lint-staged": "^10.1.1", 50 | "prettier": "^2.0.2", 51 | "rimraf": "^3.0.2", 52 | "ts-jest": "^24.0.2", 53 | "ts-node": "^8.4.1", 54 | "typescript": "^3.8.0" 55 | }, 56 | "files": [ 57 | "lib/**/*" 58 | ] 59 | } 60 | -------------------------------------------------------------------------------- /src/__test__/orderbook.test.ts: -------------------------------------------------------------------------------- 1 | import { OrderBookStore, Orderbook } from '../index'; 2 | import { Order } from '../types'; 3 | 4 | describe('Orderbook Synchronizer', () => { 5 | it('should OrderBookStore not succeed memory limit', () => { 6 | const OrderBooks = new OrderBookStore(1000); 7 | 8 | const symbol = 'BTCUSDT'; 9 | 10 | const round = 1001; 11 | 12 | for (let i = 0; i < round; i++) { 13 | const asks: Order[] = [[8000 + i, 2 * Math.random()]]; 14 | const bids: Order[] = [[6000 + i, 2 * Math.random()]]; 15 | 16 | OrderBooks.updateOrderBook(symbol, asks, bids); 17 | } 18 | 19 | expect(OrderBooks.getOrderBook(symbol).asks).toHaveLength(1000); 20 | }); 21 | 22 | it('OrderBookStore Cleanup Test', () => { 23 | const OrderBooks = new OrderBookStore(1000); 24 | 25 | const symbol = 'BTCUSDT'; 26 | 27 | const round = 1000000; 28 | 29 | for (let i = 0; i < round; i++) { 30 | const asks: Order[] = [[100 * Math.random(), 2 * Math.random()]]; 31 | const bids: Order[] = [[100 * Math.random(), 2 * Math.random()]]; 32 | 33 | OrderBooks.updateOrderBook(symbol, asks, bids); 34 | } 35 | 36 | OrderBooks.updateOrderBook(symbol, [[90, 2]], [[90, 2]]); 37 | OrderBooks.updateOrderBook(symbol, [[90, 2]], [[90, 2]]); 38 | OrderBooks.updateOrderBook(symbol, [[90, 2]], [[90, 2]]); 39 | 40 | const OrderBookResult = OrderBooks.getOrderBook(symbol); 41 | 42 | expect(OrderBookResult.bids[0][0]).toBeLessThanOrEqual(OrderBookResult.asks[0][0]); 43 | }); 44 | 45 | it('should store and handle Orderbook Symbols', () => { 46 | const OrderBooks = new OrderBookStore(10); 47 | 48 | const symbol = 'BTCUSDT'; 49 | 50 | const round = 11; 51 | 52 | for (let i = 0; i < round; i++) { 53 | const asks: Order[] = [[100 * Math.random(), 2 * Math.random()]]; 54 | const bids: Order[] = [[100 * Math.random(), 2 * Math.random()]]; 55 | 56 | OrderBooks.updateOrderBook(symbol, asks, bids); 57 | } 58 | 59 | expect(OrderBooks.getSymbolList()).toStrictEqual(expect.any(Array)); 60 | expect(OrderBooks.hasOrderBook(symbol)).toBe(true); 61 | expect(OrderBooks.hasOrderBook('none')).toBe(false); 62 | expect(OrderBooks.getOrderBook(symbol)).toStrictEqual(expect.any(Object)); 63 | expect(OrderBooks.getOrderBook('none')).toBe(undefined); 64 | }); 65 | 66 | it('OrderBook Memory limit Test', () => { 67 | const symbol = 'BTCUSDT'; 68 | 69 | const SingleOrderBook = new Orderbook(symbol, 1000); 70 | 71 | const round = 1001; 72 | 73 | for (let i = 0; i < round; i++) { 74 | const asks: Order[] = [[8000 + i, 2 * Math.random()]]; 75 | const bids: Order[] = [[6000 + i, 2 * Math.random()]]; 76 | 77 | SingleOrderBook.updateOrderBook(asks, bids); 78 | } 79 | 80 | expect(SingleOrderBook.getOrderBook().asks.length).toBe(1000); 81 | }); 82 | 83 | it('OrderBookCleanup Test', () => { 84 | const symbol = 'BTCUSDT'; 85 | 86 | const SingleOrderBook = new Orderbook(symbol, 1000); 87 | 88 | const round = 1000000; 89 | 90 | for (let i = 0; i < round; i++) { 91 | const asks: Order[] = [[100 * Math.random(), 2 * Math.random()]]; 92 | const bids: Order[] = [[100 * Math.random(), 2 * Math.random()]]; 93 | 94 | SingleOrderBook.updateOrderBook(asks, bids); 95 | } 96 | 97 | SingleOrderBook.updateOrderBook([[90, 2]], [[90, 2]]); 98 | SingleOrderBook.updateOrderBook([[90, 2]], [[90, 2]]); 99 | SingleOrderBook.updateOrderBook([[90, 2]], [[90, 2]]); 100 | 101 | const OrderBookResult = SingleOrderBook.getOrderBook(); 102 | 103 | expect(OrderBookResult.bids[0][0]).toBeLessThanOrEqual(OrderBookResult.asks[0][0]); 104 | }); 105 | }); 106 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './orderbook_store'; 2 | export * from './orderbook'; 3 | -------------------------------------------------------------------------------- /src/orderbook.ts: -------------------------------------------------------------------------------- 1 | import { OrderbookData, Order } from './types'; 2 | import { processOrderbookUpdate } from './utils'; 3 | 4 | export class Orderbook { 5 | _data: OrderbookData; 6 | protected symbol: string; 7 | private memoryLimit: number; 8 | 9 | constructor(symbol = 'none', memoryLimit = 0) { 10 | this._data = { 11 | asks: [], 12 | bids: [], 13 | }; 14 | this.symbol = symbol; 15 | this.memoryLimit = memoryLimit; 16 | } 17 | 18 | public getOrderBook(): OrderbookData { 19 | return this._data; 20 | } 21 | 22 | public updateOrderBook(asks: Order[], bids: Order[]): void { 23 | const { memoryLimit } = this; 24 | const data = this._data; 25 | 26 | this._data = processOrderbookUpdate({ ...data }, asks, bids, memoryLimit); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/orderbook_store.ts: -------------------------------------------------------------------------------- 1 | import { OrderbookData, Order } from './types'; 2 | import { processOrderbookUpdate } from './utils'; 3 | 4 | export class OrderBookStore { 5 | _data: Map; 6 | private memoryLimit: number; 7 | 8 | constructor(memoryLimit = 0) { 9 | this._data = new Map(); 10 | this.memoryLimit = memoryLimit; 11 | } 12 | 13 | public getSymbolList(): string[] { 14 | return [...this._data.keys()]; 15 | } 16 | 17 | public hasOrderBook(symbol: string): boolean { 18 | return this._data.has(symbol); 19 | } 20 | 21 | public getOrderBook(symbol: string): OrderbookData | undefined { 22 | return this._data.get(symbol); 23 | } 24 | 25 | public updateOrderBook(symbol: string, asks: Order[], bids: Order[]): void { 26 | const { memoryLimit } = this; 27 | const data = this._data.get(symbol); 28 | 29 | if (data) { 30 | this._data.set(symbol, processOrderbookUpdate({ ...data }, asks, bids, memoryLimit)); 31 | return; 32 | } 33 | 34 | this._data.set(symbol, processOrderbookUpdate({ asks: [], bids: [] }, asks, bids, memoryLimit)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | /** [price, amount] */ 2 | export type Order = [number, number]; 3 | 4 | export interface OrderbookData { 5 | asks: Order[]; 6 | bids: Order[]; 7 | } 8 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import { Order, OrderbookData } from './types'; 2 | 3 | const updateIndex = (sortedArray: Order[], order: Order, index: number, memoryLimit = 0): void => { 4 | const price = order[0]; 5 | const amount = order[1]; 6 | 7 | if (index < sortedArray.length && sortedArray[index][0] === price) { 8 | if (amount === 0) { 9 | sortedArray.splice(index, 1); 10 | } else { 11 | sortedArray.splice(index, 1, order); 12 | } 13 | } else if (amount !== 0) { 14 | sortedArray.splice(index, 0, order); 15 | } 16 | 17 | if (memoryLimit !== 0 && sortedArray.length > memoryLimit) { 18 | sortedArray.splice(memoryLimit, sortedArray.length - memoryLimit); 19 | } 20 | }; 21 | 22 | const getSortedIndex = (array: Order[], price: number, inverse = false): number => { 23 | let low = 0; 24 | let high = array ? array.length : low; 25 | 26 | while (low < high) { 27 | const mid = (low + high) >>> 1; 28 | 29 | if ((!inverse && +array[mid][0] < +price) || (inverse && +array[mid][0] > +price)) { 30 | low = mid + 1; 31 | } else { 32 | high = mid; 33 | } 34 | } 35 | return low; 36 | }; 37 | 38 | const cleanOrderbookBid = (array: Order[], price: number): void => { 39 | for (let i = 0; i < array.length; i++) { 40 | if (price < array[i][0]) { 41 | array.splice(i, 1); 42 | } else { 43 | return; 44 | } 45 | } 46 | }; 47 | 48 | const cleanOrderbookAsk = (array: Order[], price: number): void => { 49 | for (let i = 0; i < array.length; i++) { 50 | if (price > array[i][0]) { 51 | array.splice(i, 1); 52 | } else { 53 | return; 54 | } 55 | } 56 | }; 57 | 58 | export const processOrderbookUpdate = ( 59 | data: OrderbookData, 60 | asks: Order[], 61 | bids: Order[], 62 | memoryLimit: number, 63 | ): OrderbookData => { 64 | for (const order of asks) { 65 | const price = Number(order[0]); 66 | const amount = Number(order[1]); 67 | 68 | updateIndex(data.asks, [price, amount], getSortedIndex(data.asks, price, false), memoryLimit); 69 | 70 | if (amount !== 0 && data.bids[0] && price < data.bids[0][0]) { 71 | cleanOrderbookBid(data.bids, price); 72 | } 73 | } 74 | 75 | for (const order of bids) { 76 | const price = Number(order[0]); 77 | const amount = Number(order[1]); 78 | 79 | updateIndex(data.bids, [price, amount], getSortedIndex(data.bids, price, true), memoryLimit); 80 | 81 | if (amount !== 0 && data.asks[0] && price > data.asks[0][0]) { 82 | cleanOrderbookAsk(data.asks, price); 83 | } 84 | } 85 | 86 | return data; 87 | }; 88 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "lib": ["es2017", "es7", "es6", "dom"], 5 | "declaration": true, 6 | "esModuleInterop": true, 7 | "allowSyntheticDefaultImports": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "target": "es6", 10 | "newLine": "lf", 11 | "noImplicitAny": true, 12 | "moduleResolution": "node", 13 | "sourceMap": true, 14 | "outDir": "./lib", 15 | "baseUrl": ".", 16 | "strict": true, 17 | "pretty": true, 18 | "removeComments": true 19 | }, 20 | "include": ["src"], 21 | "exclude": ["node_modules", "src/__test__", "lib"] 22 | } 23 | --------------------------------------------------------------------------------