Coder Social home page Coder Social logo

fasenderos / nodejs-order-book Goto Github PK

View Code? Open in Web Editor NEW
131.0 2.0 31.0 3.32 MB

Ultra-fast Node.js Order Book written in TypeScript for high-frequency trading (HFT) :rocket::rocket:

Home Page: https://github.com/fasenderos/hft-limit-order-book

License: MIT License

JavaScript 4.81% TypeScript 95.19%
exchange hft hft-trading limit-order-book matching-algorithm matching-engine nodejs order-book orderbook trading typescript low-latency performance trading-algorithms nodejs-order-book

nodejs-order-book's Introduction

NPM Version Package License NPM Downloads CircleCI Codecov Built with TypeScript

Node.js Order Book

Ultra-fast Node.js Order Book written in TypeScript for high-frequency trading (HFT) 🚀🚀

⭐ Star me on GitHub — it motivates me a lot!

Table of Contents

Features

  • Standard price-time priority
  • Supports both market and limit orders
  • Supports post-only limit order
  • Supports conditional orders Stop Limit, Stop Market and OCO Experimental
  • Supports time in force GTC, FOK and IOC
  • Supports order cancelling
  • Supports order price and/or size updating
  • Snapshot and journaling functionalities for restoring the order book during server startup
  • High performance (above 300k trades per second)

Machine: ASUS ExpertBook, 11th Gen Intel(R) Core(TM) i7-1165G7, 2.80Ghz, 16GB RAM, Node.js v18.4.0.

nodejs-order-book-benchmark

Installation

Install with npm:

npm install nodejs-order-book

Install with yarn:

yarn add nodejs-order-book

Install with pnpm:

pnpm add nodejs-order-book

Usage

To start using order book you need to import OrderBook and create new instance:

import { OrderBook } from 'nodejs-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)

Conditional Orders Experimental

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 'nodejs-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' })

About primary functions

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 Order

// 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 Limit Order

/**
 * 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 Market Order

/**
 * 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 Stop Limit Order

/**
 * 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 Stop Market Order

/**
 * 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 OCO (One-Cancels-the-Other) Order

/**
 * 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

/**
 * 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

Cancel Order

/**
 * 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

Order Book Options

The orderbook can be initialized with the following options by passing them to the constructor:

Snapshot

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 snapshot

Snapshots 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 })

Journal Logs

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.

Enable Journaling

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)

Development

Build

Build production (distribution) files in your dist folder:

npm run build

Testing

To run all the unit-test

npm run test

Coverage

Run testing coverage

npm run test:cov

Benchmarking

Before running benchmark, make sure to have built the source code with npm run build first

npm run bench

Contributing

I would greatly appreciate any contributions to make this project better. Please make sure to follow the below guidelines before getting your hands dirty.

  1. Fork the repository
  2. Create your branch (git checkout -b my-branch)
  3. Commit any changes to your branch
  4. Push your changes to your remote branch
  5. Open a pull request

Donation

If this project help you reduce time to develop, you can give me a cup of coffee 🍵 :)

  • USDT (TRC20): TXArNxsq2Ee8Jvsk45PudVio52Joiq1yEe
  • BTC: 1GYDVSAQNgG7MFhV5bk15XJy3qoE4NFenp
  • BTC (BEP20): 0xf673ee099be8129ec05e2f549d96ebea24ac5d97
  • ETH (ERC20): 0xf673ee099be8129ec05e2f549d96ebea24ac5d97
  • BNB (BEP20): 0xf673ee099be8129ec05e2f549d96ebea24ac5d97

License

Copyright Andrea Fassina, Licensed under MIT.

nodejs-order-book's People

Contributors

dependabot[bot] avatar fasenderos avatar andreafassina avatar vanodevium avatar afshinkoohsari avatar ipod1g avatar

Stargazers

Tanishq avatar  avatar Mateo avatar Async avatar womeik avatar Maxime Golfier avatar Cristiano Belloni avatar BearMett avatar  avatar Eshaan Bansal avatar Saint Asky avatar  avatar Pierre-Edouard Galtier avatar Nikku kumar avatar  avatar Nguyen Quang Truong avatar Hai Nguyen avatar Miroslav avatar Dennoh Peter avatar  avatar Moein Rahimi  avatar Sebastian Christiansen avatar Pratik Agarwal avatar  avatar Win Raguini avatar Mutalisk avatar Long Vu avatar Yagnadeep avatar hossein najafi avatar Usman Danbaba avatar Andrew avatar Kai Li avatar Dung LT. avatar Behrouz Sameny avatar  avatar Success Ologunsua avatar tcosnr avatar  avatar Richard Barnes avatar  avatar Jad avatar  avatar Thai Duong Ng 春風 20 avatar  avatar 0x-Mr.7i74N avatar  avatar Tatenda Bwerinofa avatar corektion avatar Dong A. avatar  avatar Nam Huynh avatar Siddharth Kumar avatar Geoffrey YuHasker avatar  avatar  avatar Saeed avatar yassine avatar fri tol avatar  avatar hashus avatar  avatar  avatar Jimmy Yeung avatar Paul K avatar Mark Tsyrulnyk avatar Ali Torki avatar Lucas avatar Write Int avatar baiyijie avatar  avatar  avatar  avatar Md Hasanuzzaman avatar Rodrigo Torres avatar Phureewat A avatar jinczing avatar Mackenzie Baksh avatar Erdem Alpay avatar  avatar nilux avatar Newlife Marangwanda avatar  avatar  avatar damondd avatar  avatar Rishikesh Chandra avatar Bader  avatar H Zhang avatar  avatar  avatar ZK Tam avatar  avatar Abdul Maajid avatar  avatar Ramy al-Sharif avatar Andrea Dito avatar Jakub Zając avatar  avatar Gui avatar Marcus Lee avatar

Watchers

Aleks Lozovyuk avatar  avatar

nodejs-order-book's Issues

Order: traderID

First of all, thanks for your great work!


Created orders have no indication of who created them. It follows that I, as a trader, can buy from myself or sell to myself. It seems to me that this is not entirely logical.

I think it would be great to add a Trader ID for each order and just skip orders with the same Trader ID in the matching process.

TypeError: Cannot read properties of undefined (reading 'toString') on init OrderBook

this.orderbook = new OrderBook({snapshot: snapshot.snapshot, enableJournaling: true});
on create orderbook got an error:

TypeError: Cannot read properties of undefined (reading 'toString')
at OrderSide.append (/Users/una/Desktop/tests/matching/node_modules/hft-limit-order-book/dist/cjs/orderside.js:44:34)
at OrderBook.restoreSnapshot (/Users/una/Desktop/tests/matching/node_modules/hft-limit-order-book/dist/cjs/orderbook.js:284:32)
at new OrderBook (/Users/una/Desktop/tests/matching/node_modules/hft-limit-order-book/dist/cjs/orderbook.js:518:18)

snapshot: {"snapshot":{"bids":[{"price":30,"orders":["{"id":"14:22:1720293920736","side":"buy","origSize":1,"size":1,"price":30,"time":1720293920736,"isMaker":true}","{"id":"14:22:1720293921301","side":"buy","origSize":1,"size":1,"price":30,"time":1720293921301,"isMaker":true}"]}],"asks":[{"price":33,"orders":["{"id":"14:22:1720293904645","side":"sell","origSize":1,"size":1,"price":33,"time":1720293904646,"isMaker":true}","{"id":"14:22:1720293912873","side":"sell","origSize":1,"size":1,"price":33,"time":1720293912873,"isMaker":true}","{"id":"14:22:1720293913076","side":"sell","origSize":1,"size":1,"price":33,"time":1720293913076,"isMaker":true}"]}],"ts":1720293921302,"lastOp":5}}

how to fix pls?

buyOrderCanBeFilled/sellOrderCanBeFilled optimization

Since the OrderSide already has its own volume value, it would be good to first check whether the volume is in principle sufficient for the order.
I think it will speed up the check a bit.

Example:

  buyOrderCanBeFilled(orderSide: OrderSide, size: number, price: number) {

    // THIS IS PRE-CHECK
    if (orderSide.volume() < size) {
      return false
    }

    let cumulativeSize = 0
    orderSide.priceTree().forEach((_key, priceLevel) => {
      if (price >= priceLevel.price() && cumulativeSize < size) {
        cumulativeSize += priceLevel.volume()
      } else {
        return true // break the loop
      }
    })
    return cumulativeSize >= size
  }

Simple test reveal bug

Describe the bug

Matching a sell to multiple buys does not produced the right results.

To Reproduce

lob.createOrder("limit", "buy", 100, 1.2, "A0");
lob.createOrder("limit", "buy", 100, 1.2, "A1");
console.log(lob.orders, "sell", lob.asks.toString(),"buy", lob.bids.toString() )
//sell buy
//1.2 -> 200
lob.createOrder("limit", "sell", 309, 1.2, "B0");
console.log(lob.orders, "sell", lob.asks.toString(),"buy", lob.bids.toString() )
//sell buy
//1.2 -> -9

Expected behavior

Should output this in the asks
//sell
//1.2 -> 109

How I create orderbook UI with your lib data

Hii, I am a beginner in blockchain & trading. I want to create an order book ui like this:-

Screenshot 2023-05-21 at 5 28 12 PM

This is Binance order ui

I found some data in your library functions

console.log('bids', book.bids);
console.log('asks', book.asks);
console.log('depth', book.depth());

please anyone guide me how i create and manage this.

Question: market buy quantity

When a user makes a market order to buy some symbol, the exchange as a balance controller needs to freeze the user's money. But the market order does not have a price, and of course I do not know what amount to freeze.

In many systems, I noticed a good solution to this issue: for market buy orders, they accept the quantity in the quote currency (BTC/USD as base/quote, so they received quantity in USD), which allows me to correctly calculate the order book and freeze the excess money on the balance sheet.

Question: maybe you have some other solution or you can explain how to freeze money correctly if it is specified in the base currency.

For context: let's say I use your orderbook using asynchronous queues (kafka or nats). If I don't know what money to freeze, the user will have the option of double spending. On another side, I can check result and cancel market order but there are already fulfilled limit orders which are deleted from orderbook.

Thanks!

v6 Conditional Orders (Help Wanted)

I'm excited to announce that the new version introduces conditional orders: Stop Limit and Stop Market. While the test coverage for these new features is at 100%, I'm not yet considering them stable. I kindly request the community's help in testing these features with real-world scenarios.

Your feedback is invaluable in identifying any potential issues and ensuring the reliability of these functionalities. Please report any bugs or unexpected behaviors you encounter.

Thank you for your support and contribution to improving our project!

v6 Conditional Orders - Stop Limit, Stop Market and OCO orders

I'm excited to announce that the new version introduces conditional orders: Stop Limit and Stop Market. While the test coverage for these new features is at 100%, I'm not yet considering them stable. I kindly request the community's help in testing these features with real-world scenarios.

Your feedback is invaluable in identifying any potential issues and ensuring the reliability of these functionalities. Please report any bugs or unexpected behaviors you encounter.

Thank you for your support and contribution to improving this project!

Modifying the order price should run the matching process

Describe the bug

Hi,
After a user modifies an order price, the updated order should be matched with other orders in the book.

To Reproduce

limit("sell", "id1", 1, 200);
limit("buy", "id2", 1, 100);
modify("id2", { side: "buy", size: 1, price: 200})

Result:
asks: 200 -> 1
--------------  
bids: 200 -> 1

Expected behavior

Empty order book

Recover order book data when application restarts

I see your package used invertase/denque (stored in memory). My orders data has been saved on the database (application layer)

When my application(server) is restarted, how can I synchronize order data from my database with your package?

Stupid thing I thought of:

const lob = new OrderBook();
const orders = DB.table('orders').where('status', 'pending').all();
for order of orders {
   const result = lob.createOrder(order.type, order.side, order.size, order.price, order.id)
  // do something
}

But when the data is large, this is not feasible and unnecessary.
Any answer can help me, thanks

How to lock user balance on market order

Hello, please help me with this scenario
Pair Matic/USD
wallet balance of user1 is 10 USD
wallet balance of user2 is 5 USD

User1 want to sell 10 Matic at price of 1 USD
User2 place a MARKET order to buy 10 Matic but he use has balance of 5 USD.

How to stop this order and process according to wallet balance

Discussion: canceled orders

If the order has a FOK, then it is not quite an error when it isn't fulfilled, it is simply a canceled order.

I have an idea: to add another property to the response, canceled orders, where are placed those orders that were canceled for several reasons:

  • FOK and IOC
  • OCO orders
  • canceled by user's decision

Let's discuss?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.