Tutorial
May 9, 2023

Building with Financial Data Sets and APIs

In this article, you'll learn how to incorporate financial data into your application. First, you'll learn more about how to plan for and use real-time financial data in your applications. Then, you'll use the financial API provided by IEX Cloud's Apperate platform to build a financial stock website using NestJS.

Cloud icon

Ivan Kahl

https://iexcloud.io/community/blog/building-with-financial-data-sets-and-apis
@iexcloud
https://iexcloud.io/community/blog/building-with-financial-data-sets-and-apis
@iexcloud

Financial data sets are collections of structured and unstructured data related to finance that include stock prices, exchange rates, and company earnings. The sheer volume of financial data that's collected and processed these days has led to companies specializing in collecting and processing financial data and then exposing them over an API. A financial API lets you query financial data so you can use it in your applications without gathering and processing it yourself.

Many business applications use financial data, and most of them require access to accurate real-time financial data to function effectively. For example, an algorithmic trading platform might need to perform complex calculations on financial data to decide whether to buy or sell a stock. Digital trading applications also use real-time financial data to display stock or currency exchange rate graphs. Even news sites sometimes incorporate live market data into their news articles to show how a stock mentioned in the article is currently performing. Financial APIs provide all these applications with the real-time financial data that they need.

In this article, you'll learn how to incorporate financial data into your application. First, you'll learn more about how to plan for and use real-time financial data in your applications. Then, you'll use the financial API provided by IEX Cloud's Apperate platform to build a financial stock website using NestJS.

Using Real-Time Financial Data

If you're using a financial API to provide financial data to your application, you must understand the importance of planning for real-time data management so you can use the financial data sets provided by APIs effectively in your application.

Due to the real-time nature of financial information, developers often use an event bus to push new data to an application in real time. An event bus is a software system that lets different systems communicate using an event-based architecture—in other words, systems communicate events with other system components as they occur.

This method of communication, called event-driven communication, is more efficient than polling, where systems have to repeatedly poll another system to find out if an event occurred. Event-driven architecture lets you build efficient applications that receive information about events as soon as they occur. It's the ideal architecture for real-time applications such as a financial app.

Event buses are necessary for any application that requires real-time financial data. For example, an algorithmic trading platform can perform real-time calculations on data by using an event bus to receive the data as soon as it's available. Likewise, digital trading applications that display live rates and charts or news sites that display live stock prices can use an event bus to push new data to them in real time.

Building a Financial Website

You'll now learn how to incorporate financial data into your application by developing a server-side rendered financial stocks website. For simplicity, the demo website won't follow best practice by using an event bus to retrieve real-time data as explained above. Instead, it will query the most recent financial data using a REST API whenever a page is loaded.

The website will have a list of stock symbols that the user can edit in a side menu. When the user clicks on a stock symbol, another page will load that shows the company's name, the stock's historical prices, and its price change over that time. You'll use Apperate for retrieving the financial information that your website will display.

Here's an overview of the website architecture:

Website Architecture

You can find the complete code for this website on GitHub.

Prerequisites

You'll develop the website in TypeScript using NestJS, a Node.js web framework for building server-side web applications.

To follow along with the demonstration, you must install the latest long-term support (LTS) version of Node.js, which, at the time of writing, is Node.js 18. Once you've installed Node.js, you must also install the NestJS CLI tool.

The starter template for the financial website you'll develop is hosted on GitHub, so install Git if you don't already have it. Finally, you'll need a code editor like Visual Studio Code to edit TypeScript files.

Since you'll be using Apperate, register an IEX Cloud account. All the data sets you'll use in this article are available with its free trial.

Clone the Project Template

Since this article will focus on integrating with Apperate's financial APIs, to retrieve financial data sets for your application, you'll clone a starter template that has all the styling and basic functionality implemented.

Open a new terminal window and navigate to the folder where you'll be storing your project's source code. Run the following command to clone the template project:

```bash

git clone https://github.com/ivankahl/iexcloud-apperate-template.git

```

Once Git finishes cloning the project, you'll need to install the dependencies using the following npm command:

```bash

npm install

```

Now that the dependencies are installed, you're ready to go. Open the project folder in your code editor. The snippet below opens it in Visual Studio Code:

```bash

code ./iexcloud-apperate-template

```

### Test the Template Website

You can test the template website by running the following command in the project directory:

```bash

npm run start:dev

```

This command will:

- use TailwindCSS to watch for changes to any of the view files and regenerate the final CSS file and

- run the NestJS application, which will watch for any changes to NestJS files.

Navigate to [http://localhost:3000](http://localhost:3000) in your web browser. You should see a dark page with a sidebar showing some stock symbols:

Test the application by adding another stock symbol. When you click on a stock symbol to open its details, notice how a blank page appears. This blank page is the details page you'll implement in the following sections.

Set Up IEX Cloud in Your Project

You'll use the `@apperate/iexjs` npm package to access the Apperate platform from the Node.js project. This package is an official IEX Cloud library that grants you access to all of Apperate's features from Node.js.

Install the library using the following command in your terminal:

```bash

npm i @apperate/iexjs

```

You'll also need to retrieve your Apperate API token. Log in to your [Apperate console](https://iexcloud.io/console), where you'll see an **API Tokens** section on the home page. It has a field that contains your `public` and `secret` API tokens:

Apperate console home page with the API tokens section highlighted

Copy the `secret` API token.

Back in your source code, create an `.env` file in the root of your project. Then, paste the following text inside the file, replacing `{IEX_TOKEN}` with the token you copied above.

```bash

IEX_TOKEN={IEX_TOKEN}

```

You can find more information on the `public` and `secret` tokens in the IEX Cloud documentation.

Create the IEX Cloud Service

Next, you'll create a NestJS service with methods to retrieve the financial data using Apperate's financial API. The rest of the website will then use this wrapper service to pull financial data from Apperate.

Create a new NestJS service for IEX Cloud by running the following command in your project's root folder.

```bash

nest g service IexCloud

```

You should notice a new `iex-cloud` folder in your `src` directory. Inside the folder is the file **iex-cloud.service.ts**, where you'll implement the IEX Cloud service.

Newly created files in the IEX Cloud folder

Open the **iex-cloud.service.ts** file and replace the code inside with the following:

```ts

import { Injectable } from '@nestjs/common';

import { Client } from '@apperate/iexjs';

/**

* IEX Cloud Service that can be used to interact with some of Apperate's

* CORE data sets.

*/

@Injectable()

export class IexCloudService {

 /**

  * The IEX Cloud Client to use to query data in Apperate.

  */

 private readonly iexClient;

 /**

  * Creates a new version of the IEX Cloud Client using the IEX_TOKEN environment

  * variable to retrieve the API Key for IEX Cloud.

  */

 constructor() {

   this.iexClient = new Client({

     version: 'v1',

     api_token: process.env.IEX_TOKEN,

   });

 }

 /**

  * Tries to retrieve the stock close prices for a specified stock symbol over the given date range.

  * @param stockSymbol The stock symbol to retrieve historical financial data for.

  * @param range The date range to retrieve financial data for.

  * @returns A list of stock close prices over the specified date range, if any are available.

  */

 async getStockHistoricalDataAsync(

   stockSymbol: string,

   range: Range,

 ): Promise<StockClose[]> {

   // Retrieve all the stock prices from the HISTORICAL_PRICES dataset over the specified range.

   const historicalData = await this.iexClient.apperate.queryData({

     key: stockSymbol,

     workspace: 'CORE',

     id: 'HISTORICAL_PRICES',

     range,

     // Data is returned in descending order by default, so flip it here so the graphs are rendered

     // correctly.

     sort: 'ASC',

   });

   return historicalData.map((x) => ({ date: x.priceDate, close: x.close }));

 }

 /**

  * Retrieves details about the specified stock symbol such as company name and last price change.

  * @param stockSymbol The stock symbol to retrieve details about.

  * @returns Details about the specified stock if it was found.

  */

 async getStockDetailsAsync(stockSymbol: string): Promise<StockDetails> {

   // Retrieve the company details

   const companyResults: CompanyData[] =

     await this.iexClient.apperate.queryData({

       key: stockSymbol,

       workspace: 'CORE',

       id: 'COMPANY',

       last: 1,

     });

   // If no company details were returned, throw an Error as it means the company either doesn't

   // exist or we don't have that company's details and financial data.

   if (companyResults.length === 0) {

     throw Error('Could not find company information for the stock symbol.');

   }

   // Retrieve the stock's last two trading days so that we can calculate the last close price change.

   const lastTwoStockPrices: HistoricalPriceData[] =

     await this.iexClient.apperate.queryData({

       key: stockSymbol,

       workspace: 'CORE',

       id: 'HISTORICAL_PRICES',

       last: 2,

     });

   let change: number | null = null;

   if (lastTwoStockPrices.length === 0) {

     // If we can't retrieve the last two close prices for the stock, throw an error.

     throw Error('Could not find the latest price for the specified stock.');

   } else if (lastTwoStockPrices.length === 2) {

     // If we have two stock price records returned, we can calculate the price change by subtracting

     // the latest stock's close price from the previous day's close price. Notice how we round the

     // change to four decimal places by multiplying the number by 10000, rounding it and then dividing

     // by 10000.

     change =

       Math.round(

         (lastTwoStockPrices[0].close - lastTwoStockPrices[1].close) * 10000,

       ) / 10000;

   }

   return {

     companyName: companyResults[0].companyName,

     symbol: stockSymbol,

     change,

   };

 }

}

/**

* TypeScript type used to represent the details about a particular stock symbol.

*/

export type StockDetails = {

 companyName: string;

 symbol: string;

 change: number | null;

};

/**

* TypeScript type used to represent a single stock close price and its date.

*/

export type StockClose = {

 date: string;

 close: number;

};

/**

* Range type that shows all the different ranges that can be passed to Apperate.

*/

export type Range =

 | '1D'

 | '5D'

 | '1M'

 | '3M'

 | '6M'

 | 'YTD'

 | '1Y'

 | '3Y'

 | '5Y'

 | '15Y';

/**

* An array of all the different ranges available. This is used to render the correct

* range buttons on the frontend.

*/

export const AllRanges: Range[] = [

 '1D',

 '5D',

 '1M',

 '3M',

 '6M',

 'YTD',

 '1Y',

 '3Y',

 '5Y',

 '15Y',

];

/**

* TypeScript type containing the most essential fields that are returned when querying

* the HISTORICAL_PRICES dataset. Other fields are also returned, but we don't use them

* so they aren't specified here.

*/

type HistoricalPriceData = {

 close: number;

 high: number;

 low: number;

 open: number;

 priceDate: string;

 symbol: string;

};

/**

* TypeScript type containing the most essential fields that are returned when querying

* company data from the COMPANY dataset in Apperate. Other fields are also returned, but

* we don't use them so they aren't specified here.

*/

type CompanyData = {

 companyName: string;

 symbol: string;

 website: string | null;

};

```

The code above declares an `IexCloudService` class and several TypeScript type declarations that will be helpful when dealing with IEX Cloud data sets. Let's discuss the source code piece by piece.

#### Creating the IEX Cloud Client

An `iexClient` private property is declared at the top of the class. It stores the IEX Cloud Client, which you'll use to interact with the financial data sets in Apperate.

The `constructor` initializes the `iexClient` with a version and API token. The constructor retrieves the API token from the `IEX_TOKEN` environment variable that you had set earlier in the `.env` file.

#### Retrieving Historical Stock Data

The `getStockHistoricalDataAsync` method returns the daily historical stock prices for a specified stock symbol in the range specified.

The code uses the `queryData` method on the IEX Cloud Client to query the `HISTORICAL_PRICES` data set. When using the `queryData` method, the `workspace` field specifies in which workspace to look for the data set, and the `id` field specifies the name of the data set in the specified workspace. You also need to specify which stock you'd like to retrieve data for using the `key` field and which date range to query using the `range` field. By default, Apperate returns data in descending order, so you set `sort` to ascending (`ASC`) order to render the graphs correctly.

Once the method has queried the data, it returns the data to be displayed on the website at a later stage.

#### Retrieving Stock Company Data

The `getStockDetailsAsync` method retrieves a stock's company information based on the stock symbol provided.

The function again uses the `queryData` method to query the [`COMPANY` data set](https://iexcloud.io/docs/core/COMPANY) provided by Apperate. If the code finds the company details in Apperate, the function calculates the price change before returning all the data to be displayed on the front page. Validation statements throughout the method will give an appropriate error if any of the queried data is invalid.

### Add the Detail Page to the Controller

Now that you've developed the `IexCloudService` class, you'll use it in the **app.controller.ts** file to retrieve the data from Apperate and render it on the web page with stock details.

Open the **app.controller.ts** file and paste the following code:

```ts

import {

 BadRequestException,

 Controller,

 Get,

 Param,

 Query,

 Render,

 Res,

} from '@nestjs/common';

import {

 AllRanges,

 IexCloudService,

 Range,

} from './iex-cloud/iex-cloud.service';

import { Response } from 'express';

@Controller()

export class AppController {

 /**

  * List of stocks to display in the sidebar of the web page.

  */

 stocks = ['AAPL', 'GOOG'];

 /**

  * Constructs a new instance of the AppController and passes in the IEX Cloud Service object.

  * @param iexCloudService The IEX Cloud Service to use to retrieve financial data.

  */

 constructor(private readonly iexCloudService: IexCloudService) {}

 /**

  * Renders the home page.

  * @returns Returns the list of stocks to display on the sidebar of the home page.

  */

 @Get()

 @Render('index')

 root() {

   return { stocks: this.stocks };

 }

 /**

  * Render the Add Stock form.

  * @returns Nothing.

  */

 @Get('add')

 @Render('add')

 add() {

   return;

 }

 /**

  * Saves the new stock symbol and redirects the user to the details page for the newly created stock.

  * @param stockSymbol The new stock symbol that should be added.

  * @param res The response object, used to redirect to the new stock details page.

  * @returns The page redirect.

  */

 @Get('add/save')

 addSave(@Query('symbol') stockSymbol: string, @Res() res: Response) {

   this.stocks.push(stockSymbol);

   return res.redirect(`/detail/${stockSymbol}`);

 }

 /**

  * Renders the stock details page which includes company information and historical data.

  * @param stockSymbol The stock symbol to render the details page for.

  * @param range The date range to retrieve historical data for.

  * @returns All the company and historical data that should be shown on the details page.

  */

 @Get('detail/:symbol')

 @Render('detail')

 async detail(

   @Param('symbol') stockSymbol: string,

   @Query('range') range?: Range,

 ) {

   // If no range is specified, set it to 1M

   range = range ?? '1M';

   // Load the stock and company details

   let stockDetails = null;

   try {

     stockDetails = await this.iexCloudService.getStockDetailsAsync(

       stockSymbol,

     );

   } catch (e) {

     throw new BadRequestException(e.message);

   }

   // Load the historical data

   let historicalData = null;

   try {

     historicalData = await this.iexCloudService.getStockHistoricalDataAsync(

       stockSymbol,

       range,

     );

   } catch (e) {

     throw new BadRequestException(e.message);

   }

   // Return all the information to be displayed on the page.

   return {

     stocks: this.stocks,

     selectedStock: {

       ...stockDetails,

       historicalData,

     },

     ranges: AllRanges,

     selectedRange: range,

   };

 }

}

```

The code in the website's starter template and the code snippet above differs in the following two ways:

#### Injecting IexCloudService Class

In the code snippet above, you can see how NestJS provides an instance of the `IexCloudService` class you developed in the previous section to the controller class using the `constructor` method, also known as [dependency injection](https://docs.nestjs.com/providers#dependency-injection):

```ts

/**

 * Constructs a new instance of the AppController and passes in the IEX Cloud Service object.

 * @param iexCloudService The IEX Cloud Service to use to retrieve financial data.

 */

constructor(private readonly iexCloudService: IexCloudService) {}

```

Because the `iexCloudService` parameter is prefixed with `private readonly` in the constructor parameter list, TypeScript automatically creates a private property from the parameter. You'll later use this property to retrieve the information for the stock detail page.

#### Detail Method

In the code snippet above, you'll also find the `detail` method toward the bottom of the snippet, which looks like this:

```ts

/**

* Renders the stock details page which includes company information and historical data.

* @param stockSymbol The stock symbol to render the details page for.

* @param range The date range to retrieve historical data for.

* @returns All the company and historical data that should be shown on the details page.

*/

@Get('detail/:symbol')

@Render('detail')

async detail(

 @Param('symbol') stockSymbol: string,

 @Query('range') range?: Range,

) {

 // If no range is specified, set it to 1M

 range = range ?? '1M';

 // Load the stock and company details

 let stockDetails = null;

 try {

   stockDetails = await this.iexCloudService.getStockDetailsAsync(

     stockSymbol,

   );

 } catch (e) {

   throw new BadRequestException(e.message);

 }

 // Load the historical data

 let historicalData = null;

 try {

   historicalData = await this.iexCloudService.getStockHistoricalDataAsync(

     stockSymbol,

     range,

   );

 } catch (e) {

   throw new BadRequestException(e.message);

 }

 // Return all the information to be displayed on the page.

 return {

   stocks: this.stocks,

   selectedStock: {

     ...stockDetails,

     historicalData,

   },

   ranges: AllRanges,

   selectedRange: range,

 };

}

```

Based on the TypeScript decorators on the method, this method executes whenever a `GET` request to `detail/:symbol` is made and returns the `views/detail.hbs` view.

The method first sets a default range if none was specified when the method was invoked. Afterward, the function retrieves the company information and the historical data using the `IexCloudService` you developed in the previous section. Once you've retrieved all the data, the method returns the company details, historical data, selected stock, and selected date range to NestJS to render on the webpage.

Create the Detail View

The last step is to create the **views/detail.hbs** view, which will display the stock details on the website. The view file uses [Handlebars](https://handlebarsjs.com/) to render the dynamic stock details on the webpage, hence the `.hbs` file extension.

Open the **views/detail.hbs** file and paste the following code into it:

```hbs

{{> sidebar }}

<section class="flex flex-col gap-4 bg-gray-700 py-8 px-10 drop-shadow-lg rounded-r-3xl my-8 w-full flex-1">

 <div class="flex-0 flex gap-4 items-center">

   <div class="flex-1 text-white flex gap-4 items-center">

     <h1 class="text-4xl font-bold">{{selectedStock.companyName}}</h1>

     <h2 class="text-2xl text-light opacity-50">{{selectedStock.symbol}}</h2>

   </div>

   <div class="text-white flex-0 py-1 px-2 rounded-lg font-bold {{#when selectedStock.change 'gteq' 0}}bg-green-700{{else}}bg-red-700{{/when}}">{{selectedStock.change}}</div>

 </div>

 {{> rangePicker stock=selectedStock.symbol ranges=ranges selectedRange=selectedRange}}

 <canvas id="historicalDataChart" class="flex-1"></canvas>

</section>

<script>

 const ctx = document.getElementById('historicalDataChart');

 new Chart(ctx, {

   type: 'line',

   data: {

     labels: {{{json selectedStock.historicalData}}}.map(x => x.date),

     datasets: [{

       label: 'Close Price',

       data: {{{json selectedStock.historicalData}}}.map(x => x.close),

       borderWidth: 1

     }]

   },

   options: {

     scales: {

       y: {

         beginAtZero: false

       }

     }

   }

 });

</script>

```

The template first renders the left sidebar, which contains the list of stock symbols the user can select. A stock details page then displays more details about the company, like its name and symbol, its stock price change, and a graph of the historical price for that stock. The date range for retrieving historical data is specified using a range picker component, and the resulting historical data is graphed using the Chart.js library.

Testing the Website

Now that you've integrated the website with Apperate to query and display financial data, test the website by running the following command in your terminal:

```bash

npm run start:dev

```

Navigate to [http://localhost:3000](http://localhost:3000) in your web browser to see the same page with stock symbols on the left as earlier. Select one of the symbols to open your newly developed stock details page, as shown below:

AAPL Stock Details Page

Notice the company details displayed at the top of the page and the chart underneath showing the historical prices for the stock. Explore the available date ranges and see how the historical price chart changes.

You can also add another stock symbol like `MSFT` (Microsoft) or `AMZN` (Amazon) and view stock price details for those particular stocks.

AMZN Stock Details Page

You can find the final code for this website on GitHub.

Conclusion

Real-time financial data is critical for financial applications like algorithmic trading platforms and digital trading apps.

In this article, you learned about financial data sets and how to integrate them into your applications using financial APIs like IEX Cloud's Apperate platform. You first learned why event bus architecture is a reliable method for pushing real-time updates to an application. You then saw a practical demonstration of retrieving company details and historical prices for stocks from Apperate in a NestJS application.