Skip to content

Instantly share code, notes, and snippets.

@VictorTaelin
Created December 26, 2016 02:39
Show Gist options
  • Save VictorTaelin/b662b4d75561cb2acdeb21bf68421fc3 to your computer and use it in GitHub Desktop.
Save VictorTaelin/b662b4d75561cb2acdeb21bf68421fc3 to your computer and use it in GitHub Desktop.
module.exports = (function(){
function Book(baseCurrency, token){
var book = {};
book.offers = {};
book.offers[baseCurrency] = [];
book.offers[token] = [];
book.pair = [baseCurrency, token];
return book;
};
function offer(offer, book, debug){
var trades = [];
var offers = book.offers[offer.offerToken];
var asks = book.offers[offer.askToken];
if (debug)
console.log(
"buy "+offer.askToken+"; "+
"offer "+offer.offerAmount+" "+offer.offerToken+"; "+
"price "+offer.askPrice+" "+offer.offerToken+"/"+offer.askToken);
while (offer.offerAmount > 0 && asks.length > 0 && offer.askPrice >= 1/asks[asks.length-1].askPrice){
var ask = asks.pop(); // offer B, ask A
var dealPrice = 1/ask.askPrice; // A / B
var dealAmount = Math.min(offer.offerAmount, ask.offerAmount * dealPrice); // A
var trade = {
offerUser: offer.offerUser,
offerToken: offer.offerToken,
offerAmount: dealAmount,
askUser: ask.offerUser,
askToken: offer.askToken,
askAmount: dealAmount / dealPrice};
if (debug){
console.log("deal: "+dealPrice+" "+offer.offerToken+"/"+offer.askToken+" ("+(1/dealPrice)+")");
console.log("give "+trade.offerAmount+" "+trade.offerToken+" for "+trade.askAmount+" "+trade.askToken);
};
trades.push(trade);
offer.offerAmount -= trade.offerAmount;
ask.offerAmount -= trade.askAmount;
if (debug){
console.log("now offer "+JSON.stringify(offer));
console.log("now ask "+JSON.stringify(ask));
};
if (ask.offerAmount > 0)
book.offers[offer.askToken].push(ask);
};
if (offer.offerAmount > 0){
for (var i=0, l=offers.length; i<l; ++i){
if (offer && offer.askPrice < offers[i].askPrice){
offers.splice(i, 0, offer);
offer = null;
};
};
if (offer)
offers.push(offer);
};
return {book: book, trades: trades};
};
function sell(user, amount, price, book){
return offer({
offerUser: user,
offerToken: book.pair[1],
offerAmount: amount,
askToken: book.pair[0],
askPrice: 1/price},
book);
};
function buy(user, amount, price, book){
return offer({
offerUser: user,
offerToken: book.pair[0],
offerAmount: amount * price,
askToken: book.pair[1],
askPrice: price},
book);
};
function show(book){
function pad(str, len, rev){
while (str.length < len)
str = rev ? str+" " : " "+str;
return str.slice(0,len);
};
function num(num){
return pad(num === 0 ? "" : num.toFixed(8), 14, 0);
};
var str = "";
str += "[ " + book.pair[0] + " / " + book.pair[1] + " MARKET ]\n";
str += "| BUY ORDERS | SELL ORDERS |\n";
str += "| USER | AMOUNT | PRICE | USER | AMOUNT | PRICE |\n";
var as = book.offers[book.pair[0]].slice(0);
var bs = book.offers[book.pair[1]].slice(0);
for (var a = as.pop(), b = bs.pop(); a || b; a = as.pop(), b = bs.pop()){
str += "| "+pad(a ? a.offerUser : "",8,1)+" ";
str += "| "+num(a ? (a.offerAmount/a.askPrice) : 0)+" ";
str += "| "+num(a ? a.askPrice : 0)+" ";
str += "| "+pad(b ? b.offerUser : "",8,1)+" ";
str += "| "+num(b ? b.offerAmount : 0)+" ";
str += "| "+num(b ? (1/b.askPrice) : 0)+" |\n";
};
return str;
};
return {
Book: Book,
sell: sell,
buy: buy,
show: show};
})();
@tloriato
Copy link

Hello @MaiaVictor , very nice git.

I was wondering how could I test it using node? Thank you.

@VictorTaelin
Copy link
Author

VictorTaelin commented Mar 4, 2017

const Book = require("./book.js");

// Create a new book that buys/sells ETH with price in BTC (base currency).
let book = Book.Book("btc", "eth");

// To add offers, just call Book.buy(user, amount, price, book). Modifies the book.
console.log("Adding offers.");
let offer0 = Book.buy("tloriato", 100, 0.01, book); // tloriato wants to buy 100 eth at B0.01
let offer1 = Book.sell("srpx", 100, 0.02, book); // srpx wants to sell 100 eth at B0.02
let offer2 = Book.sell("gandhi", 10, 0.01, book); // gandhi wants to sell 10 eth at B0.01
console.log("");

// Each offer added can trigger N trades, depending on the book state.
// You can find what trades an offer triggered with offer.trades.
// You can then use that object to add/subtract to your user's balances.
console.log("Getting matches (trades).");
console.log("- offer 0 has trades:", offer0.trades); // output empty (no trade on offer0)
console.log("- offer 1 has trades:", offer1.trades); // output empty (no trade on offer1)
console.log("- offer 2 has trades:", offer2.trades); // output is: [ { offerUser: 'gandhi', offerToken: 'eth', offerAmount: 10, askUser: 'tloriato', askToken: 'btc', askAmount: 0.1 } ]
                                                     // that means gandhi sold 10 eth to tloriato for 0.1 btc
console.log("");

// you can pretty print it with the traditional "exchange book UI"
// you can modify this function if you want to render your book as HTML (for a React site)
console.log("Pretty print of Book's state:");
console.log(Book.show(book));
console.log("");

// book itself is just a JSON, so you can put it inside your JSON anywhere you wnt
console.log("JSON of Book:");
console.log(JSON.stringify(book, null, 2));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment