
Company News
/Security News
Socket Selected for OpenAI's Cybersecurity Grant Program
Socket is an initial recipient of OpenAI's Cybersecurity Grant Program, which commits $10M in API credits to defenders securing open source software.
hft-limit-order-book
Advanced tools
:star: Star me on GitHub — it motivates me a lot!
Ultra-fast matching engine written in TypeScript
post-only limit orderMachine: ASUS ExpertBook, 11th Gen Intel(R) Core(TM) i7-1165G7, 2.80Ghz, 16GB RAM, Node.js v18.4.0.
Install with npm:
npm install hft-limit-order-book --save
Install with yarn:
yarn add hft-limit-order-book
To start using order book you need to import OrderBook and create new instance:
import { OrderBook } from 'hft-limit-order-book'
const ob = new OrderBook()
Then you'll be able to use next primary functions:
ob.createOrder({ type: 'limit' | 'market', side: 'buy' | 'sell', size: number, price?: number, id?: string, postOnly?: boolean, timeInForce?: 'GTC' | 'FOK' | 'IOC' })
ob.limit({ id: string, side: 'buy' | 'sell', size: number, price: number, postOnly?: boolean, timeInForce?: 'GTC' | 'FOK' | 'IOC' })
ob.market({ side: 'buy' | 'sell', size: number })
ob.modify(orderID: string, { side: 'buy' | 'sell', size: number, price: number })
ob.cancel(orderID: string)
The version v6.1.0 introduced support for Conditional Orders Stop Market, Stop Limit and OCO. Even though the test coverage for these new features is at 100%, they are not yet considered stable because they have not been tested with real-world scenarios. For this reason, if you want to use conditional orders, you need to instantiate the order book with the experimentalConditionalOrders option set to true.
import { OrderBook } from 'hft-limit-order-book'
const ob = new OrderBook({ experimentalConditionalOrders: true })
ob.createOrder({ type: 'stop_limit' | 'stop_market' | 'oco', side: 'buy' | 'sell', size: number, price?: number, id?: string, stopPrice?: number, timeInForce?: 'GTC' | 'FOK' | 'IOC', stopLimitTimeInForce?: 'GTC' | 'FOK' | 'IOC' })
ob.stopLimit({ id: string, side: 'buy' | 'sell', size: number, price: number, stopPrice: number, timeInForce?: 'GTC' | 'FOK' | 'IOC' })
ob.stopMarket({ side: 'buy' | 'sell', size: number, stopPrice: number })
ob.oco({ id: string, side: 'buy' | 'sell', size: number, price: number, stopPrice: number, stopLimitPrice: number, timeInForce?: 'GTC' | 'FOK' | 'IOC', stopLimitTimeInForce?: 'GTC' | 'FOK' | 'IOC' })
To add an order to the order book you can call the general createOrder() function or calling the underlying limit(), market(), stopLimit(), stopMarket() or oco() functions
// Create limit order
ob.createOrder({ type: 'limit', side: 'buy' | 'sell', size: number, price: number, id: string, postOnly?: boolean, timeInForce?: 'GTC' | 'FOK' | 'IOC' })
// Create market order
ob.createOrder({ type: 'market', side: 'buy' | 'sell', size: number })
// Create stop limit order
ob.createOrder({ type: 'stop_limit', side: 'buy' | 'sell', size: number, price: number, id: string, stopPrice: number, timeInForce?: 'GTC' | 'FOK' | 'IOC' })
// Create stop market order
ob.createOrder({ type: 'stop_market', side: 'buy' | 'sell', size: number, stopPrice: number })
// Create OCO order
ob.createOrder({ type: 'oco', side: 'buy' | 'sell', size: number, stopPrice: number, stopLimitPrice: number, timeInForce?: 'GTC' | 'FOK' | 'IOC', stopLimitTimeInForce?: 'GTC' | 'FOK' | 'IOC' })
/**
* Create a limit order. See {@link LimitOrderOptions} for details.
*
* @param options
* @param options.side - `sell` or `buy`
* @param options.id - Unique order ID
* @param options.size - How much of currency you want to trade in units of base currency
* @param options.price - The price at which the order is to be fullfilled, in units of the quote currency
* @param options.postOnly - When `true` the order will be rejected if immediately matches and trades as a taker. Default is `false`
* @param options.timeInForce - Time-in-force type supported are: GTC, FOK, IOC. Default is GTC
* @returns An object with the result of the processed order or an error. See {@link IProcessOrder} for the returned data structure
*/
ob.limit({ side: 'buy' | 'sell', id: string, size: number, price: number, postOnly?: boolean, timeInForce?: 'GTC' | 'FOK' | 'IOC' })
For example:
ob.limit({ side: "sell", id: "uniqueID", size: 55, price: 100 })
asks: 110 -> 5 110 -> 5
100 -> 1 100 -> 56
-------------- -> --------------
bids: 90 -> 5 90 -> 5
80 -> 1 80 -> 1
done - null
partial - null
ob.limit({ side: "buy", id: "uniqueID", size: 7, price: 120 })
asks: 110 -> 5
100 -> 1
-------------- -> --------------
bids: 90 -> 5 120 -> 1
80 -> 1 90 -> 5
80 -> 1
done - 2 (or more orders)
partial - uniqueID order
ob.limit({ side: "buy", id: "uniqueID", size: 3, price: 120 })
asks: 110 -> 5
100 -> 1 110 -> 3
-------------- -> --------------
bids: 90 -> 5 90 -> 5
80 -> 1 80 -> 1
done - 1 order with 100 price, (may be also few orders with 110 price) + uniqueID order
partial - 1 order with price 110
/**
* Create a market order. See {@link MarketOrderOptions} for details.
*
* @param options
* @param options.side - `sell` or `buy`
* @param options.size - How much of currency you want to trade in units of base currency
* @returns An object with the result of the processed order or an error. See {@link IProcessOrder} for the returned data structure
*/
ob.market({ side: 'buy' | 'sell', size: number })
For example:
ob.market({ side: 'sell', size: 6 })
asks: 110 -> 5 110 -> 5
100 -> 1 100 -> 1
-------------- -> --------------
bids: 90 -> 5 80 -> 1
80 -> 2
done - 2 (or more orders)
partial - 1 order with price 80
quantityLeft - 0
ob.market({ side: 'buy', size: 10 })
asks: 110 -> 5
100 -> 1
-------------- -> --------------
bids: 90 -> 5 90 -> 5
80 -> 1 80 -> 1
done - 2 (or more orders)
partial - null
quantityLeft - 4
/**
* Create a stop limit order. See {@link StopLimitOrderOptions} for details.
*
* @param options
* @param options.side - `sell` or `buy`
* @param options.id - Unique order ID
* @param options.size - How much of currency you want to trade in units of base currency
* @param options.price - The price at which the order is to be fullfilled, in units of the quote currency
* @param options.stopPrice - The price at which the order will be triggered.
* @param options.timeInForce - Time-in-force type supported are: GTC, FOK, IOC. Default is GTC
* @returns An object with the result of the processed order or an error. See {@link IProcessOrder} for the returned data structure
*/
ob.stopLimit({ side: 'buy' | 'sell', id: string, size: number, price: number, stopPrice: number, timeInForce?: 'GTC' | 'FOK' | 'IOC' })
/**
* Create a stop market order. See {@link StopMarketOrderOptions} for details.
*
* @param options
* @param options.side - `sell` or `buy`
* @param options.size - How much of currency you want to trade in units of base currency
* @param options.stopPrice - The price at which the order will be triggered.
* @returns An object with the result of the processed order or an error. See {@link IProcessOrder} for the returned data structure
*/
ob.stopMarket({ side: 'buy' | 'sell', size: number, stopPrice: number })
/**
* Create an OCO (One-Cancels-the-Other) order.
* OCO order combines a `stop_limit` order and a `limit` order, where if stop price
* is triggered or limit order is fully or partially fulfilled, the other is canceled.
* Both orders have the same `side` and `size`. If you cancel one of the orders, the
* entire OCO order pair will be canceled.
*
* For BUY orders the `stopPrice` must be above the current price and the `price` below the current price
* For SELL orders the `stopPrice` must be below the current price and the `price` above the current price
*
* See {@link OCOOrderOptions} for details.
*
* @param options
* @param options.side - `sell` or `buy`
* @param options.id - Unique order ID
* @param options.size - How much of currency you want to trade in units of base currency
* @param options.price - The price of the `limit` order at which the order is to be fullfilled, in units of the quote currency
* @param options.stopPrice - The price at which the `stop_limit` order will be triggered.
* @param options.stopLimitPrice - The price of the `stop_limit` order at which the order is to be fullfilled, in units of the quote currency.
* @param options.timeInForce - Time-in-force of the `limit` order. Type supported are: GTC, FOK, IOC. Default is GTC
* @param options.stopLimitTimeInForce - Time-in-force of the `stop_limit` order. Type supported are: GTC, FOK, IOC. Default is GTC
* @returns An object with the result of the processed order or an error. See {@link IProcessOrder} for the returned data structure
*/
ob.oco({ side: 'buy' | 'sell', id: string, size: number, price: number, stopPrice: number, stopLimitPrice: number, timeInForce?: 'GTC' | 'FOK' | 'IOC', stopLimitTimeInForce?: 'GTC' | 'FOK' | 'IOC' })
/**
* Modify an existing order with given ID. When an order is modified by price or quantity,
* it will be deemed as a new entry. Under the price-time-priority algorithm, orders are
* prioritized according to their order price and order time. Hence, the latest orders
* will be placed at the back of the matching order queue.
*
* @param orderID - The ID of the order to be modified
* @param orderUpdate - An object with the modified size and/or price of an order. The shape of the object is `{size, price}`.
* @returns An object with the result of the processed order or an error
*/
ob.modify(orderID: string, { size: number, price: number })
For example:
ob.limit({ side: "sell", id: "uniqueID", size: 55, price: 100 })
asks: 110 -> 5 110 -> 5
100 -> 1 100 -> 56
-------------- -> --------------
bids: 90 -> 5 90 -> 5
80 -> 1 80 -> 1
// Modify the size from 55 to 65
ob.modify("uniqueID", { size: 65 })
asks: 110 -> 5 110 -> 5
100 -> 56 100 -> 66
-------------- -> --------------
bids: 90 -> 5 90 -> 5
80 -> 1 80 -> 1
// Modify the price from 100 to 110
ob.modify("uniqueID", { price: 110 })
asks: 110 -> 5 110 -> 70
100 -> 66 100 -> 1
-------------- -> --------------
bids: 90 -> 5 90 -> 5
80 -> 1 80 -> 1
/**
* Remove an existing order with given ID from the order book
*
* @param orderID - The ID of the order to be removed
* @returns The removed order if exists or `undefined`
*/
ob.cancel(orderID: string)
For example:
ob.cancel("myUniqueID-Sell-1-with-100")
asks: 110 -> 5
100 -> 1 110 -> 5
-------------- -> --------------
bids: 90 -> 5 90 -> 5
80 -> 1 80 -> 1
The orderbook can be initialized with the following options by passing them to the constructor:
A snapshot represents the state of the order book at a specific point in time. It includes the following properties:
asks: List of ask orders, each with a price and a list of associated orders.bids: List of bid orders, each with a price and a list of associated orders.ts: A timestamp indicating when the snapshot was taken, in Unix timestamp format.lastOp: The id of the last operation included in the snapshotSnapshots are crucial for restoring the order book to a previous state. The orderbook can restore from a snapshot before processing any journal logs, ensuring consistency and accuracy.
After taking the snapshot, you can safely remove all logs preceding the lastOp id.
const ob = new OrderBook({ enableJournaling: true})
// after every order save the log to the database
const order = ob.limit({ side: "sell", id: "uniqueID", size: 55, price: 100 })
await saveLog(order.log)
// ... after some time take a snapshot of the order book and save it on the database
const snapshot = ob.snapshot()
await saveSnapshot(snapshot)
// If you want you can safely remove all logs preceding the `lastOp` id of the snapshot, and continue to save each subsequent log to the database
await removePreviousLogs(snapshot.lastOp)
// On server restart get the snapshot and logs from the database and initialize the order book
const logs = await getLogs()
const snapshot = await getSnapshot()
const ob = new OrderBook({ snapshot, journal: log, enableJournaling: true })
The journal option expects an array of journal logs that you can get by setting enableJournaling to true. When the journal is provided, the order book will replay all the operations, bringing the order book to the same state as the last log.
// Assuming 'logs' is an array of log entries retrieved from the database
const logs = await getLogs()
const ob = new OrderBook({ journal: logs, enableJournalLog: true })
By combining snapshots with journaling, you can effectively restore and audit the state of the order book.
enabledJournaling is a configuration setting that determines whether journaling is enabled or disabled. When enabled, the property log will be added to the body of the response for each operation. The logs must be saved to the database and can then be used when a new instance of the order book is instantiated.
const ob = new OrderBook({ enableJournaling: true }) // false by default
// after every order save the log to the database
const order = ob.limit({ side: "sell", id: "uniqueID", size: 55, price: 100 })
await saveLog(order.log)
Build production (distribution) files in your dist folder:
npm run build
To run all the unit-test
npm run test
Run testing coverage
npm run test:cov
Before running benchmark, make sure to have built the source code with npm run build first
npm run bench
I would greatly appreciate any contributions to make this project better. Please make sure to follow the below guidelines before getting your hands dirty.
If this project help you reduce time to develop, you can give me a cup of coffee 🍵 :)
TXArNxsq2Ee8Jvsk45PudVio52Joiq1yEe1GYDVSAQNgG7MFhV5bk15XJy3qoE4NFenp0xf673ee099be8129ec05e2f549d96ebea24ac5d970xf673ee099be8129ec05e2f549d96ebea24ac5d970xf673ee099be8129ec05e2f549d96ebea24ac5d97Copyright Andrea Fassina, Licensed under MIT.
FAQs
Node.js Lmit Order Book for high-frequency trading (HFT).
The npm package hft-limit-order-book receives a total of 307 weekly downloads. As such, hft-limit-order-book popularity was classified as not popular.
We found that hft-limit-order-book demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Company News
/Security News
Socket is an initial recipient of OpenAI's Cybersecurity Grant Program, which commits $10M in API credits to defenders securing open source software.

Security News
Socket CEO Feross Aboukhadijeh joins 10 Minutes or Less, a podcast by Ali Rohde, to discuss the recent surge in open source supply chain attacks.

Research
/Security News
Campaign of 108 extensions harvests identities, steals sessions, and adds backdoors to browsers, all tied to the same C2 infrastructure.