Alternative Data and NLP in Quant Strategies › Sentiment Analysis for Financial Text

Michael BrenndoerferJanuary 4, 20264 min read
Quantitative FinanceAll chapters
Part 13 of 15Machine Learning and Alternative Data
Chapter 71Alternative Data and NLP in Quant Strategies › Sentiment Analysis for Financial Text
Reading section 7 of 18 · Sentiment Analysis for Financial Text · 4 minSection 7 of 18 · 4 min

Book contents

Section 7 of 18 · 4 min read

Alternative Data and NLP in Quant Strategies › Sentiment Analysis for Financial TextOne section · Sections in this chapter7 / 18 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Sentiment analysis (determining whether text expresses positive, negative, or neutral views) is the most common NLP application in quantitative finance. The intuition is straightforward: positive news should correlate with positive price movements, negative news with declines. Implementation, however, requires attention to domain-specific language and the unique characteristics of financial communication.

Dictionary-Based Approaches

The simplest sentiment analysis methods use predefined word lists: positive words add to sentiment, negative words subtract. The Loughran-McDonald financial sentiment dictionary, specifically developed for financial text, has become a standard resource.

Generic sentiment dictionaries perform poorly on financial text because many words have domain-specific meanings. In everyday English, liability is negative. In finance, it is a neutral accounting term. Volatile might be negative in most contexts, but in finance it describes a factual characteristic of returns. The Loughran-McDonald dictionary addresses these issues by classifying words based on their financial context.

Converting word counts into a standardized sentiment metric requires capturing net sentiment intensity while controlling for document length. This normalization matters because we need to compare sentiment across documents of varying lengths. Without it, a 1000-word document with 10 positive words appears more positive than a 100-word document with 5 positive words, even though the shorter document has five times the sentiment density. By dividing by total words, we obtain a measure of sentiment intensity that is comparable across documents regardless of their length.

The sentiment score is computed as the difference between positive and negative word counts, normalized by document length. The score ranges from approximately -1 (all words negative) to +1 (all words positive), with 0 indicating neutral or balanced sentiment.

Sentiment=Npositive−NnegativeNtotal\text{Sentiment} = \frac{N_{\text{positive}} - N_{\text{negative}}}{N_{\text{total}}}

where:

  • NpositiveN_{\text{positive}}: count of words in the document that match the positive sentiment dictionary
  • NnegativeN_{\text{negative}}: count of words in the document that match the negative sentiment dictionary
  • NtotalN_{\text{total}}: total word count in the document (all words, not just sentiment words)
  • The score ranges from approximately -1 (all words negative) to +1 (all words positive), with 0 indicating neutral or balanced sentiment

This provides a standardized measure between -1 (maximally negative) and +1 (maximally positive). The numerator captures the net sentiment (positive minus negative words), while the denominator normalizes by document length. Without normalization, longer documents would mechanically have higher absolute scores even if their sentiment intensity was the same. The theoretical bounds of -1 and +1 are achieved only in extreme cases where every word matches the sentiment dictionaries. In practice, most documents contain many neutral words, so sentiment scores typically fall in a much narrower range around zero.

In[11]:
Code
# Simplified Loughran-McDonald inspired word lists
# (The full dictionary contains thousands of words)
lm_positive = {
    "achieve",
    "accomplished",
    "advantage",
    "better",
    "boost",
    "breakthrough",
    "enhance",
    "exceed",
    "excellent",
    "favorable",
    "gain",
    "good",
    "great",
    "growth",
    "improve",
    "increase",
    "opportunity",
    "outperform",
    "positive",
    "profit",
    "progress",
    "strong",
    "success",
    "surpass",
    "upturn",
}

lm_negative = {
    "adverse",
    "against",
    "bad",
    "below",
    "concern",
    "decline",
    "deficit",
    "deteriorate",
    "difficult",
    "disappoint",
    "downturn",
    "drop",
    "fail",
    "falling",
    "fear",
    "hurt",
    "impair",
    "inability",
    "lack",
    "less",
    "lose",
    "loss",
    "miss",
    "negative",
    "problem",
    "risk",
    "threat",
    "uncertain",
    "unfavorable",
    "weak",
    "worsen",
    "worse",
}


def lm_sentiment(text):
    """Calculate sentiment using Loughran-McDonald approach."""
    words = text.lower().split()
    pos_count = sum(1 for w in words if w in lm_positive)
    neg_count = sum(1 for w in words if w in lm_negative)
    total_words = len(words)

    if total_words == 0:
        return 0.0, 0, 0

    # Normalize by document length to get score between -1 and +1
    sentiment = (pos_count - neg_count) / total_words
    return sentiment, pos_count, neg_count


# Test on sample financial texts
test_texts = [
    "Strong revenue growth exceeded expectations, driven by favorable market conditions",
    "The company reported disappointing results with declining margins and increased risk",
    "Revenue was flat compared to the prior quarter with stable operating performance",
]
Out[12]:
Console
Dictionary-Based Sentiment Analysis:
======================================================================

Text 1: "Strong revenue growth exceeded expectations, driven by favor..."
  Positive words: 3, Negative words: 0
  Sentiment score: +0.3000

Text 2: "The company reported disappointing results with declining ma..."
  Positive words: 0, Negative words: 1
  Sentiment score: -0.0909

Text 3: "Revenue was flat compared to the prior quarter with stable o..."
  Positive words: 0, Negative words: 0
  Sentiment score: +0.0000

Dictionary-based approaches require no training data, run quickly, and expose how each word affects the score. The results show how word counts translate directly to sentiment scores. Text 1 with 3 positive words and 0 negative words receives a strongly positive score, while Text 2 with multiple negative terms receives a negative score. Text 3, which uses balanced or neutral language, scores near zero.

However, these approaches have limitations. They cannot handle negation: not good incorrectly receives a positive score because it contains good. They also cannot understand context-dependent meanings and fail to detect sarcasm. The phrase surprising lack of losses might be positive, but a dictionary approach would count lack and losses as negative.