Daily Stock Market Updates In Slack Using Python and AWS Lambda

Posted on Mon 20 February 2023 in Tech • 3 min read

The Problem - Stock Market Updates In Slack

Our investment strategy involves owning broad market funds instead of specific stocks and sectors. We also don't sell frequently, and instead choose to keep buying regardless of the market conditions. That said, I still like to keep tabs on how the stock market is doing so I know the general sense of it's movement.

Barchart and Google Finance have some charts and information, but I was looking for a way to get that sent to me daily. Most things I found either send too frequently or try to send specific stock tickers. I specifically just wanted the 3 major indicies (Dow, S&P 500, and Nasdaq) with the daily change in percent format and a marker of positive or negative.

Solution - Python Function in AWS Lambda to Slack

My solution was to utilize a python library called yfinance to get the stock price for today and yesterday, then do the math to get the percent change. Then, send a string to a Slack webhook that can post a message so I get notified.

Slack

I have my own Slack organization that I use for various notifications about Google Drive, Github, Twitter, and more. I wanted a notification to be sent when the Lambda function was triggered, so I created a Webhook connection in my Slack channel using this setup and saved the Webhook URL.

AWS Lambda

To set up the AWS Lambda function, I created a new function using the latest python version as the runtime. I kept the defaults for most of this.

One option for the code is to install yfinance into a container and create a layer in Lambda, but I chose to install it within the function since this is only running once per day and the installation is pretty quick. If this was running more frequently, I'd probably set up the layer.

Here's the code I used in the function:

import json
import boto3
import os
import subprocess
import sys
from urllib.request import Request, urlopen

# Install yfinance using pip
subprocess.check_call([sys.executable, "-m", "pip", "install", "--target", "/tmp", 'yfinance'])
sys.path.append('/tmp')

import yfinance

def lambda_handler(event, context):
    # Get the 3 tickers
    dji=yfinance.Ticker('^DJI')
    sp=yfinance.Ticker('^GSPC')
    nasdaq=yfinance.Ticker('^IXIC')

    # Calculate the percent and set up the slack emojis based on positive or negative
    dji_percent = 1 - (dji.fast_info['previousClose'] / dji.fast_info['lastPrice'])
    dji_arrow = ":white_check_mark:"
    if dji_percent < 0:
        dji_arrow = ":x:"
    sp_percent = 1 - (sp.fast_info['previousClose'] / sp.fast_info['lastPrice'])
    sp_arrow = ":white_check_mark:"
    if sp_percent < 0:
        sp_arrow = ":x:"
    nasdaq_percent = 1 - (nasdaq.fast_info['previousClose'] / nasdaq.fast_info['lastPrice'])
    nasdaq_arrow = ":white_check_mark:"
    if nasdaq_percent < 0:
        nasdaq_arrow = ":x:"


    # Form the slack text
    slack_url = 'https://hooks.slack.com/services/your/webhook/url'
    slack_text = "Stock market update:\n"

    slack_text += "S&P 500:   "+sp_arrow+"   {:.2%}\n".format(sp_percent)
    slack_text += "Dow 30:    "+dji_arrow+"   {:.2%}\n".format(dji_percent)
    slack_text += "Nasdaq:    "+nasdaq_arrow+"   {:.2%}\n".format(nasdaq_percent)
    slack_message = {
        'text': slack_text,
        'username': "AWS Lambda",
        'icon_emoji': ':moneybag:'
    }
    data = json.dumps(slack_message).encode('ascii')

    # Send the Slack request
    req = Request(slack_url, data)
    response = urlopen(req)
    print(response)

    return {
        'statusCode': 200,
        'body': json.dumps(f'Done!')
    }

EventBridge Trigger

Once the function is saved, I needed a daily trigger to invoke the Lambda function. This functionality is now in EventBridge using cron. Since I was running this at 6pm EST every weekday, I used a cron expression of:

cron(0 23 ? * MON-FRI *)

This expression means that it will run at minute 0 of hour 23 (UTC) of every month on days that are between Monday and Friday in every year. The question mark in the "day of month" field is because we are specifying the weekdays, so you can't have a star in the day of month or it won't accept the expression.

Resulting Message

The resulting message in Slack shows me just the information I want to know. It's also short enough that the notification on my watch shows all of the data, so I can see it at a glance. This also leaves the door open for modifying the message or adding more data.