Ingesting Websocket Data for Live Stock Streams with Cloudera Flow Management Powered by Apache NiFi
Tags: apachenifi, websockets
Published: 2020-12-22 18:18:26

---
title: Ingesting Websocket Data for Live Stock Streams with Cloudera Flow Management Powered by Apache NiFi
published: true
date: 2020-12-22 18:17:00 UTC
tags: apachenifi, websockets
canonical_url: 
---

## Ingesting Websocket Data for Live Stock Streams with Cloudera Flow Management Powered by Apache NiFi

The stocks I follow have a lot of trades and changes throughout the day, I would like to capture all of this data and make it available to my colleagues.   I will push it to Kafka and make it available via a topic and I may also push it to Slack or Dischord or a webpage or dashboard or Cloudera Visual App dashboard.   We'll see what people request.

  

[![](https://1.bp.blogspot.com/-0-ve4eWmotk/X-IzzzhVwSI/AAAAAAAAcH8/FszDP-xk_kwqvCbI-AMy3W_c_Ab_H1UFACLcBGAsYHQ/w640-h604/nififlow1.png)](https://1.bp.blogspot.com/-0-ve4eWmotk/X-IzzzhVwSI/AAAAAAAAcH8/FszDP-xk_kwqvCbI-AMy3W_c_Ab_H1UFACLcBGAsYHQ/s1285/nififlow1.png)

We will read websockets from wss://ws.finnhub.io?token=YOURTOKEN.   You will need to [sign](https://finnhub.io/dashboard) up for a [finnhub](https://finnhub.io/).io account to get this data.   The API is well documented and very easy to use with Apache NiFi.

As updates happen we receive websocket calls and send them to Kafka for use in Flink SQL, Kafka Connect, Spark Streaming, Kafka Streams, Python, .Java Spring Boot Apps, NET Apps and NIFi.

#### Definition of Fields

s

Symbol.

p

Last price.

t

UNIX milliseconds timestamp.

v

Volume.

c

List of trade conditions. A comprehensive list of trade conditions code can be found [here](https://docs.google.com/spreadsheets/d/1PUxiSWPHSODbaTaoL2Vef6DgU-yFtlRGZf19oBb9Hp0/edit?usp=sharing)

### Incoming Websocket Text Message Processing

[![](https://1.bp.blogspot.com/-9yHBy930HaE/X-Iz6Ucw8rI/AAAAAAAAcIA/XyDMDS7OXeYNxtIy10w_6drsSUBKqhhBwCLcBGAsYHQ/w623-h837/nififlow2.png)](https://1.bp.blogspot.com/-9yHBy930HaE/X-Iz6Ucw8rI/AAAAAAAAcIA/XyDMDS7OXeYNxtIy10w_6drsSUBKqhhBwCLcBGAsYHQ/s1167/nififlow2.png)
  

We parse out the fields we want, then rename them for something readable.   Then we build a new JSON field that matches our trades schema then we push to Kafka.

First step we need to setup a controller pool to connect to finnhub's web socket API.

[![](https://1.bp.blogspot.com/-4DxL2t4jyZA/X-I1aVuO6EI/AAAAAAAAcI8/dZlGSf6_YHEEiwVbqDAsr1PtLTGrcowlwCLcBGAsYHQ/w640-h318/websocketcontroller.png)](https://1.bp.blogspot.com/-4DxL2t4jyZA/X-I1aVuO6EI/AAAAAAAAcI8/dZlGSf6_YHEEiwVbqDAsr1PtLTGrcowlwCLcBGAsYHQ/s650/websocketcontroller.png)

**We can see data in flight via NiFi Provenance.**

[![](https://1.bp.blogspot.com/-FTZxVYJfL5Y/X-I1WAkOkcI/AAAAAAAAcIY/3E-ArEUKVXwNyKMlHk3QlScRyQWINMisACLcBGAsYHQ/w640-h424/allthedatalive.png)](https://1.bp.blogspot.com/-FTZxVYJfL5Y/X-I1WAkOkcI/AAAAAAAAcIY/3E-ArEUKVXwNyKMlHk3QlScRyQWINMisACLcBGAsYHQ/s1116/allthedatalive.png)
  

  

  

**The detailed steps and settings for converting raw websocket text messages to final messages to send to Kafka.**  

  

  

[![](https://1.bp.blogspot.com/-vpcJIuBigAQ/X-I1WQt4XzI/AAAAAAAAcIc/7IqcHjBa3cAdMyeK39XjOYN_XdwV8tvLwCLcBGAsYHQ/w640-h204/newfields.png)](https://1.bp.blogspot.com/-vpcJIuBigAQ/X-I1WQt4XzI/AAAAAAAAcIc/7IqcHjBa3cAdMyeK39XjOYN_XdwV8tvLwCLcBGAsYHQ/s575/newfields.png)
  

[![](https://1.bp.blogspot.com/-zfzYQW6Isbk/X-I1W6SeySI/AAAAAAAAcIg/UuUgZTCArpgsSby0yXAyUY67UKyUVWDDACLcBGAsYHQ/w640-h146/newrecord.png)](https://1.bp.blogspot.com/-zfzYQW6Isbk/X-I1W6SeySI/AAAAAAAAcIg/UuUgZTCArpgsSby0yXAyUY67UKyUVWDDACLcBGAsYHQ/s704/newrecord.png)
  

[![](https://1.bp.blogspot.com/-o1xC2DN7MAE/X-I1Xnry50I/AAAAAAAAcIk/S8Asq14ii1sTCzq2Ethewgs5zSUDNIgKQCLcBGAsYHQ/w640-h470/publishtoKafka.png)](https://1.bp.blogspot.com/-o1xC2DN7MAE/X-I1Xnry50I/AAAAAAAAcIk/S8Asq14ii1sTCzq2Ethewgs5zSUDNIgKQCLcBGAsYHQ/s806/publishtoKafka.png)
  

  

  

[![](https://1.bp.blogspot.com/-yUW75QWdqNo/X-I1Yh3B0nI/AAAAAAAAcIs/fVIMNMSL0PATljKRRDHG6gvhw3xJD0rYwCLcBGAsYHQ/w640-h212/rebuildrecord.png)](https://1.bp.blogspot.com/-yUW75QWdqNo/X-I1Yh3B0nI/AAAAAAAAcIs/fVIMNMSL0PATljKRRDHG6gvhw3xJD0rYwCLcBGAsYHQ/s938/rebuildrecord.png)
  

[![](https://1.bp.blogspot.com/-1zdezOJP-YA/X-I1Y8YsVrI/AAAAAAAAcIw/o9Gfol6xpbIPDbYDi_pH9B86AwVGjqlkACLcBGAsYHQ/w640-h200/renameWeirdFields.png)](https://1.bp.blogspot.com/-1zdezOJP-YA/X-I1Y8YsVrI/AAAAAAAAcIw/o9Gfol6xpbIPDbYDi_pH9B86AwVGjqlkACLcBGAsYHQ/s462/renameWeirdFields.png)
  

[![](https://1.bp.blogspot.com/-EwlYfC8esGQ/X-I1Zj7UQ-I/AAAAAAAAcI0/732PfTZxZHAr0Y7tuNn2gnsBKTQ4ka2uQCLcBGAsYHQ/w640-h192/subscribetoCLDR.png)](https://1.bp.blogspot.com/-EwlYfC8esGQ/X-I1Zj7UQ-I/AAAAAAAAcI0/732PfTZxZHAr0Y7tuNn2gnsBKTQ4ka2uQCLcBGAsYHQ/s476/subscribetoCLDR.png)
  

[![](https://1.bp.blogspot.com/-DmC8Bsvg87I/X-I1aHvTuzI/AAAAAAAAcI4/g1huJpOr3Cs2VpuP9tuDaZfQrFbhL-EYQCLcBGAsYHQ/w640-h184/websocketconnection.png)](https://1.bp.blogspot.com/-DmC8Bsvg87I/X-I1aHvTuzI/AAAAAAAAcI4/g1huJpOr3Cs2VpuP9tuDaZfQrFbhL-EYQCLcBGAsYHQ/s584/websocketconnection.png)
  

  

  

**Raw Data From Websockets Text Message**

[![](https://1.bp.blogspot.com/-WgcpgVmZMs0/X-I1X_awRCI/AAAAAAAAcIo/s7aP38ojKdwM_IgWmDA5K2XtXHrJFFY_wCLcBGAsYHQ/w640-h70/rawdata.png)](https://1.bp.blogspot.com/-WgcpgVmZMs0/X-I1X_awRCI/AAAAAAAAcIo/s7aP38ojKdwM_IgWmDA5K2XtXHrJFFY_wCLcBGAsYHQ/s807/rawdata.png)

  

**Formatted JSON Data Before Converting and Sending to Kafka Topic (trades)**

[![](https://1.bp.blogspot.com/--u8Bw3_9gg8/X-I1WDmpsXI/AAAAAAAAcIU/I8xGuY74tEEkvHov8RtIZb-mi5psLIvawCLcBGAsYHQ/w640-h314/examplecleandata.png)](https://1.bp.blogspot.com/--u8Bw3_9gg8/X-I1WDmpsXI/AAAAAAAAcIU/I8xGuY74tEEkvHov8RtIZb-mi5psLIvawCLcBGAsYHQ/s567/examplecleandata.png)

  

  

**We can view the final clean data in Kafka via Cloudera Streams Messaging Manager (SMM)**

[![](https://1.bp.blogspot.com/-3o9kzWST0Sc/X-I1bGLAl0I/AAAAAAAAcJA/F2hZnw8g8iASxQWm5eYvClSSmBiOjl8MACLcBGAsYHQ/w640-h212/websocketstokafkaSMM.png)](https://1.bp.blogspot.com/-3o9kzWST0Sc/X-I1bGLAl0I/AAAAAAAAcJA/F2hZnw8g8iASxQWm5eYvClSSmBiOjl8MACLcBGAsYHQ/s2477/websocketstokafkaSMM.png)
  

[![](https://1.bp.blogspot.com/-MCObOqyrkgE/X-I1WECNpmI/AAAAAAAAcIQ/z3DIimQFHa0GyhLN--_5coyeRYTFhE8PACLcBGAsYHQ/w640-h300/cleanKafkaDataSMM.png)](https://1.bp.blogspot.com/-MCObOqyrkgE/X-I1WECNpmI/AAAAAAAAcIQ/z3DIimQFHa0GyhLN--_5coyeRYTFhE8PACLcBGAsYHQ/s636/cleanKafkaDataSMM.png)

**Schema**

[https://github.com/tspannhw/ApacheConAtHome2020/blob/main/schemas/trades.avsc](https://github.com/tspannhw/ApacheConAtHome2020/blob/main/schemas/trades.avsc)

**Happy Holidays from Tim and the Streaming Felines!**

[![](https://1.bp.blogspot.com/-DsWHOnZTbuc/X-I321qehjI/AAAAAAAAcJo/7rQfsqBhgdwQFDupMMeHjmPOyV43C8eVQCLcBGAsYHQ/w640-h640/IMG-0413.jpg)](https://1.bp.blogspot.com/-DsWHOnZTbuc/X-I321qehjI/AAAAAAAAcJo/7rQfsqBhgdwQFDupMMeHjmPOyV43C8eVQCLcBGAsYHQ/s2048/IMG-0413.jpg)
  

[![](https://1.bp.blogspot.com/-hn3k2RoHWsU/X-I320tk7pI/AAAAAAAAcJk/tAF7Vxp5xy4Qst_Cp2yIw34x8KYCY5rmQCLcBGAsYHQ/w640-h640/IMG-0424.jpg)](https://1.bp.blogspot.com/-hn3k2RoHWsU/X-I320tk7pI/AAAAAAAAcJk/tAF7Vxp5xy4Qst_Cp2yIw34x8KYCY5rmQCLcBGAsYHQ/s2048/IMG-0424.jpg)
  

[![](https://1.bp.blogspot.com/-hObyAn5op1A/X-I320ARvOI/AAAAAAAAcJg/DDgDe6P30y8k2Liw1d16CzIxfo7Qw2SYACLcBGAsYHQ/w640-h640/IMG-0430.jpg)](https://1.bp.blogspot.com/-hObyAn5op1A/X-I320ARvOI/AAAAAAAAcJg/DDgDe6P30y8k2Liw1d16CzIxfo7Qw2SYACLcBGAsYHQ/s2048/IMG-0430.jpg)
  

### **Reference**

- [https://community.cloudera.com/t5/Community-Articles/NiFi-WebSocket-support/tac-p/248174](https://community.cloudera.com/t5/Community-Articles/NiFi-WebSocket-support/tac-p/248174) 
- [https://finnhub.io/docs/api](https://finnhub.io/docs/api)
- [https://dzone.com/articles/real-time-stock-processing-with-apache-nifi-and-ap](https://dzone.com/articles/real-time-stock-processing-with-apache-nifi-and-ap)
- [https://github.com/tspannhw/SmartStocks](https://github.com/tspannhw/SmartStocks)

  

**Related Youtube Video**

  

<iframe allowfullscreen="" height="497" src="https://www.youtube.com/embed/f4cipioFCW8" width="598" youtube-src-id="f4cipioFCW8"></iframe>