For the sake of brevity we will cover only the data integration portion of the build in this tutorial, but our demo application code is also included in the GitHub repository for your use.
The Intrinio API is capable of utilizing WebSockets to stream real-time stock information. This provides a great advantage over traditional polling-based methods of retrieving quote data because it is sent only as needed — in other words if the price isn’t changing on a stock we don’t have to keep polling over and over again to check the price.
This project was created using Xcode 9, Beta 4.
Let’s get started!
Create a new iOS project: in the example provided, we use the Page Based App template provided in Xcode. Close the project once it has been created, and make your way over to your terminal. Change directory to the top level of your project, and run the following command to initialize CocoaPods for your project:
This creates a file namedPodfile in your top level project directory. Now you need to add Starscream to your Podfile and install it. In your Podfile under the line use_frameworks! enter the line:
pod 'Starscream', '~> 2.1'
Save the file and then run the following:
You should see some green text that tells you this was successful. Now re-open your project using the .xcworkspace project file (this is important because it allows the pod we just installed to be used in your project).
Now we are ready to get into the data integration component of the project. Add a new Swift file to your project called IntrinioConnector.swift, this will contain all of the Swift code for our API connector. Add another new Swift file called Utilities.swift, this will contain the necessary data structures for parsing our JSON.
In the IntrinioConnector.swift file enter the following:
What we have done here is imported the necessary modules, namely the Starscream module that will enable us to use WebSockets. We have also defined a class named IntrinioConnector and made it a WebSocket delegate, allowing it to handle any events our WebSocket generates. Finally we have created a property socket to contain the handle for our WebSocket.
Next let’s add the following code to IntrinioConnector.swift
Here we have defined the rest of the class properties we will need. You will need to fill in username and password with your respective API username and password from Intrinio. We also define a timer object heartbeater to contain the timer that controls our heartbeat to the WebSocket. Intrinio requires a heartbeat ping be sent every 20 seconds (we have it set to 15 in ours) in order to keep the connection alive. We have also defined a couple of event handlers that represent pointers to callback functions; eventReadyis called when the socket is established and ready to receive requests from our application and eventHandler is used to handle all subsequent data related events.
Next, we define the function start which begins the connection process. First we initialize a basic NSMutableURLRequest to the Intrinio authentication URL through our private function getRequestForURL. This function embeds our username and password in the header for basic HTTP authentication and returns a request object.
Now we can create a HTTP request task and write a closure to handle the response. In the response handler, we assign the returned API token to our class property, and then use the token to begin initiating the actual WebSocket connection. We initialize a WebSocket handle and assign it to the variablesocket, tell it to use the current class as it’s event delegate, and then attempt to connect. Finally we must start this whole order of operations by calling task.resume(), and then wait for a callback to notify us of any state change to our socket.
To handle these callbacks, we must add the following code:
First, let’s clear some overhead code out of the way. When we establish our socket, we will need to send periodic “heartbeats” to the remote server over our socket. The function above heartbeat simply writes this request.
If our socket successfully connects, then we will receive a callback to websocketDidConnect. In this function, we define the connection state as being ready by assigning true to connectionReady, and clear out any previously stored subscription data (it all gets invalidated whenever a connection drops). Then we initialize the timer to handle the heartbeat requests at an interval of 15 seconds. Finally we dispatch a new thread to handle the callback to our ready event we initialized earlier. At this point our app would know our Intrinio API feed is open for business.
If the socket did not connect successfully, or if at any point our connection breaks the function websocketDidDisconnect() is called. This function will invalidate our heartbeat process, change the state variable connectionReady to false and print any debugging information to your console. I’m sure at some point if I continued to develop this demo I would probably also need a callback handler for the disconnect event the same as we have an eventReady that is called upon a successful connection.
Now that the connection is setup, let’s get down to adding some subscriptions, which will allow us to listen for updates on various ticker symbols.
The function subscribeToTicker allows us to request updates for a specific ticker symbol (i.e. AAPL, AMZN, etc). I’ve added some controls to both of these functions above to check whether a ticker is subscribed already, to prevent hammering the API server with duplicate requests. If it’s already subscribed, then we’ll skip adding it again, and if it’s not already subscribed… well then we need to subscribe! unSubscribeToTicker is used to stop listening for updates on a given ticker symbol.
Once we’ve subscribed to some ticker symbols, we should start seeing quotes trickling in (assuming markets are open and the symbol is active in trading). To handle this we need to create a couple of new methods:
These two methods, as you’ll notice, are very similar — essentially depending on the type of data being received (text vs binary) one or the other will be called. websocketDidReceiveMessage is the only one that this demo will use, but you should be aware that both exist.
When a message is received from our Intrinio data feed, the websocketDidReceiveMessage callback is called. Here we take advantage of some of the new shiny Swift 4 features and use the new Decodable interface. Basically, if we define structs that match the expected structure of the JSON we’re attempting to parse, then Swift will pretty much do all the work of serializing it into usable objects for you. First we initialize a JSONDecoder object, then we call decode on it using the text we just received. We should now have a generic event object that can be passed through in a new thread to the eventHandler callback our application initialized earlier. It’s up to your application how to handle various events, you can see a few examples in the source code provided with this article. Here is an excerpt of our demo application’s callback for this:
As you can see, using a switch statement we examine the event property of the withEvent structured passed to the function. The only event our application expects to receive is “quote” and thus any other event is simply dumped into the console. When we receive a “quote” event we find the symbol and update the price, then kick off a series of events that update our application’s interface.
Finally, let’s define the contents of our Utilities.swift file:
Here we have defined all of the basic JSON elements we need to parse responses from Intrinio’s API. IEXEvent implements the Decodable interface which allows it to be used directly with the JSONDecoder to parse data. In this example IEXEvent.event will equal “quote” and IEXEvent.payload will contain data as outlined in the IEXPayload structure, which represents quote data.
That’s it! You should have all the knowledge needed to create a working WebSocket connection with Intrinio’s real-time data feed. Don’t forget to check out our github repository containing all of the code from this article as well as further examples of integrating the data with your application.
Link to GitHub repository: IntrinioDemo