Creating a Stock Market Simulator for Twitch Chat Using NodeJS and AWS

Nick Ramkissoon
Geek Culture
Published in
7 min readMar 7, 2021
Photo by M. B. M. on Unsplash

A recent obsession with Twitch has led to a flow of ideas related to creating games and experiences that involve Twitch chat. One of which is a stock market simulator where chatters share an account with an initial pool of cash and they enter buy and sell orders in chat. Gains, losses, current positions, and other account data would be streamed so chatters can know how their trades are performing.

For this project, I used NodeJS and AWS to build a Twitch chat bot to read stock orders, a backend service for processing orders, and a frontend UI that displays account data to a browser that can be streamed to Twitch. I’ll walk through each these components, share implementation details, and provide some walkthroughs for setting up a similar project of your own.

Prequisites

  1. A Twitch account is required so you can pass account credentials into your bot.
  2. An AWS account is required because we will be using AWS SNS and DynamoDB.
  3. In order to get real-time quote data for processing orders in the backend service, I used my TD Ameritrade account to make authorized requests to their real-time quote data APIs. If you do not have a brokerage account, you can create a developer account and get delayed data. You can also get quote data from various other means such as scraping Yahoo Finance.

The Twitch Chat Bot

The requirements for the chat bot are simple, it needs to:

  1. read Twitch chat in real time
  2. parse chat messages for stock market orders
  3. send orders to a backend server to be processed

Twitch chat bots are easy to create using the tmi.js package for Node. The tmi.js package allows the bot to call event handlers for various events such as when a new message is typed in chat.

The main bot driver code is fairly simple. A client is created using your Twitch account credentials, and we define an onMessageHandler function that processes each message if markets are open. Messages are parsed using regular expressions (e.g. “BUY AAPL 10”)to determine if they are orders. Orders are then queued up for publishing to an AWS SNS Topic.

To set up the SNS Topic, go to your AWS console and navigate to Simple Notification Service. Go to Topics then Create topic. Be sure to select Standard on the create topic screen. We need standard because our backend service will be subscribing to the SNS Topic over HTTP.

AWS SNS Topic Creation

Choose any name for your topic and you can leave the rest of the options as default. Create the topic and go to Topics on the left-side menu. You should be able to see your newly created topic and its ARN. Copy the Topic ARN into a .env file or environment variable so that the bot knows where to send the orders to.

With this, we should have a working bot that can read stock market orders and publish them to an SNS Topic to be consumed by other services.

Here’s the GitHub repository for the full chat bot implementation.

The Backend Service for Processing Orders and Updating the Account

The backend server is a simple Express server that processes orders and updates the account data in DynamoDB whenever a new order comes in from SNS or after a set interval to keep the data as up-to-date as possible.

There are two API endpoints for the server: the orders endpoint and account endpoints.

POST
/sns/orders
GET
/data/account

The orders endpoint accepts order messages from our SNS Topic. For this to work, we need to subscribe our API endpoint to the SNS Topic. Open up the AWS Console and go to your created SNS Topic then Create Subscription.

AWS SNS Create Subscription Form

Be sure to select the Topic ARN for you SNS Topic and HTTPS as the protocol (because we a subscribing a web server to the topic). The endpoint can be tricky if you are running the server on localhost. I used ngrok and added the URL created by ngrok as the endpoint. You can host the server on EC2, DigitalOcean Droplets, etc. and simply provide the host URL + /sns/orders.

In our Express router function for our order API logic, we need to confirm the subscription to SNS via the AWS SDK. This requires a simple response to SNS to confirm the subscription. Once AWS has received confirmation, the SNS Topic can start sending order messages to the server. Whenever a new SNS notification is sent to the endpoint, we extract and parse the message from SNS into order objects and pass the orders to a runUpdate function which contains the core account data update logic.

Before we dive into the runUpdate function, we need to set up DynamoDB tables to read and write account data. Setting up DynamoDB tables are relatively simple using the AWS console so we’ll just jump into what tables are required for our application.

Three tables are required, and in my implementation, I created another table to read/write API credentials for my TD Ameritrade account (this table is not important if you are using a different source for quote data). These are the required tables and a sample document from each:

Account Value Table: contains account data such as percent game, market value, etc. with a timestamp sort key (each DynamoDB document is a snapshot of the account value at a given point in time)

{
"day_gain_percent": 0,
"day_gain_total": 0,
"key": "account_value",
"mkt_value": 100000,
"previous_day_mkt_value": 100000,
"timestamp": 1611071780713,
"total_gain_percent": 0,
"total_gain_total": 0
}

Positions Table: contains documents representing each position indexed by ticker symbol, each document has the most up-to-date position value/gains/losses, price, quantity, etc.

{
"asset_type": "Equity",
"average_cost_per_unit": 142.65,
"day_gain_percent": 0.1187,
"day_gain_total": 0.17,
"mkt_value": 2866.6,
"POSITION": "AAPL",
"price": 143.33,
"quantity": 20,
"total_gain_percent": 0.48,
"total_gain_total": 13.6
}

Processed Orders Table: contains the processed orders for a given update on the server, each order also has data related to the Twitch user who entered the order.

{
"key": "processed_orders",
"processedOrders": [
{
"executed": true,
"orderValidationInfo": {
"isValid": true
},
"processedTimestamp": 1611671916539,
"userOrderData": {
"badges": {
"premium": "1"
},
"color": "#FF0000",
"display-name": "foo",
"id": "123",
"order": "!SELL NIO 110",
"tmi-sent-ts": "1611671926787",
"user-id": "1234",
"username": "foo"
}
}
],
"timestamp": 1611671916605
}

The runUpdate function leverages all these tables to update the account and positions after a set interval or whenever a new order comes in through AWS SNS.

The steps to update the data is fairly simple to follow:

  1. get the current positions
  2. get the current account value
  3. get tickers for both positions and any new orders then get the quote data using some data provider
  4. validate and execute the orders
  5. update the positions
  6. write the new position and account data to the DynamoDB tables

To go in depth on the order validation logic, reading and writing to DynamoDB, and the update logic, here’s is the GitHub repository for the full backend server.

The Frontend for Displaying Account Data and Positions to Twitch

The goal is to livestream the simulated account in near real-time to Twitch. A browser can be streamed so the frontend UI will be a simple web page. For this, I used React and the Material-UI component library to build out a dashboard with different panels that display different kinds of data.

Five panel components were implemented:

  1. a graph of account value throughout the day
  2. current account value and day/total gains
  3. a table with current positions and individual gains, quantities, etc.
  4. a panel with valid stock market order formats that Twitch users can enter
  5. a feed of order events that show what order each user entered and if the order executed

Some other notes on the UI panels: the chart was developed using react-chart-js-2, and the entire UI updates on a set interval.

The frontend receives new data from backend server by regularly fetching account data from the previously mentioned account data API on the backend. The new account data is passed into the appropriate component state/props to update the entire UI.

Here is the GitHub repository for the frontend.

Below is the final look of the UI (the account was very much in the red…).

UI for displaying data to Twitch

Putting It All Together

By running npm run start (or dev) in the bot, backend, and frontend Node projects and having our AWS resources available, the project should be running. All that’s left is to open the frontend UI on a web browser and stream to Twitch!

For the intermediate-level programmer or aspiring software engineer, a project of this scale teaches a lot in terms of design. It is a true full-stack project with clear requirements and end product. The inclusion of AWS services such as SNS and DynamoDB is an added bonus that exposes you to working with AWS and the AWS SDK in JavaScript.

Of course, new features can be added such as options trading (where the real stock market fun is) and events when a Twitch user subscribes or follows. For example, one cool idea is to add more simulated cash into the account every time a new user follows. The Twitch API includes webhooks for this exact purpose! Departing from trading stocks entirely, new ideas for interactive games with Twitch chat can be developed using the chat bot/backend/frontend architecture. The possibilities are endless here.

--

--

Nick Ramkissoon
Geek Culture

Software engineer that loves to educate and help people.