Created
December 26, 2016 02:39
-
-
Save VictorTaelin/b662b4d75561cb2acdeb21bf68421fc3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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}; | |
})(); |
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
Hello @MaiaVictor , very nice git.
I was wondering how could I test it using node? Thank you.