Trade the News with Python

pexels-photo-518543-518543.jpg

Building a Real-Time Financial News Sentiment Analyzer with Python, Redis, and OpenAI

Introduction

In the fast-paced world of stock trading, having real-time access to financial news and the ability to analyze its sentiment can give traders a significant edge. In this blog post, we will walk you through the development of a system that read the live financial news, analyzes its sentiment, and publishes the results to a Redis channel. This setup can then be used to trigger automated trading decisions based on news sentiment.

Step 1: Setting Up the Environment

Before diving into the code, ensure you have the following components installed and configured:

  • Interactive Brokers API (IB API): For fetching live financial news.
  • Redis: For publishing and subscribing to processed news data.
  • OpenAI API: For sentiment analysis of the news articles.

Step 2: Fetching Financial News Using IB API

The IB API provides access to live market data, including news headlines and full articles. We start by creating a client that connects to the Interactive Brokers Trader Workstation (TWS) or IB Gateway.

from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract

class IBApi(EWrapper, EClient):
    def __init__(self):
        EClient.__init__(self, self)
        self.processed_news_ids = set()

    def tickNews(self, tickerId, timeStamp, providerCode, articleId, headline, extraData):
        print(f"News: {headline} (Provider: {providerCode}, ID: {articleId})")
        if articleId in self.processed_news_ids:
            print(f"Skipping duplicate news article ID: {articleId}")
            return
        self.processed_news_ids.add(articleId)
        self.reqNewsArticle(tickerId, providerCode, articleId, [])

    def newsArticle(self, reqId, articleType, articleText):
        print(f"Full Article (Type {articleType}): {articleText}")
        sentiment, symbol = self.analyze_sentiment(articleText)
        print(f"Sentiment: {sentiment}, Symbol: {symbol}")
        self.publish_article_with_sentiment(articleText, sentiment, symbol)

Step 3: Analyzing Sentiment with OpenAI API

The next step is to analyze the sentiment of the news articles using OpenAI’s GPT-3.5-turbo model. This will help us understand whether the news is positive, neutral, or negative, and how it might impact stock prices.

from openai import OpenAI
import json
from util import openai_pass

client = OpenAI(api_key=openai_pass)

class IBApi(EWrapper, EClient):
    # Other methods...

    def analyze_sentiment(self, text):
        response = client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=[
                {"role": "system", "content": "You are a financial news analyst."},
                {"role": "user", "content": (
                    f"Analyze the sentiment of the following news article and return a sentiment score from 1 to 5 "
                    f"(1 = Strong Sell, 2 = Sell, 3 = Neutral, 4 = Buy, 5 = Strong Buy) and identify the stock symbol affected:\n\n"
                    f"{text}\n\n"
                    "Return the result in the format: {\"sentiment\": <score>, \"symbol\": \"<stock_symbol>\"}"
                )}
            ],
            max_tokens=100
        )
        result = response.choices[0].message.content.strip()
        try:
            result = result.replace("'", '"')
            result_json = json.loads(result)
            sentiment = result_json.get('sentiment', 3)
            symbol = result_json.get('symbol', 'Unknown')
        except json.JSONDecodeError as e:
            print(f"JSON decode error: {e}")
            print(f"Response text: {result}")
            sentiment = 3
            symbol = 'Unknown'
        return sentiment, symbol

Step 4: Publishing Data to Redis

To make the analyzed data accessible to other systems or services, we publish the news article and its sentiment score to a Redis channel.

import redis

class IBApi(EWrapper, EClient):
    def __init__(self):
        EClient.__init__(self, self)
        self.redis_client = redis.StrictRedis(host='192.168.50.245', port=6379, db=1)
        self.processed_news_ids = set()

    # Other methods...

    def publish_article_with_sentiment(self, text, sentiment, symbol):
        news_data = {
            "article": text,
            "sentiment": sentiment,
            "symbol": symbol
        }
        self.redis_client.publish('news_channel', json.dumps(news_data))

Step 5: Subscribing to Redis Channel

Finally, create a subscriber that listens to the news_channel and processes the incoming data. This can be used to trigger automated trading decisions.

import redis
import json

def redis_subscribe():
    client = redis.StrictRedis(host='192.168.50.245', port=6379, db=1)
    pubsub = client.pubsub()
    pubsub.subscribe('news_channel')
    
    print("Subscribed to 'news_channel'. Waiting for messages...")
    
    try:
        for message in pubsub.listen():
            if message['type'] == 'message':
                news_data = json.loads(message['data'].decode('utf-8'))
                print(f"Received news update: {news_data}")
    except KeyboardInterrupt:
        print("Unsubscribing and exiting...")
        pubsub.unsubscribe()
        print("Unsubscribed.")

if __name__ == "__main__":
    redis_subscribe()

Conclusion

By combining the power of Interactive Brokers API, OpenAI, and Redis, we’ve created a real-time system that processes financial news, analyzes its sentiment, and publishes the results to a Redis channel. This setup can be extended to automate trading decisions, providing a robust tool for traders to stay ahead of market movements.

This tutorial demonstrates the seamless integration of various technologies to build a practical and valuable financial tool. We hope this inspires you to explore further enhancements and applications in your trading strategies.

Feel free to ask any questions or share your thoughts in the comments below! Happy trading!

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top