Skip to content

Instantly share code, notes, and snippets.

@joshualyon
Last active November 3, 2021 19:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joshualyon/ebd2f0886f38d71faf3dbc5bb0c000f3 to your computer and use it in GitHub Desktop.
Save joshualyon/ebd2f0886f38d71faf3dbc5bb0c000f3 to your computer and use it in GitHub Desktop.
Bitstamp Custom Tile (Realtime Socket)
<script src="https://unpkg.com/vue@next"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.21.1/axios.min.js"></script>
<div id="app">
<div class="title">{{channel}}</div>
<span class="price">{{formattedPrice}}</span>
<div class="connection-status">{{connectionStatus}}</div>
</div>
<style>
html, body { height: 100%; margin: 0; }
#app { height: 100%; width: 100%;}
.title { position: fixed; top: 0.5em; left: 0; right: 0; text-align: center; font-size: 0.8em;}
.price { height: 100%; display: flex; align-items: center; justify-content: center; font-size: min(20vh, 20vw) }
.connection-status { position: fixed; bottom: 0.5em; left: 0.5em;font-size:0.8em;opacity:0.5;}
</style>
<script>
const Ticker = {
data() {
return {
ws: null,
timeout: 250, //250ms default, exponentially backs off
channel: "btcusd",
price: null,
isConnected: false
}
},
computed: {
connectionStatus(){
return this.isConnected ? 'Connected' : 'Connecting...';
},
formattedPrice(){
if(this.price) return this.price.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})
}
},
methods: {
initialize(){
//simultaneously connect to the websocket and send an initial REST request for latest price
this.connect()
this.query();
},
query(){
let url = `https://www.bitstamp.net/api/v2/ticker/${this.channel}/`
let proxiedUrl = `https://api.allorigins.win/get?url=${encodeURIComponent(url)}`
axios.get(proxiedUrl).then((response) =>{
if(response.data && response.data.contents){
let data = JSON.parse(response.data.contents);
if(this.price == null && data.last != null)
this.price = Number(data.last);
}
})
},
connect() {
let ws = new WebSocket('wss://ws.bitstamp.net/');
this.ws = ws; // copy it over for easier reference elsewhere
ws.onopen = this.onOpen;
ws.onmessage = this.onMessage;
ws.onclose = this.onClose;
ws.onerror = this.onError;
},
onOpen(){
this.isConnected = true;
let subscribeRequest = {
"event": "bts:subscribe",
"data": {
"channel": `live_trades_${this.channel}`
}
}
//subscribe to our desired data
this.ws.send(JSON.stringify(subscribeRequest))
},
onMessage(e){
//handle the messages
console.log(e);
if(e.type === "message" && e.data){
let message = JSON.parse(e.data);
if(message.event === "trade" && message.data != null && message.data.price != null){
this.price = message.data.price
}
}
},
onClose(e){
this.isConnected = false;
//update next timeout retry, capped at 10 seconds
let timeout = Math.min(10000,this.timeout+=this.timeout)
let timeoutSeconds = timeout / 1000;
console.log(`[Socket Closed] Attemping reconnect in ${timeoutSeconds} seconds...`, e.reason);
setTimeout(this.connect, timeout);
},
onError(err){
console.error('[Socket Error] Closing socket, encountered error: ', err.message);
this.ws.close();
}
},
mounted(){
this.initialize();
}
}
let tickerInstance = Vue.createApp(Ticker).mount('#app')
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment