Last active
July 15, 2019 05:56
-
-
Save davesag/e658bd0cbcc7103e019c002fe18cbf31 to your computer and use it in GitHub Desktop.
Realtime Buy and Sell orders on Independent Reserve
This file contains 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
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<title>Independent Reserve WebSockets Demo</title> | |
<script> | |
const SORTS = { | |
buy: (a, b) => b - a, | |
sell: (a, b) => a - b | |
} | |
const BASE = 'wss://websockets.independentreserve.com/' | |
const reduce = (oldState, { crypto, price, action }) => { | |
const newState = { ...oldState } | |
const nc = newState[crypto] | |
const oc = oldState[crypto] | |
nc[action] = oc[action].includes(price) | |
? oc[action] | |
: [ ...oc[action], price].sort(SORTS[action]).slice(0, 2) | |
nc.spread = (nc.sell.length && nc.buy.length) | |
? (nc.sell[0] - nc.buy[0]) | |
: 0 | |
return newState | |
} | |
const aud = number => number.toLocaleString('en-AU', { | |
style: 'currency', | |
currency: 'AUD', | |
currencyDisplay: 'symbol' | |
}) | |
const writeState = state => { | |
Object.keys(state).forEach(crypto => { | |
Object.keys(state[crypto]).forEach(action => { | |
const field = state[crypto][action] | |
const price = Array.isArray(field) ? field[0] : field | |
const cell = document.getElementById(`${action}-${crypto}`) | |
cell.innerHTML = price > 0 | |
? aud(price) | |
: '' | |
}) | |
}) | |
} | |
const writeStatus = status => { | |
document.getElementById('status').innerText = status | |
} | |
const run = () => { | |
const CURRENCIES = Array | |
.from(document.querySelectorAll('th.currency').values()) | |
.map(n => n.textContent.toLowerCase()) | |
const INITIAL_STATE = CURRENCIES.reduce((acc, elem) => { | |
acc[elem] = { | |
buy: [], | |
sell: [], | |
spread: 0 | |
} | |
return acc | |
}, {}) | |
const subscribe = CURRENCIES.map(c => `orderbook-${c}-aud`).join(',') | |
const webSocket = new WebSocket(`${BASE}?subscribe=${subscribe}`) | |
let state = { ...INITIAL_STATE } | |
let timer | |
webSocket.onopen = () => { | |
console.log('Connected') | |
writeStatus('Connected') | |
timer = setInterval(() => { | |
writeState(state) | |
}, 1000) | |
} | |
webSocket.onerror = err => { | |
console.error('Error', err) | |
writeStatus('Error - Reload to re-connect') | |
clearInterval(timer) | |
} | |
webSocket.onclose = () => { | |
console.log('Disconnected') | |
writeStatus('Disconnected - Reload to re-connect') | |
clearInterval(timer) | |
} | |
webSocket.onmessage = function (event) { | |
const json = JSON.parse(event.data) | |
const { Event: evt, Data: data } = json | |
if (evt === 'NewOrder') { | |
const { Pair: pair, OrderType: type, Price: price, Volume: volume } = data | |
const [crypto, fiat] = pair.split('-') | |
const action = type === 'LimitBid' | |
? 'buy' | |
: type === 'LimitOffer' | |
? 'sell' | |
: undefined | |
if (action) { | |
state = reduce(state, { crypto, price, action }) | |
const status = `${action} ${volume.toFixed(4)} ${crypto.toUpperCase()} for ${aud(price)}` | |
writeStatus(`Order: ${status}`) | |
} else { | |
writeStatus(`Ignoring Order Type ${type}`) | |
} | |
} | |
} | |
} | |
window.onload = run | |
</script> | |
<style> | |
body { | |
font-family: Sans-serif; | |
} | |
table { | |
width: 400px; | |
} | |
table, th, td { | |
border: 1px solid black; | |
border-collapse: collapse; | |
font-family: Sans-serif; | |
} | |
.currency { | |
font-family: monospace; | |
text-align: right; | |
} | |
th.currency { | |
width: 40px; | |
padding-right: 5px; | |
} | |
td.currency { | |
width: 120px; | |
padding-right: 2px; | |
} | |
#status { | |
margin-top: 10px; | |
font-family: monospace; | |
} | |
#credits { | |
margin-top: 10px; | |
} | |
#credits p { | |
padding: 2px 0 0 0; | |
margin: 0; | |
font-size: x-small; | |
} | |
</style> | |
</head> | |
<body> | |
<h3>Independent Reserve — Activity (AUD)</h3> | |
<p>Realtime buy and sell orders on <a href="https://www.independentreserve.com/invite/AJNEHL">Independent Reserve</a>.</p> | |
<table> | |
<thead> | |
<tr> | |
<th></th> | |
<th>Highest Buy</th> | |
<th>Lowest Sell</th> | |
<th>Spread</th> | |
</tr> | |
</thead> | |
<tbody> | |
<tr> | |
<th class="currency">Eth</th> | |
<td id="buy-eth" class="currency"></td> | |
<td id="sell-eth" class="currency"></td> | |
<td id="spread-eth" class="currency"></td> | |
</tr> | |
<tr> | |
<th class="currency">Xbt</th> | |
<td id="buy-xbt" class="currency"></td> | |
<td id="sell-xbt" class="currency"></td> | |
<td id="spread-xbt" class="currency"></td> | |
</tr> | |
<tr> | |
<th class="currency">Omg</th> | |
<td id="buy-omg" class="currency"></td> | |
<td id="sell-omg" class="currency"></td> | |
<td id="spread-omg" class="currency"></td> | |
</tr> | |
<tr> | |
<th class="currency">Xlm</th> | |
<td id="buy-xlm" class="currency"></td> | |
<td id="sell-xlm" class="currency"></td> | |
<td id="spread-xlm" class="currency"></td> | |
</tr> | |
</tbody> | |
</table> | |
</body> | |
<div id="status"></div> | |
<div id="credits"> | |
<p> | |
Written by | |
<a href="https://about.me/davesag">Dave Sag</a> | |
using Independent Reserve's | |
<a href="https://github.com/independentreserve/websockets">websockets dcoumentation</a>. | |
</p> | |
<p> | |
See also the | |
<tt><a href="https://github.com/davesag/ir-api">ir-api</a></tt> | |
project on GitHub. | |
</p> | |
</div> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
See it working at https://codepen.io/davesag/details/KjYmoW