Introduction
We now have our data being pushed to us.
Lets make use of SignalR to push this information to the client and display it on a real time graph.
This article is the second part in the series.
Part 1 can be found here: Creating a Real-time Cryptocurrency Websocket API [Part 1].
Prerequisites
- Visual Studio 2015 or 2017 with Framework 4.6.1
- A
Coinigy
API key and secret (please see Part 1 on how to get this key and secret)
Table of Contents
- Using the code
- Step 01 - Create a Web Application
- Step 02 - Install Nuget packages
- Step 03 - Create a Startup Class
- Step 04 - Create a hub
- Step 05 - Subscribe to events
- Step 06 - Subscribe to Trade Channel
- Step 07 - Connect and push trade messages to client
- Step 08 - Create an HTML page
- Step 09 - Create a JavaScript file
- Step 10 - Subscribe and update charts
- Final words
Using the Code
Step 01 - Create a Web Application
Open Visual Studio and go to File > New > Project and select ASP.NET Web Application.
Ensure your framework targets .NET Framework 4.6.1.
Give your project a name (e.g. Coinigy.Web
) and click "OK".
Select the "Empty"-template and ensure nothing else is checked or selected.
Click "OK".
Step 02 - Install Nuget Packages
In the package manager console, install the following packages using these commands:
"Install-Package PureSocketCluster
"
"Install-Package Microsoft.AspNet.SignalR
"
Step 03 - Create a Startup Class
We need to create an OWIN startup class to initialize SignalR.
Right-click on your project and select "Add > OWIN Startup class" and give it the name "Startup
". Click OK.
Replace the Configuration
function with the following code:
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
Step 04 - Create a hub
Lets create a Hubs-folder and add a hub to send information to our client in real time.
Right-click on the project and select "Add > New Folder" and give it the name "Hubs".
Lets add the hub by right-clicking on the "Hubs"-folder and select "Add > New Item > SignalR Hub Class (v2)" and name it "MarketDataHub
".
We still need to add the reference to our API from Part 1 so that we can use it within our application. Compile the project from Part 1 to create the DLL. Add a reference to it by right-clicking on the "References" node under the web project and selecting "Add Reference > Browse > Select the DLL from Part 1 > OK". You should now be able to reference the project within your web application
Lets jump back to the MarketDataHub
.
Add the following field to the hub:
private readonly Websocket socket = null;
And initialize it within the hub's constructor:
public MarketDataHub()
{
socket = new Websocket(new API.Models.ApiCredentials
{
ApiKey = "[YOUR-API-KEY]",
ApiSecret = "[YOUR-API-SECRET]"
});
}
Lets build our project to see that everything is working. Press Ctrl+Shift+B.
Note: If you receive the following error: "Multiple assemblies with equivalent identity have been imported...", right-click on the System.Xml.ReaderWriter
under "References" in the web project and remove it. Rebuild to ensure everything is working.
Step 05 - Subscribe to events
Now that our websocket is initialized, lets subscribe to the OnClientReady
and OnTradeMessage
events.
Add the following code in the hub's constructor after initializing the socket:
public MarketDataHub()
{
this.socket.OnClientReady += Socket_OnClientReady;
this.socket.OnTradeMessage += Socket_OnTradeMessage;
}
And create the functions to handle these events appropriately:
private void Socket_OnClientReady()
{
}
private void Socket_OnTradeMessage(string exchange, string primaryCurrency, string secondaryCurrency, API.Models.TradeItem trade)
{
}
The purpose of these functions, as described in Part 1, is to be notified when the client is ready to receive commands (ready to subscribe to channels) and to be notified when a new trade message arrives.
Step 06 - Subscribe to Trade Channel
To subscribe to a trade channel, we can add the following code to our Socket_OnClientReady
function:
this.socket.SubscribeToTradeChannel("BMEX", "XBT", "USD");
We will now start receiving information from this trade channel within the Socket_OnTradeMessage
function.
Step 07 - Connect and push trade messages to client
We only want to send an update to the user once a second. We will need to add a lock
to our function to allow only one thread at a time to push messages. We also need to add a field to inidicate whether we should wait before sending another update. Lets add those two fields to our MarketDataHub
class:
private readonly object objLock = new object();
private bool doWait = false;
And update our Socket_OnTradeMessage
function:
lock (this.objLock)
{
if (this.doWait)
{
Thread.Sleep(1000);
this.doWait = false;
}
Clients.All.broadcastTradePrice(exchange, primaryCurrency, trade.Price);
this.doWait = true;
}
When a user now subscribes to the broadcastTradePrice
function on the client side, they will start to receive updates.
Finally, we need to connect to our socket after wiring up all the events within the hub's constructor. Add the following line at the end of the constructor:
this.socket.Connect();
Now our hub is complete. Lets move onto the client side.
Step 08 - Create an HTML page
Right-click on your project and select "Add > HTML Page" and call it "index.html". Replace its contents with the following code:
<!DOCTYPE html>
<html>
<head>
<title>Websocket Example</title>
<!--
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/epoch/0.8.4/css/epoch.min.css" />
</head>
<body>
<h1> Gauge: </h1>
<div id="gaugeChart" class="epoch gauge-small"></div>
<h1> Area chart: </h1>
<div id="areaChart" class="epoch" style="width: 100%; height: 300px;border:solid 1px #C0C0C0;"></div>
<h1> Line chart: </h1>
<div id="lineChart" class="epoch" style="width: 100%; height: 300px;border:solid 1px #C0C0C0;"></div>
<!--
<script src="Scripts/jquery-1.6.4.min.js"></script>
<script src="Scripts/jquery.signalR-2.2.2.min.js"></script>
<script src="signalr/hubs"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/d3/3.4.8/d3.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/epoch/0.8.4/js/epoch.min.js"></script>
<script src="Scripts/scripts.js"></script>
</body>
</html>
This page will show a line, area and gauge chart.
Step 09 - Create a JavaScript file
Lets add some JavaScript to subscribe to the events coming from the server.
Right-click on the "Scripts"-folder and select "Add > JavaScript File" and call it "scripts.js".
We can start by initializing our charts using the following code within our scripts file:
$(function () {
var areaChart = $('#areaChart').epoch({
type: 'time.area',
data: [{ values: [] }],
axes: ['left', 'bottom', 'right']
});
var lineChart = $('#lineChart').epoch({
type: 'time.line',
data: [{ values: [] }],
axes: ['left', 'bottom', 'right']
});
var gaugeChart = $('#gaugeChart').epoch({
type: 'time.gauge',
value: previousPrice
});
});
Now we can subscribe to the SignalR hub we created. Add the following 3 fields to the script after initializing the charts:
var marketDataHub = $.connection.marketDataHub;
var timestamp = ((new Date()).getTime() / 1000) | 0;
var previousPrice = 0;
The timestamp
field will be used to track time on the x-axis of our charts. The y-axis will show the trade market prices.
The previousPrice
field is used by our gauge chart. We use this value to determine the average price increase/decrease of the market data. (The gauge chart shows its value in percentages.)
Step 10 - Subscribe and update charts
Everything is setup and we can start listening to messages being sent from the server. Lets add the following function to our script file:
marketDataHub.client.broadcastTradePrice = function (exchange, primaryCurrency, price) {
areaChart.push([{ time: timestamp, y: price }]);
lineChart.push([{ time: timestamp, y: price }]);
previousPrice = previousPrice == 0 ? price : previousPrice;
var performance = price / previousPrice;
gaugeChart.update(performance);
timestamp++;
console.log(price);
previousPrice = price;
};
The parameters for the line and area charts are timestamp
and y
. Time is displayed on the x-axis and prices are displayed on the y-axis.
Next we run a calculation to determine what the percentage increase/decrease is to update our gauge chart. After all charts have been updated, we increase our timestamp
and wait for the next message to be sent from the server. Finally we can start the connection to the hub. Add the following code after the above function:
$.connection.hub.start();
Press F5 to debug your web application. You should see your charts being updated in real time:
Final Words
We are now able to use our API within our web application to show the user real time trade market data in a visual, graphical format.